public SprotoObject(object val) { string typename = SprotoObject.TypeOf(val); this.type = typename; this.val = val; }
public RpcPackage PackRequest(string proto, SprotoObject request = null, Int64 session = 0, SprotoObject ud = null) { //Console.WriteLine("PackRequest {0} {1} {2}",proto,request,session); SprotoProtocol protocol = this.C2S.GetProtocol(proto); UInt16 tag = protocol.tag; SprotoObject header = this.NewPackageHeader(this.C2S, tag, session, ud); this.writer.Seek(0, SprotoStream.SEEK_BEGIN); // clear stream SprotoStream writer = this.C2S.Encode(header, this.writer); if (request != null) { string expect = protocol.request; if (request.type != expect) { SprotoHelper.Error("[SprotoRpc.Request] expect '{0}' got '{1}'", expect, request.type); } writer = this.C2S.Encode(request, writer); } RpcPackage package = new RpcPackage(); package.data = this.C2S.Pack(writer.Buffer, 0, writer.Position, out package.size); if (session != 0) { SprotoHelper.Assert(!this.sessions.ContainsKey(session), String.Format("repeat session: {0}", session)); RpcMessage message = new RpcMessage(); message.session = session; message.proto = proto; message.request = request; message.tag = tag; this.sessions[session] = message; } return(package); }
private Dictionary <T, SprotoObject> DecodeSprotoObjectDict <T> (SprotoMgr sprotomgr, SprotoType type, SprotoField field, SprotoStream reader) { Dictionary <T, SprotoObject> dict = new Dictionary <T, SprotoObject>(); UInt32 size = this.ReadUInt32(reader); while (size > 0) { UInt32 elem_size = this.ReadUInt32(reader); UInt32 need_size = elem_size + SprotoCodec.SIZEOF_LENGTH; size = size - need_size; if (size < 0) { SprotoHelper.Error("[SprotoCodec.DecodeSprotoObjectDict] fail"); } SprotoObject elemobj = this.DecodeSprotoObject(sprotomgr, type, reader); SprotoObject keyobj = elemobj.Get(field.key); T key = (T)keyobj.val; dict[key] = elemobj; } if (size != 0) { SprotoHelper.Error("[SprotoCodec.DecodeSprotoObjectDict] fail"); } return(dict); }
public SprotoObject NewSprotoObject(string typename, object val = null) { if (null == this.GetType(typename)) { SprotoHelper.Error("[SprotoMgr.NewSprotoObject] unsupport type '{0}'", typename); } SprotoObject obj = new SprotoObject(); obj.type = typename; obj.val = val; return(obj); }
public SprotoObject Decode(SprotoMgr sprotomgr, string typename, SprotoStream reader) { if (SprotoHelper.IsBuildInType(typename)) { SprotoHelper.Error("[SprotoCodec.Decode] expect a 'non-buildin-type' got '{0}'", typename); } SprotoType type = sprotomgr.GetType(typename); if (null == type) { SprotoHelper.Error("[SprotoCodec.Decode] occur a unknow-type '{0}'", typename); } SprotoObject obj = this.DecodeSprotoObject(sprotomgr, type, reader); return(obj); }
private UInt32 EncodeSprotoObjectList(SprotoMgr sprotomgr, List <SprotoObject> list, SprotoStream writer) { UInt32 size = 0; for (int i = 0; i < list.Count; i++) { SprotoObject elemobj = list[i]; SprotoType elemtype = sprotomgr.GetType(elemobj.type); int elemsize_pos = writer.Position; writer.Seek(SprotoCodec.SIZEOF_LENGTH, SprotoStream.SEEK_CUR); UInt32 elemsize = this.EncodeSprotoObject(sprotomgr, elemtype, elemobj, writer); this.FillSize(writer, elemsize_pos, elemsize); size += (SprotoCodec.SIZEOF_LENGTH + elemsize); } return(size); }
public void Set(string fieldname, object value) { if (value.GetType() == typeof(SprotoObject)) { SprotoObject obj = value as SprotoObject; if (null == obj.type) { SprotoHelper.Error("[SprotoObject] uninitialize"); } this.fields.Add(fieldname, obj); } else { SprotoObject obj = new SprotoObject(value); this.fields.Add(fieldname, obj); } }
public SprotoStream Encode(SprotoMgr sprotomgr, SprotoObject obj, SprotoStream writer = null) { if (null == writer) { writer = new SprotoStream(); } string typename = obj.type; if (SprotoHelper.IsBuildInType(typename)) { SprotoHelper.Error("[SprotoCodec.Encode] expect a 'non-buildin-type sprotoobj' got '{0}'", typename); } SprotoType type = sprotomgr.GetType(typename); if (null == type) { SprotoHelper.Error("[SprotoCodec.Encode] occur a unknow-type '{0}'", typename); } this.EncodeSprotoObject(sprotomgr, type, obj, writer); return(writer); }
private UInt32 EncodeSprotoObjectDict <T> (SprotoMgr sprotomgr, Dictionary <T, SprotoObject> dict, SprotoField field, SprotoStream writer) { UInt32 size = 0; List <T> keys = new List <T>(dict.Keys); keys.Sort(); // keep encode stable foreach (var key in keys) { SprotoObject elemobj = dict[key]; if (elemobj.Get(field.key) == null) { SprotoHelper.Error("[SprotoCodec.EncodeSprotoObjectDict] exist null mainindex '{0}' in field '{1}'", field.key, field.name); } SprotoType elemtype = sprotomgr.GetType(elemobj.type); int elemsize_pos = writer.Position; writer.Seek(SprotoCodec.SIZEOF_LENGTH, SprotoStream.SEEK_CUR); UInt32 elemsize = this.EncodeSprotoObject(sprotomgr, elemtype, elemobj, writer); this.FillSize(writer, elemsize_pos, elemsize); size += (SprotoCodec.SIZEOF_LENGTH + elemsize); } return(size); }
private SprotoObject NewPackageHeader(SprotoMgr sprotomgr, UInt16 tag, Int64 session, SprotoObject ud = null) { SprotoObject header = sprotomgr.NewSprotoObject(this.package); if (tag != 0) // tag == 0 mean : response header { header["type"] = tag; } else { SprotoHelper.Assert(session != 0, "response expect session"); } if (session != 0) { header["session"] = session; } if (ud != null) { header["ud"] = ud; } return(header); }
public RpcPackage PackResponse(string proto, SprotoObject response = null, Int64 session = 0, SprotoObject ud = null) { //Console.WriteLine("PackResponse {0} {1} {2}",proto,response,session); SprotoProtocol protocol = this.S2C.GetProtocol(proto); SprotoObject header = this.NewPackageHeader(this.S2C, 0, session, ud); this.writer.Seek(0, SprotoStream.SEEK_BEGIN); // clear stream SprotoStream writer = this.S2C.Encode(header, this.writer); if (response != null) { string expect = protocol.response; if (response.type != expect) { SprotoHelper.Error("[SprotoRpc.Response] expect '{0}' got '{1}'", expect, response.type); } writer = this.S2C.Encode(response, writer); } RpcPackage package = new RpcPackage(); package.data = this.S2C.Pack(writer.Buffer, 0, writer.Position, out package.size); return(package); }
private List <SprotoObject> DecodeSprotoObjectList(SprotoMgr sprotomgr, SprotoType type, SprotoStream reader) { List <SprotoObject> list = new List <SprotoObject>(); UInt32 size = this.ReadUInt32(reader); while (size > 0) { UInt32 elem_size = this.ReadUInt32(reader); UInt32 need_size = elem_size + SprotoCodec.SIZEOF_LENGTH; size = size - need_size; if (size < 0) { SprotoHelper.Error("[SprotoCodec.DecodeSprotoObjectList] fail"); } SprotoObject elemobj = this.DecodeSprotoObject(sprotomgr, type, reader); list.Add(elemobj); } if (size != 0) { SprotoHelper.Error("[SprotoCodec.DecodeSprotoObjectList] fail"); } return(list); }
public byte[] PackEncode(SprotoObject obj, out int size, SprotoStream writer = null) { SprotoStream stream = this.Encode(obj, writer); return(this.Pack(stream.Buffer, 0, stream.Position, out size)); }
public SprotoStream Encode(SprotoObject obj, SprotoStream writer = null) { return(this.Codec.Encode(this, obj, writer)); }
private SprotoObject DecodeSprotoObject(SprotoMgr sprotomgr, SprotoType type, SprotoStream reader) { SprotoObject obj = sprotomgr.NewSprotoObject(type.name); // decode header part UInt16 fieldnum = this.ReadUInt16(reader); List <UInt16> data_tags = new List <UInt16>(); UInt16 curtag = 0; for (UInt16 i = 0; i < fieldnum; i++) { UInt16 tag = this.ReadUInt16(reader); if (tag == 0) { data_tags.Add(curtag); curtag++; } else if (0 == (tag & 1)) // even { UInt16 val = (UInt16)((tag / 2) - 1); SprotoField field = type.GetField(curtag); if (field != null) // for protocol version compatibility { if (field.type == "integer") { if (0 == field.digit) { Int64 number = (Int64)(val); obj.Set(field.name, number); } else { double number = (double)val / MathPow(10, field.digit); obj.Set(field.name, number); } } else if (field.type == "boolean") { if (!(val == 0 || val == 1)) { SprotoHelper.Error("[SprotoCodec.DecodeSprotoObject] type={0},field={1},boolean type expect value '0/1' got '{2}'", type.name, curtag, val); } bool ok = (val == 0) ? false : true; obj.Set(field.name, ok); } else { SprotoHelper.Error("[SprotoCodec.DecodeSprotoObject] type={0},field={1},expect type 'integer/boolean' got '{2}'", type.name, curtag, field.type); } } curtag++; } else // odd { curtag += (UInt16)((tag + 1) / 2); } } // decode data part foreach (UInt16 tag in data_tags) { SprotoField field = type.GetField(tag); if (field != null) { object fieldobj = null; if (SprotoHelper.IsBuildInType(field.type)) { fieldobj = this.DecodeBuildInType(field, reader); } else { SprotoType fieldtype = sprotomgr.GetType(field.type); if (field.is_array) { if (field.key != null) { string keytype = fieldtype.GetField(field.key).type; if (keytype == "integer") { fieldobj = this.DecodeSprotoObjectDict <Int64>(sprotomgr, fieldtype, field, reader); } else if (keytype == "string") { fieldobj = this.DecodeSprotoObjectDict <string>(sprotomgr, fieldtype, field, reader); } else if (keytype == "boolean") { fieldobj = this.DecodeSprotoObjectDict <bool>(sprotomgr, fieldtype, field, reader); } else { SprotoHelper.Error("[SprotoCodec.DecodeSprotoObject] keytype expect 'integer/boolean/string' got '{0}'", keytype); } } else { fieldobj = this.DecodeSprotoObjectList(sprotomgr, fieldtype, reader); } } else { this.ReadUInt32(reader); fieldobj = this.DecodeSprotoObject(sprotomgr, fieldtype, reader); } } obj.Set(field.name, fieldobj); } else { // for protocol version compatibility UInt32 fieldsize = this.ReadUInt32(reader); this.IgnoreByte(reader, fieldsize); } } return(obj); }
// not support recursive SprotoObject public override string ToString() { string val; if (null == this.val) { val = null; } else { string typename = SprotoObject.TypeOf(this.val); if (typename == "integer" || typename == "boolean" || typename == "string" || typename == "binary" || typename == "double") { val = this.val.ToString(); } else if (typename == "integer_list") { val = SprotoHelper.DumpList <Int64>(this.val as List <Int64>); } else if (typename == "boolean_list") { val = SprotoHelper.DumpList <bool>(this.val as List <bool>); } else if (typename == "string_list") { val = SprotoHelper.DumpList <string>(this.val as List <string>); } else if (typename == "binary_list") { val = SprotoHelper.DumpList <byte[]>(this.val as List <byte[]>); } else if (typename == "double_list") { val = SprotoHelper.DumpList <double>(this.val as List <double>); } else if (typename == "object_list") { val = SprotoHelper.DumpList <SprotoObject>(this.val as List <SprotoObject>); } else if (typename == "integer_object_dict") { val = SprotoHelper.DumpDict <Int64, SprotoObject>(this.val as Dictionary <Int64, SprotoObject>); } else if (typename == "string_object_dict") { val = SprotoHelper.DumpDict <string, SprotoObject>(this.val as Dictionary <string, SprotoObject>); } else if (typename == "boolean_object_dict") { val = SprotoHelper.DumpDict <bool, SprotoObject>(this.val as Dictionary <bool, SprotoObject>); } else { val = "unknow"; } } string fields = SprotoHelper.DumpDict <string, SprotoObject>(this.fields); return("{" + String.Format("type={0},val={1},fields={2}", this.type, val, fields) + "}"); }
private UInt32 EncodeBuildInType(SprotoField field, SprotoObject fieldobj, SprotoStream writer) { UInt32 size = 0; switch (field.type) { case "integer": if (field.is_array) { if (field.digit == 0) { List <Int64> list = fieldobj.val as List <Int64>; size = this.EncodeIntegerList(list, writer); } else { List <double> double_list = fieldobj.val as List <double>; List <Int64> list = new List <Int64>(); double_list.ForEach(v => list.Add((Int64)(Math.Round(v * MathPow(10, field.digit))))); size = this.EncodeIntegerList(list, writer); } } else { Int64 val; if (field.digit == 0) { val = (Int64)fieldobj.val; } else { val = (Int64)(Math.Round((double)fieldobj.val * MathPow(10, field.digit))); } size = this.EncodeInteger(val, writer); } break; case "boolean": if (field.is_array) { List <bool> list = fieldobj.val as List <bool>; size = this.EncodeBooleanList(list, writer); } else { SprotoHelper.Error("[SprotoCodec.EncodeBuildInType] 'boolean' should encode in header part"); //bool val = (bool)fieldobj.val; //return this.EncodeBoolean(val,writer); } break; case "string": if (field.is_array) { List <string> list = fieldobj.val as List <string>; size = this.EncodeStringList(list, writer); } else { string val = fieldobj.val as string; size = this.EncodeString(val, writer); } break; case "binary": if (field.is_array) { List <byte[]> list = fieldobj.val as List <byte[]>; size = this.EncodeBinaryList(list, writer); } else { byte[] val = fieldobj.val as byte[]; size = this.EncodeBinary(val, writer); } break; default: SprotoHelper.Error("[SprotoCodec.EncodeBuildInType] invalid buildin-type '{0}'", field.type); break; } return(size); }
private UInt32 EncodeSprotoObject(SprotoMgr sprotomgr, SprotoType type, SprotoObject obj, SprotoStream writer) { // encode header part List <UInt16> tags = new List <UInt16>(type.tagfields.Keys); tags.Sort(); UInt16 fieldnum = 0; Int16 lasttag = -1; int fieldnum_pos = writer.Position; writer.Seek(SprotoCodec.SIZEOF_FIELD, SprotoStream.SEEK_CUR); List <UInt16> data_tags = new List <UInt16>(); for (int i = 0; i < tags.Count; i++) { UInt16 tag = tags[i]; SprotoField field = type.GetField(tag); SprotoObject fieldobj = obj.Get(field.name); if (fieldobj != null) { UInt16 skiptag = (UInt16)(tag - lasttag); //Console.WriteLine("skiptag: tag={0},lasttag={1},skiptag={2}",tag,lasttag,skiptag); lasttag = (Int16)tag; if (skiptag > 1) { skiptag = (UInt16)((skiptag - 1) * 2 - 1); this.WriteTag(writer, skiptag); fieldnum++; } fieldnum++; bool encode_in_header = false; if (!field.is_array) { if (field.type == "integer") { Int64 integer; if (field.digit == 0) { integer = (Int64)fieldobj.val; } else { integer = (Int64)(Math.Round((double)fieldobj.val * MathPow(10, field.digit))); } if (this.IsSmallInteger(integer)) { encode_in_header = true; UInt16 number = (UInt16)((integer + 1) * 2); this.WriteTag(writer, number); } } else if (field.type == "boolean") { encode_in_header = true; bool ok = (bool)fieldobj.val; UInt16 integer = (UInt16)(ok ? 1 : 0); UInt16 number = (UInt16)((integer + 1) * 2); this.WriteTag(writer, number); } } if (!encode_in_header) { this.WriteTag(writer, 0); data_tags.Add(tag); } else { } } } this.FillFieldNum(writer, fieldnum_pos, fieldnum); UInt32 size = SprotoCodec.SIZEOF_FIELD + fieldnum * SprotoCodec.SIZEOF_FIELD; // encode data part foreach (UInt16 tag in data_tags) { SprotoField field = type.GetField(tag); SprotoType fieldtype = sprotomgr.GetType(field.type); SprotoObject fieldobj = obj.Get(field.name); int fieldsize_pos = writer.Position; UInt32 fieldsize = 0; writer.Seek(SprotoCodec.SIZEOF_LENGTH, SprotoStream.SEEK_CUR); if (SprotoHelper.IsBuildInType(field.type)) { fieldsize = this.EncodeBuildInType(field, fieldobj, writer); } else { if (field.is_array) { if (field.key != null) { string keytype = fieldtype.GetField(field.key).type; if (keytype == "integer") { Dictionary <Int64, SprotoObject> dict = fieldobj.val as Dictionary <Int64, SprotoObject>; fieldsize = this.EncodeSprotoObjectDict <Int64>(sprotomgr, dict, field, writer); } else if (keytype == "string") { Dictionary <string, SprotoObject> dict = fieldobj.val as Dictionary <string, SprotoObject>; fieldsize = this.EncodeSprotoObjectDict <string>(sprotomgr, dict, field, writer); } else if (keytype == "boolean") { Dictionary <bool, SprotoObject> dict = fieldobj.val as Dictionary <bool, SprotoObject>; fieldsize = this.EncodeSprotoObjectDict <bool>(sprotomgr, dict, field, writer); } else { SprotoHelper.Error("[SprotoCodec.EncodeSprotoObject] keytype expect 'integer/boolean/string' got '{0}'", keytype); } } else { List <SprotoObject> list = fieldobj.val as List <SprotoObject>; fieldsize = this.EncodeSprotoObjectList(sprotomgr, list, writer); } } else { fieldsize = this.EncodeSprotoObject(sprotomgr, fieldtype, fieldobj, writer); } } this.FillSize(writer, fieldsize_pos, fieldsize); size += (fieldsize + SprotoCodec.SIZEOF_LENGTH); } return(size); }
// Parser from binary(*.spb) private static void _ParseFromBinary(SprotoMgr sprotomgr, byte[] bytes, int length) { SprotoMgr meta = SprotoParser.Parse(meta_proto); SprotoStream reader = new SprotoStream(); reader.Write(bytes, 0, length); reader.Seek(0, SprotoStream.SEEK_BEGIN); SprotoObject group = meta.Decode("group", reader); List <SprotoObject> types = null; List <SprotoObject> protocols = null; if (group.Get("type") != null) { types = group.Get("type"); foreach (SprotoObject meta_type in types) { SprotoType type = new SprotoType(); type.name = meta_type["name"]; if (meta_type.Has("fields")) { List <SprotoObject> fields = meta_type["fields"]; foreach (SprotoObject meta_field in fields) { SprotoField field = new SprotoField(); field.name = meta_field["name"]; field.tag = (UInt16)meta_field["tag"]; field.is_array = false; if (meta_field.Has("array")) { field.is_array = (bool)meta_field["array"]; } Int64 type_id; if (meta_field.Has("buildin")) { type_id = meta_field["buildin"]; field.type = SprotoParser.BuildInTypeId2Name[type_id]; if (type_id == 0 && meta_field.Has("type")) { // fixed float field.digit = (UInt16)meta_field["type"]; } else if (type_id == 2 && meta_field.Has("type")) { // binary field.type = "binary"; } } else { type_id = meta_field["type"]; SprotoObject t = types[(int)type_id]; field.type = t["name"]; // map if (meta_field.Has("key")) { SprotoHelper.Assert(field.is_array); UInt16 map_index = (UInt16)meta_field["key"]; List <SprotoObject> t_fields = t["fields"]; string name = null; foreach (SprotoObject f in t_fields) { if (f["tag"] == map_index) { name = f["name"]; break; } } SprotoHelper.Assert(name != null, String.Format("map index {0} cann't find in type '{1}'", map_index, field.type)); field.key = name; } } type.AddField(field); } } sprotomgr.AddType(type); } } if (group.Get("protocol") != null) { protocols = group.Get("protocol"); foreach (SprotoObject meta_protocol in protocols) { SprotoProtocol protocol = new SprotoProtocol(); protocol.name = meta_protocol["name"]; protocol.tag = (UInt16)meta_protocol["tag"]; if (meta_protocol["request"] != null) { Int64 request = meta_protocol["request"]; protocol.request = types[(int)request]["name"]; } if (meta_protocol["response"] != null) { Int64 response = meta_protocol["response"]; protocol.response = types[(int)response]["name"]; } bool confirm = meta_protocol["confirm"]; if (confirm) { protocol.response = null; } sprotomgr.AddProtocol(protocol); } } }
public static byte[] DumpToBinary(SprotoMgr sprotomgr) { SprotoMgr meta = SprotoParser.Parse(meta_proto); SprotoObject group = meta.NewSprotoObject("group"); // make result stable List <SprotoType> types = new List <SprotoType>(sprotomgr.Types.Values); types.Sort(delegate(SprotoType lhs, SprotoType rhs) { return(string.Compare(lhs.name, rhs.name)); }); if (sprotomgr.Types.Count != 0) { List <SprotoObject> meta_types = new List <SprotoObject>(); foreach (SprotoType type in types) { SprotoObject meta_type = meta.NewSprotoObject("type"); meta_type["name"] = type.name; if (type.fields.Count != 0) { List <SprotoField> fields = new List <SprotoField>(type.fields.Values); fields.Sort(delegate(SprotoField lhs, SprotoField rhs) { return(lhs.tag < rhs.tag ? -1 : 1); }); List <SprotoObject> meta_fields = new List <SprotoObject>(); foreach (SprotoField field in fields) { SprotoObject meta_field = meta.NewSprotoObject("type.field"); meta_field["name"] = field.name; meta_field["tag"] = field.tag; if (SprotoParser.BuildInTypeName2Id.ContainsKey(field.type)) { meta_field["buildin"] = SprotoParser.BuildInTypeName2Id[field.type]; if (field.type == "binary") { meta_field["type"] = 1; } else if (field.type == "integer" && field.digit > 0) { meta_field["type"] = field.digit; } } else { meta_field["type"] = types.IndexOf(sprotomgr.Types[field.type]); } if (field.is_array) { meta_field["array"] = true; if (field.key != null) { SprotoType t = sprotomgr.Types[field.type]; SprotoField f = t.fields[field.key]; meta_field["key"] = f.tag; } } meta_fields.Add(meta_field); } meta_type["fields"] = meta_fields; } meta_types.Add(meta_type); } group["type"] = meta_types; } if (sprotomgr.Protocols.Count != 0) { // make result stable List <SprotoProtocol> protocols = new List <SprotoProtocol>(sprotomgr.Protocols.Values); protocols.Sort(delegate(SprotoProtocol lhs, SprotoProtocol rhs) { return(lhs.tag < rhs.tag ? -1 : 1); }); List <SprotoObject> meta_protocols = new List <SprotoObject>(); foreach (SprotoProtocol protocol in protocols) { SprotoObject meta_protocol = meta.NewSprotoObject("protocol"); meta_protocol["name"] = protocol.name; meta_protocol["tag"] = protocol.tag; if (protocol.request != null) { meta_protocol["request"] = types.IndexOf(sprotomgr.Types[protocol.request]); } if (protocol.response != null) { meta_protocol["response"] = types.IndexOf(sprotomgr.Types[protocol.response]); } else { meta_protocol["confirm"] = true; } meta_protocols.Add(meta_protocol); } group["protocol"] = meta_protocols; } SprotoStream writer = new SprotoStream(); meta.Encode(group, writer); byte[] result = new byte[writer.Position]; for (int i = 0; i < writer.Position; i++) { result[i] = writer.Buffer[i]; } return(result); }
public RpcMessage UnpackMessage(byte[] bytes, int size) { RpcMessage message = null; int bin_size = 0; byte[] bin = this.S2C.Unpack(bytes, 0, size, out bin_size); this.reader.Seek(0, SprotoStream.SEEK_BEGIN); // clear stream this.reader.Buffer = bin; SprotoObject header = this.S2C.Decode(this.package, this.reader); if (header["type"] != null) { // request UInt16 tag = (UInt16)header["type"]; SprotoProtocol protocol = this.S2C.GetProtocol(tag); SprotoObject request = null; if (protocol.request != null) { request = this.S2C.Decode(protocol.request, this.reader); } message = new RpcMessage(); message.type = "request"; if (header["session"] != null) { message.session = header["session"]; } if (header["ud"] != null) { message.ud = header["ud"]; } message.proto = protocol.name; message.tag = protocol.tag; message.request = request; } else { // response SprotoHelper.Assert(header["session"] != null, "session not found"); Int64 session = header["session"]; if (this.sessions.TryGetValue(session, out message)) { //Console.WriteLine("remove session {0}",session); this.sessions.Remove(session); } SprotoHelper.Assert(message != null, "unknow session"); message.type = "response"; if (header["ud"] != null) { message.ud = header["ud"]; } SprotoProtocol protocol = this.C2S.GetProtocol(message.tag); if (protocol.response != null) { SprotoObject response = this.C2S.Decode(protocol.response, this.reader); message.response = response; } } return(message); }