Merge branch 'master' of http://git.newlifex.com/NewLife/X
大石头 编写于 2018-09-25 18:53:17
X
using System;
using System.Collections.Generic;
using NewLife.Data;

namespace NewLife.Net.Handlers
{
    /// <summary>长度字段作为头部</summary>
    public class LengthFieldCodec : MessageCodec<Packet>
    {
        #region 属性
        /// <summary>长度所在位置</summary>
        public Int32 Offset { get; set; }

        /// <summary>长度占据字节数,1/2/4个字节,0表示压缩编码整数,默认2</summary>
        public Int32 Size { get; set; } = 2;

        /// <summary>过期时间,超过该时间后按废弃数据处理,默认500ms</summary>
        public Int32 Expire { get; set; } = 500;
        #endregion

        /// <summary>编码</summary>
        /// <param name="context"></param>
        /// <param name="msg"></param>
        /// <returns></returns>
        protected override Object Encode(IHandlerContext context, Packet msg)
        {
            var len = Math.Abs(Size);
            var buf = msg.Data;
            var idx = 0;
            var dlen = msg.Total;

            // 修正压缩编码
            if (len == 0) len = IOHelper.GetEncodedInt(dlen).Length;

            // 尝试退格,直接利用缓冲区
            if (msg.Offset >= len)
            {
                idx = msg.Offset - len;
                msg.Set(msg.Data, msg.Offset - len, msg.Count + len);
            }
            // 新建数据包,形成链式结构
            else
            {
                buf = new Byte[len];
                msg = new Packet(buf) { Next = msg };
            }

            switch (Size)
            {
                case 0:
                    var buf2 = IOHelper.GetEncodedInt(dlen);
                    buf.Write(idx, buf2);
                    break;
                case 1:
                    buf[idx] = (Byte)dlen;
                    break;
                case 2:
                    buf.Write((UInt16)dlen, idx);
                    break;
                case 4:
                    buf.Write((UInt32)dlen, idx);
                    break;
                case -2:
                    buf.Write((UInt16)dlen, idx, false);
                    break;
                case -4:
                    buf.Write((UInt32)dlen, idx, false);
                    break;
                default:
                    throw new NotSupportedException();
            }

            return msg;
        }

        /// <summary>解码</summary>
        /// <param name="context"></param>
        /// <param name="pk"></param>
        /// <returns></returns>
        protected override IList<Packet> Decode(IHandlerContext context, Packet pk)
        {
            var ss = context.Session;
            var mcp = ss["CodecItem"] as CodecItem;
            if (mcp == null) ss["CodecItem"] = mcp = new CodecItem();

            var pks = Parse(pk, mcp, ms => GetLength(ms, Offset, Size), Expire);

            // 跳过头部长度
            var len = Offset + Math.Abs(Size);
            foreach (var item in pks)
            {
                item.Set(item.Data, item.Offset + len, item.Count - len);
                //item.SetSub(len, item.Count - len);
            }

            return pks;
        }
    }
}