/*
* (C) Copyright 2015-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* ohun@live.cn (夜色)
*/
package com.mpush.netty.codec;
import com.mpush.api.protocol.Packet;
import com.mpush.api.protocol.JsonPacket;
import com.mpush.api.protocol.UDPPacket;
import com.mpush.tools.Jsons;
import com.mpush.tools.config.CC;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.DatagramPacket;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.TooLongFrameException;
import java.util.HashMap;
import java.util.List;
import static com.mpush.api.protocol.Packet.decodePacket;
/**
* Created by ohun on 2015/12/19.
* length(4)+cmd(1)+cc(2)+flags(1)+sessionId(4)+lrc(1)+body(n)
*
* @author ohun@live.cn
*/
public final class PacketDecoder extends ByteToMessageDecoder {
private static final int maxPacketSize = CC.mp.core.max_packet_size;
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
decodeHeartbeat(in, out);
decodeFrames(in, out);
}
private void decodeHeartbeat(ByteBuf in, List<Object> out) {
while (in.isReadable()) {
if (in.readByte() == Packet.HB_PACKET_BYTE) {
out.add(Packet.HB_PACKET);
} else {
in.readerIndex(in.readerIndex() - 1);
break;
}
}
}
private void decodeFrames(ByteBuf in, List<Object> out) {
if (in.readableBytes() >= Packet.HEADER_LEN) {
//1.记录当前读取位置位置.如果读取到非完整的frame,要恢复到该位置,便于下次读取
in.markReaderIndex();
Packet packet = decodeFrame(in);
if (packet != null) {
out.add(packet);
} else {
//2.读取到不完整的frame,恢复到最近一次正常读取的位置,便于下次读取
in.resetReaderIndex();
}
}
}
private Packet decodeFrame(ByteBuf in) {
int readableBytes = in.readableBytes();
int bodyLength = in.readInt();
if (readableBytes < (bodyLength + Packet.HEADER_LEN)) {
return null;
}
if (bodyLength > maxPacketSize) {
throw new TooLongFrameException("packet body length over limit:" + bodyLength);
}
return decodePacket(new Packet(in.readByte()), in, bodyLength);
}
public static Packet decodeFrame(DatagramPacket frame) {
ByteBuf in = frame.content();
int readableBytes = in.readableBytes();
int bodyLength = in.readInt();
if (readableBytes < (bodyLength + Packet.HEADER_LEN)) {
return null;
}
return decodePacket(new UDPPacket(in.readByte()
, frame.sender()), in, bodyLength);
}
public static Packet decodeFrame(String frame) throws Exception {
if (frame == null) return null;
return Jsons.fromJson(frame, JsonPacket.class);
}
}