package com.pekall.smartplug.codec; import com.pekall.smartplug.message.GetStatusRequest; import com.pekall.smartplug.message.GetStatusResponse; import com.pekall.smartplug.message.Heartbeat; import com.pekall.smartplug.message.HelloRequest; import com.pekall.smartplug.message.HelloResponse; import com.pekall.smartplug.message.MessageType; import com.pekall.smartplug.message.ReportStatusRequest; import com.pekall.smartplug.message.ReportStatusResponse; import com.pekall.smartplug.message.SetStatusRequest; import com.pekall.smartplug.message.SetStatusResponse; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.frame.FrameDecoder; import java.io.UnsupportedEncodingException; public class SmartPlugDecoder extends FrameDecoder { private static final int HEADER_SIZE = 4; // msg_type: short, msg_length: short private static final int STRING_MAX_BYTES = 31; private static final int STRING_MAX_BYTES_PLUS_ONE = STRING_MAX_BYTES + 1; @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { // Make sure if the message header was received. if (buffer.readableBytes() < HEADER_SIZE) { // The message header was not received yet - return null. // This method will be invoked again when more packets are // received and appended to the buffer. return null; } // The message header is in the buffer. // Mark the current buffer position before reading the type field // because the whole frame might not be in the buffer yet. // We will reset the buffer position to the marked position if // there's not enough bytes in the buffer. buffer.markReaderIndex(); // Read the type field; short typeValue = buffer.readShort(); // Read the length field. short length = buffer.readShort(); // Make sure if there's enough bytes in the buffer. if (buffer.readableBytes() < length) { // The whole bytes were not received yet - return null. // This method will be invoked again when more packets are // received and appended to the buffer. // Reset to the marked position to read the type field again // next time. buffer.resetReaderIndex(); return null; } MessageType type = MessageType.fromValue(typeValue); switch (type) { case MSG_HELLO_REQ: return decodeHelloRequest(buffer); case MSG_HELLO_RES: return decodeHelloResponse(buffer); case MSG_REPORT_STATUS_REQ: return decodeReportStatusRequest(buffer); case MSG_REPORT_STATUS_RES: return decodeReportStatusResponse(buffer); case MSG_HEARTBEAT: return decodeHeartbeat(buffer); case MSG_GET_STATUS_REQ: return decodeGetStatusRequest(buffer); case MSG_GET_STATUS_RES: return decodeGetStatusResponse(buffer); case MSG_SET_STATUS_REQ: return decodeSetStatusRequest(buffer); case MSG_SET_STATUS_RES: return decodeSetStatusResponse(buffer); default: throw new IllegalArgumentException("Unknown MessageType: " + type); } } private Object decodeHeartbeat(ChannelBuffer buffer) { int messageId = buffer.readInt(); short status = buffer.readShort(); return new Heartbeat(messageId, status); } private Object decodeSetStatusResponse(ChannelBuffer buffer) { int messageId = buffer.readInt(); short resultCode = buffer.readShort(); return new SetStatusResponse(messageId, resultCode); } private Object decodeSetStatusRequest(ChannelBuffer buffer) { int messageId = buffer.readInt(); short status = buffer.readShort(); return new SetStatusRequest(messageId, status); } private Object decodeGetStatusResponse(ChannelBuffer buffer) { int messageId = buffer.readInt(); short status = buffer.readShort(); return new GetStatusResponse(messageId, status); } private Object decodeGetStatusRequest(ChannelBuffer buffer) { int messageId = buffer.readInt(); return new GetStatusRequest(messageId); } private Object decodeReportStatusResponse(ChannelBuffer buffer) { int messageId = buffer.readInt(); return new ReportStatusResponse(messageId); } private Object decodeReportStatusRequest(ChannelBuffer buffer) { int messageId = buffer.readInt(); short status = buffer.readShort(); return new ReportStatusRequest(messageId, status); } private Object decodeHelloRequest(ChannelBuffer buffer) throws UnsupportedEncodingException { int messageId = buffer.readInt(); byte[] bytes = new byte[STRING_MAX_BYTES_PLUS_ONE]; int deviceIdLen = buffer.bytesBefore((byte)0); buffer.readBytes(bytes); String deviceId = new String(bytes, 0, deviceIdLen, "utf-8"); int deviceModeLen = buffer.bytesBefore((byte)0); buffer.readBytes(bytes); String deviceMode = new String(bytes, 0, deviceModeLen, "utf-8"); return new HelloRequest(messageId, deviceId, deviceMode); } private Object decodeHelloResponse(ChannelBuffer buffer) throws UnsupportedEncodingException { int messageId = buffer.readInt(); short resultCode = buffer.readShort(); int serverNameLen = buffer.bytesBefore((byte)0); byte[] bytes = new byte[STRING_MAX_BYTES_PLUS_ONE]; buffer.readBytes(bytes); String serverName = new String(bytes, 0, serverNameLen, "utf-8"); return new HelloResponse(messageId, resultCode, serverName); } }