mirror of
https://gitee.com/jisol/jisol-game/
synced 2025-09-27 02:36:14 +00:00
提交Unity 联机Pro
This commit is contained in:
@@ -0,0 +1,562 @@
|
||||
#if !BESTHTTP_DISABLE_SOCKETIO && BESTHTTP_SOCKETIO_ENABLE_NEWTONSOFT_JSON_DOTNET_ENCODER
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using BestHTTP.PlatformSupport.Memory;
|
||||
using BestHTTP.SocketIO3.Events;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BestHTTP.SocketIO3.Parsers
|
||||
{
|
||||
public sealed class JsonDotNetParser : IParser
|
||||
{
|
||||
private IncomingPacket PacketWithAttachment = IncomingPacket.Empty;
|
||||
private JsonSerializerSettings _settings;
|
||||
|
||||
public JsonDotNetParser()
|
||||
{ }
|
||||
|
||||
public JsonDotNetParser(JsonSerializerSettings settings)
|
||||
{
|
||||
this._settings = settings;
|
||||
}
|
||||
|
||||
private int ToInt(char ch)
|
||||
{
|
||||
int charValue = Convert.ToInt32(ch);
|
||||
int num = charValue - '0';
|
||||
if (num < 0 || num > 9)
|
||||
return -1;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
public IncomingPacket Parse(SocketManager manager, string from)
|
||||
{
|
||||
int idx = 0;
|
||||
var transportEvent = (TransportEventTypes)ToInt(from[idx++]);
|
||||
var socketIOEvent = SocketIOEventTypes.Unknown;
|
||||
var nsp = string.Empty;
|
||||
var id = -1;
|
||||
var payload = string.Empty;
|
||||
int attachments = 0;
|
||||
|
||||
if (from.Length > idx && ToInt(from[idx]) >= 0)
|
||||
socketIOEvent = (SocketIOEventTypes)ToInt(from[idx++]);
|
||||
else
|
||||
socketIOEvent = SocketIOEventTypes.Unknown;
|
||||
|
||||
// Parse Attachment
|
||||
if (socketIOEvent == SocketIOEventTypes.BinaryEvent || socketIOEvent == SocketIOEventTypes.BinaryAck)
|
||||
{
|
||||
int endIdx = from.IndexOf('-', idx);
|
||||
if (endIdx == -1)
|
||||
endIdx = from.Length;
|
||||
|
||||
int.TryParse(from.Substring(idx, endIdx - idx), out attachments);
|
||||
|
||||
idx = endIdx + 1;
|
||||
}
|
||||
|
||||
// Parse Namespace
|
||||
if (from.Length > idx && from[idx] == '/')
|
||||
{
|
||||
int endIdx = from.IndexOf(',', idx);
|
||||
if (endIdx == -1)
|
||||
endIdx = from.Length;
|
||||
|
||||
nsp = from.Substring(idx, endIdx - idx);
|
||||
idx = endIdx + 1;
|
||||
}
|
||||
else
|
||||
nsp = "/";
|
||||
|
||||
// Parse Id
|
||||
if (from.Length > idx && ToInt(from[idx]) >= 0)
|
||||
{
|
||||
int startIdx = idx++;
|
||||
while (from.Length > idx && ToInt(from[idx]) >= 0)
|
||||
idx++;
|
||||
|
||||
int.TryParse(from.Substring(startIdx, idx - startIdx), out id);
|
||||
}
|
||||
|
||||
// What left is the payload data
|
||||
if (from.Length > idx)
|
||||
payload = from.Substring(idx);
|
||||
else
|
||||
payload = string.Empty;
|
||||
|
||||
var packet = new IncomingPacket(transportEvent, socketIOEvent, nsp, id);
|
||||
packet.AttachementCount = attachments;
|
||||
|
||||
string eventName = packet.EventName;
|
||||
object[] args = null;
|
||||
|
||||
switch (socketIOEvent)
|
||||
{
|
||||
case SocketIOEventTypes.Unknown:
|
||||
packet.DecodedArg = payload;
|
||||
break;
|
||||
|
||||
case SocketIOEventTypes.Connect:
|
||||
// No Data | Object
|
||||
if (!string.IsNullOrEmpty(payload))
|
||||
(eventName, args) = ReadData(manager, packet, payload);
|
||||
break;
|
||||
|
||||
case SocketIOEventTypes.Disconnect:
|
||||
// No Data
|
||||
break;
|
||||
|
||||
case SocketIOEventTypes.Error:
|
||||
// String | Object
|
||||
(eventName, args) = ReadData(manager, packet, payload);
|
||||
break;
|
||||
|
||||
case SocketIOEventTypes.BinaryAck:
|
||||
// Save payload until all attachments arrive
|
||||
if (packet.AttachementCount > 0)
|
||||
packet.DecodedArg = payload;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Array
|
||||
(eventName, args) = ReadData(manager, packet, payload);
|
||||
// Save payload until all attachments arrive
|
||||
if (packet.AttachementCount > 0)
|
||||
packet.DecodedArg = payload;
|
||||
break;
|
||||
}
|
||||
|
||||
packet.EventName = eventName;
|
||||
|
||||
if (args != null)
|
||||
{
|
||||
if (args.Length == 1)
|
||||
packet.DecodedArg = args[0];
|
||||
else
|
||||
packet.DecodedArgs = args;
|
||||
}
|
||||
|
||||
if (packet.AttachementCount > 0)
|
||||
{
|
||||
PacketWithAttachment = packet;
|
||||
return IncomingPacket.Empty;
|
||||
}
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
public IncomingPacket MergeAttachements(SocketManager manager, IncomingPacket packet)
|
||||
{
|
||||
string payload = packet.DecodedArg as string;
|
||||
packet.DecodedArg = null;
|
||||
|
||||
string placeholderFormat = "{{\"_placeholder\":true,\"num\":{0}}}";
|
||||
|
||||
for (int i = 0; i < packet.Attachements.Count; ++i)
|
||||
{
|
||||
string placeholder = string.Format(placeholderFormat, i);
|
||||
BufferSegment data = packet.Attachements[i];
|
||||
|
||||
payload = payload.Replace(placeholder, "\"" + Convert.ToBase64String(data.Data, data.Offset, data.Count) + "\"");
|
||||
}
|
||||
|
||||
(string eventName, object[] args) = ReadData(manager, packet, payload);
|
||||
|
||||
packet.EventName = eventName;
|
||||
|
||||
if (args != null)
|
||||
{
|
||||
if (args.Length == 1)
|
||||
packet.DecodedArg = args[0];
|
||||
else
|
||||
packet.DecodedArgs = args;
|
||||
}
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
private (string, object[]) ReadData(SocketManager manager, IncomingPacket packet, string payload)
|
||||
{
|
||||
Socket socket = manager.GetSocket(packet.Namespace);
|
||||
|
||||
string eventName = packet.EventName;
|
||||
Subscription subscription = socket.GetSubscription(eventName);
|
||||
|
||||
object[] args = null;
|
||||
|
||||
switch (packet.SocketIOEvent)
|
||||
{
|
||||
case SocketIOEventTypes.Unknown:
|
||||
// TODO: Error?
|
||||
break;
|
||||
|
||||
case SocketIOEventTypes.Connect:
|
||||
// No Data | Object
|
||||
using (var strReader = new System.IO.StringReader(payload))
|
||||
using (var txtReader = new JsonTextReader(strReader))
|
||||
args = ReadParameters(socket, subscription, txtReader);
|
||||
break;
|
||||
|
||||
case SocketIOEventTypes.Disconnect:
|
||||
// No Data
|
||||
break;
|
||||
|
||||
case SocketIOEventTypes.Error:
|
||||
// String | Object
|
||||
switch (payload[0])
|
||||
{
|
||||
case '{':
|
||||
using (var strReader = new System.IO.StringReader(payload))
|
||||
using (var txtReader = new JsonTextReader(strReader))
|
||||
args = ReadParameters(socket, subscription, txtReader);
|
||||
break;
|
||||
|
||||
default:
|
||||
args = new object[] { new Error(payload) };
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case SocketIOEventTypes.Ack:
|
||||
case SocketIOEventTypes.BinaryAck:
|
||||
eventName = IncomingPacket.GenerateAcknowledgementNameFromId(packet.Id);
|
||||
subscription = socket.GetSubscription(eventName);
|
||||
|
||||
args = ReadParameters(socket, subscription, JsonConvert.DeserializeObject<List<object>>(payload, this._settings), 0);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
// Array
|
||||
|
||||
List<object> array = JsonConvert.DeserializeObject<List<object>>(payload, this._settings);
|
||||
|
||||
if (array.Count > 0)
|
||||
{
|
||||
eventName = array[0].ToString();
|
||||
subscription = socket.GetSubscription(eventName);
|
||||
}
|
||||
|
||||
if (packet.AttachementCount == 0 || packet.Attachements != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
args = ReadParameters(socket, subscription, array, 1);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HTTPManager.Logger.Exception("DefaultJsonParser", string.Format("ReadParameters with eventName: {0}", eventName), ex);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return (eventName, args);
|
||||
}
|
||||
|
||||
private object[] ReadParameters(Socket socket, Subscription subscription, List<object> array, int startIdx)
|
||||
{
|
||||
object[] args = null;
|
||||
|
||||
if (array.Count > startIdx)
|
||||
{
|
||||
var desc = subscription != null ? subscription.callbacks.FirstOrDefault() : default(CallbackDescriptor);
|
||||
int paramCount = desc.ParamTypes != null ? desc.ParamTypes.Length : 0;
|
||||
|
||||
int arrayIdx = startIdx;
|
||||
if (paramCount > 0)
|
||||
{
|
||||
args = new object[paramCount];
|
||||
|
||||
for (int i = 0; i < desc.ParamTypes.Length; ++i)
|
||||
{
|
||||
Type type = desc.ParamTypes[i];
|
||||
|
||||
if (type == typeof(Socket))
|
||||
args[i] = socket;
|
||||
else if (type == typeof(SocketManager))
|
||||
args[i] = socket.Manager;
|
||||
else if (type == typeof(Placeholder))
|
||||
args[i] = new Placeholder();
|
||||
else
|
||||
args[i] = ConvertTo(desc.ParamTypes[i], array[arrayIdx++]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
public object ConvertTo(Type toType, object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return null;
|
||||
|
||||
#if NETFX_CORE
|
||||
TypeInfo objType = obj.GetType().GetTypeInfo();
|
||||
#else
|
||||
Type objType = obj.GetType();
|
||||
#endif
|
||||
|
||||
#if NETFX_CORE
|
||||
TypeInfo typeInfo = toType.GetTypeInfo();
|
||||
#endif
|
||||
|
||||
#if NETFX_CORE
|
||||
if (typeInfo.IsEnum)
|
||||
#else
|
||||
if (toType.IsEnum)
|
||||
#endif
|
||||
return Enum.Parse(toType, obj.ToString(), true);
|
||||
|
||||
#if NETFX_CORE
|
||||
if (typeInfo.IsPrimitive)
|
||||
#else
|
||||
if (toType.IsPrimitive)
|
||||
#endif
|
||||
return Convert.ChangeType(obj, toType);
|
||||
|
||||
if (toType == typeof(string))
|
||||
return obj.ToString();
|
||||
|
||||
#if NETFX_CORE
|
||||
if (typeInfo.IsGenericType && toType.Name == "Nullable`1")
|
||||
return Convert.ChangeType(obj, toType.GenericTypeArguments[0]);
|
||||
#else
|
||||
if (toType.IsGenericType && toType.Name == "Nullable`1")
|
||||
return Convert.ChangeType(obj, toType.GetGenericArguments()[0]);
|
||||
#endif
|
||||
|
||||
#if NETFX_CORE
|
||||
if (objType.Equals(typeInfo))
|
||||
#else
|
||||
if (objType.Equals(toType))
|
||||
#endif
|
||||
return obj;
|
||||
|
||||
if (toType == typeof(byte[]) && objType == typeof(string))
|
||||
return Convert.FromBase64String(obj.ToString());
|
||||
|
||||
return JsonConvert.DeserializeObject(JsonConvert.SerializeObject(obj, this._settings), toType, this._settings);
|
||||
}
|
||||
|
||||
private object[] ReadParameters(Socket socket, Subscription subscription, JsonTextReader reader)
|
||||
{
|
||||
var desc = subscription != null ? subscription.callbacks.FirstOrDefault() : default(CallbackDescriptor);
|
||||
int paramCount = desc.ParamTypes != null ? desc.ParamTypes.Length : 0;
|
||||
object[] args = null;
|
||||
|
||||
if (paramCount > 0)
|
||||
{
|
||||
args = new object[paramCount];
|
||||
|
||||
for (int i = 0; i < desc.ParamTypes.Length; ++i)
|
||||
{
|
||||
Type type = desc.ParamTypes[i];
|
||||
|
||||
if (type == typeof(Socket))
|
||||
args[i] = socket;
|
||||
else if (type == typeof(SocketManager))
|
||||
args[i] = socket.Manager;
|
||||
else
|
||||
{
|
||||
args[i] = JsonSerializer.CreateDefault(this._settings).Deserialize(reader, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
public IncomingPacket Parse(SocketManager manager, BufferSegment data, TransportEventTypes transportEvent = TransportEventTypes.Unknown)
|
||||
{
|
||||
IncomingPacket packet = IncomingPacket.Empty;
|
||||
|
||||
if (PacketWithAttachment.Attachements == null)
|
||||
PacketWithAttachment.Attachements = new List<BufferSegment>(PacketWithAttachment.AttachementCount);
|
||||
PacketWithAttachment.Attachements.Add(data);
|
||||
|
||||
if (PacketWithAttachment.Attachements.Count == PacketWithAttachment.AttachementCount)
|
||||
{
|
||||
packet = manager.Parser.MergeAttachements(manager, PacketWithAttachment);
|
||||
PacketWithAttachment = IncomingPacket.Empty;
|
||||
}
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
public OutgoingPacket CreateOutgoing(TransportEventTypes transportEvent, string payload)
|
||||
{
|
||||
return new OutgoingPacket { Payload = "" + (char)('0' + (byte)transportEvent) + payload };
|
||||
}
|
||||
|
||||
private StringBuilder builder = new StringBuilder();
|
||||
public OutgoingPacket CreateOutgoing(Socket socket, SocketIOEventTypes socketIOEvent, int id, string name, object arg)
|
||||
{
|
||||
return CreateOutgoing(socket, socketIOEvent, id, name, arg != null ? new object[] { arg } : null);
|
||||
}
|
||||
|
||||
private int GetBinaryCount(object[] args)
|
||||
{
|
||||
if (args == null || args.Length == 0)
|
||||
return 0;
|
||||
|
||||
int count = 0;
|
||||
for (int i = 0; i < args.Length; ++i)
|
||||
if (args[i] is byte[])
|
||||
count++;
|
||||
|
||||
return count;
|
||||
}
|
||||
public OutgoingPacket CreateOutgoing(Socket socket, SocketIOEventTypes socketIOEvent, int id, string name, object[] args)
|
||||
{
|
||||
builder.Length = 0;
|
||||
List<byte[]> attachements = null;
|
||||
|
||||
switch (socketIOEvent)
|
||||
{
|
||||
case SocketIOEventTypes.Ack:
|
||||
if (GetBinaryCount(args) > 0)
|
||||
{
|
||||
attachements = CreatePlaceholders(args);
|
||||
socketIOEvent = SocketIOEventTypes.BinaryAck;
|
||||
}
|
||||
break;
|
||||
|
||||
case SocketIOEventTypes.Event:
|
||||
if (GetBinaryCount(args) > 0)
|
||||
{
|
||||
attachements = CreatePlaceholders(args);
|
||||
socketIOEvent = SocketIOEventTypes.BinaryEvent;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
builder.Append(((int)TransportEventTypes.Message).ToString());
|
||||
builder.Append(((int)socketIOEvent).ToString());
|
||||
|
||||
if (socketIOEvent == SocketIOEventTypes.BinaryEvent || socketIOEvent == SocketIOEventTypes.BinaryAck)
|
||||
{
|
||||
builder.Append(attachements.Count.ToString());
|
||||
builder.Append('-');
|
||||
}
|
||||
|
||||
// Add the namespace. If there is any other then the root nsp ("/")
|
||||
// then we have to add a trailing "," if we have more data.
|
||||
bool nspAdded = false;
|
||||
if (socket.Namespace != "/")
|
||||
{
|
||||
builder.Append(socket.Namespace);
|
||||
nspAdded = true;
|
||||
}
|
||||
|
||||
// ack id, if any
|
||||
if (id >= 0)
|
||||
{
|
||||
if (nspAdded)
|
||||
{
|
||||
builder.Append(',');
|
||||
nspAdded = false;
|
||||
}
|
||||
|
||||
builder.Append(id.ToString());
|
||||
}
|
||||
|
||||
// payload
|
||||
switch (socketIOEvent)
|
||||
{
|
||||
case SocketIOEventTypes.Connect:
|
||||
// No Data | Object
|
||||
if (args != null && args.Length > 0)
|
||||
{
|
||||
if (nspAdded) builder.Append(',');
|
||||
|
||||
builder.Append(JsonConvert.SerializeObject(args[0], this._settings));
|
||||
}
|
||||
break;
|
||||
|
||||
case SocketIOEventTypes.Disconnect:
|
||||
// No Data
|
||||
break;
|
||||
|
||||
case SocketIOEventTypes.Error:
|
||||
// String | Object
|
||||
if (args != null && args.Length > 0)
|
||||
{
|
||||
if (nspAdded) builder.Append(',');
|
||||
|
||||
builder.Append(JsonConvert.SerializeObject(args[0], this._settings));
|
||||
}
|
||||
break;
|
||||
|
||||
case SocketIOEventTypes.Ack:
|
||||
case SocketIOEventTypes.BinaryAck:
|
||||
if (nspAdded) builder.Append(',');
|
||||
|
||||
if (args != null && args.Length > 0)
|
||||
{
|
||||
builder.Append(JsonConvert.SerializeObject(args, this._settings));
|
||||
}
|
||||
else
|
||||
builder.Append("[]");
|
||||
break;
|
||||
|
||||
default:
|
||||
if (nspAdded) builder.Append(',');
|
||||
|
||||
// Array
|
||||
builder.Append('[');
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
{
|
||||
builder.Append('\"');
|
||||
builder.Append(name);
|
||||
builder.Append('\"');
|
||||
}
|
||||
|
||||
if (args != null && args.Length > 0)
|
||||
{
|
||||
builder.Append(',');
|
||||
|
||||
var argsJson = JsonConvert.SerializeObject(args, this._settings);
|
||||
builder.Append(argsJson, 1, argsJson.Length - 2);
|
||||
}
|
||||
|
||||
builder.Append(']');
|
||||
break;
|
||||
}
|
||||
|
||||
return new OutgoingPacket { Payload = builder.ToString(), Attachements = attachements };
|
||||
}
|
||||
|
||||
private List<byte[]> CreatePlaceholders(object[] args)
|
||||
{
|
||||
List<byte[]> attachements = null;
|
||||
|
||||
for (int i = 0; i < args.Length; ++i)
|
||||
{
|
||||
var binary = args[i] as byte[];
|
||||
if (binary != null)
|
||||
{
|
||||
if (attachements == null)
|
||||
attachements = new List<byte[]>();
|
||||
attachements.Add(binary);
|
||||
|
||||
args[i] = new Placeholder { _placeholder = true, num = attachements.Count - 1 };
|
||||
}
|
||||
}
|
||||
|
||||
return attachements;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c1b1e9a202e74ba4089e4aa518f64109
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,500 @@
|
||||
#if !BESTHTTP_DISABLE_SOCKETIO && BESTHTTP_SOCKETIO_ENABLE_GAMEDEVWARE_MESSAGEPACK
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
using BestHTTP.PlatformSupport.Memory;
|
||||
using BestHTTP.SocketIO3.Events;
|
||||
|
||||
using GameDevWare.Serialization;
|
||||
using GameDevWare.Serialization.MessagePack;
|
||||
using GameDevWare.Serialization.Serializers;
|
||||
|
||||
namespace BestHTTP.SocketIO3.Parsers
|
||||
{
|
||||
public sealed class MsgPackParser : IParser
|
||||
{
|
||||
// Variables to calculate an average buffer size to start with in CreateOutgoing
|
||||
ulong sumLength;
|
||||
uint count;
|
||||
|
||||
/// <summary>
|
||||
/// Custom function instead of char.GetNumericValue, as it throws an error under WebGL using the new 4.x runtime.
|
||||
/// It will return the value of the char if it's a numeric one, otherwise -1.
|
||||
/// </summary>
|
||||
private int ToInt(char ch)
|
||||
{
|
||||
int charValue = Convert.ToInt32(ch);
|
||||
int num = charValue - '0';
|
||||
if (num < 0 || num > 9)
|
||||
return -1;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
public IncomingPacket MergeAttachements(SocketManager manager, IncomingPacket packet) { return packet; }
|
||||
|
||||
public IncomingPacket Parse(SocketManager manager, string from)
|
||||
{
|
||||
int idx = 0;
|
||||
var transportEvent = (TransportEventTypes)ToInt(from[idx++]);
|
||||
var socketIOEvent = SocketIOEventTypes.Unknown;
|
||||
var nsp = string.Empty;
|
||||
var id = -1;
|
||||
var payload = string.Empty;
|
||||
int attachments = 0;
|
||||
|
||||
if (from.Length > idx && ToInt(from[idx]) >= 0)
|
||||
socketIOEvent = (SocketIOEventTypes)ToInt(from[idx++]);
|
||||
else
|
||||
socketIOEvent = SocketIOEventTypes.Unknown;
|
||||
|
||||
// Parse Attachment
|
||||
if (socketIOEvent == SocketIOEventTypes.BinaryEvent || socketIOEvent == SocketIOEventTypes.BinaryAck)
|
||||
{
|
||||
int endIdx = from.IndexOf('-', idx);
|
||||
if (endIdx == -1)
|
||||
endIdx = from.Length;
|
||||
|
||||
int.TryParse(from.Substring(idx, endIdx - idx), out attachments);
|
||||
idx = endIdx + 1;
|
||||
}
|
||||
|
||||
// Parse Namespace
|
||||
if (from.Length > idx && from[idx] == '/')
|
||||
{
|
||||
int endIdx = from.IndexOf(',', idx);
|
||||
if (endIdx == -1)
|
||||
endIdx = from.Length;
|
||||
|
||||
nsp = from.Substring(idx, endIdx - idx);
|
||||
idx = endIdx + 1;
|
||||
}
|
||||
else
|
||||
nsp = "/";
|
||||
|
||||
// Parse Id
|
||||
if (from.Length > idx && ToInt(from[idx]) >= 0)
|
||||
{
|
||||
int startIdx = idx++;
|
||||
while (from.Length > idx && ToInt(from[idx]) >= 0)
|
||||
idx++;
|
||||
|
||||
int.TryParse(from.Substring(startIdx, idx - startIdx), out id);
|
||||
}
|
||||
|
||||
// What left is the payload data
|
||||
if (from.Length > idx)
|
||||
payload = from.Substring(idx);
|
||||
else
|
||||
payload = string.Empty;
|
||||
|
||||
return new IncomingPacket(transportEvent, socketIOEvent, nsp, id) { DecodedArg = payload, AttachementCount = attachments };
|
||||
}
|
||||
|
||||
public IncomingPacket Parse(SocketManager manager, BufferSegment data, TransportEventTypes transportEvent = TransportEventTypes.Unknown)
|
||||
{
|
||||
using (var stream = new System.IO.MemoryStream(data.Data, data.Offset, data.Count))
|
||||
{
|
||||
var buff = BufferPool.Get(MsgPackReader.DEFAULT_BUFFER_SIZE, true);
|
||||
try
|
||||
{
|
||||
var context = new SerializationContext
|
||||
{
|
||||
Options = SerializationOptions.SuppressTypeInformation/*,
|
||||
ExtensionTypeHandler = CustomMessagePackExtensionTypeHandler.Instance*/
|
||||
};
|
||||
IJsonReader reader = new MsgPackReader(stream, context, Endianness.BigEndian, buff);
|
||||
|
||||
reader.ReadObjectBegin();
|
||||
|
||||
int type = -1, id = -1;
|
||||
string nsp = null;
|
||||
|
||||
bool hasData = false, readData = false;
|
||||
|
||||
IncomingPacket packet = IncomingPacket.Empty;
|
||||
|
||||
READ:
|
||||
|
||||
while (reader.Token != JsonToken.EndOfObject)
|
||||
{
|
||||
string key = reader.ReadMember();
|
||||
|
||||
switch(key)
|
||||
{
|
||||
case "type":
|
||||
type = reader.ReadByte();
|
||||
break;
|
||||
|
||||
case "nsp":
|
||||
nsp = reader.ReadString();
|
||||
break;
|
||||
|
||||
case "id":
|
||||
id = reader.ReadInt32();
|
||||
break;
|
||||
|
||||
case "data":
|
||||
if (!hasData)
|
||||
{
|
||||
hasData = true;
|
||||
SkipData(reader, (SocketIOEventTypes)type);
|
||||
}
|
||||
else
|
||||
{
|
||||
readData = true;
|
||||
|
||||
packet = new IncomingPacket(transportEvent != TransportEventTypes.Unknown ? transportEvent : TransportEventTypes.Message, (SocketIOEventTypes)type, nsp, id);
|
||||
(string eventName, object[] args) = ReadData(manager, packet, reader);
|
||||
|
||||
packet.EventName = eventName;
|
||||
if (args != null)
|
||||
{
|
||||
if (args.Length == 1)
|
||||
packet.DecodedArg = args[0];
|
||||
else
|
||||
packet.DecodedArgs = args;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// type, nsp, id and data can come in any order. To read data strongly typed we need to know all the additional fields before processing the data field.
|
||||
// In order to do it, when we first encounter the data field we skip it than we do a reset and an additional turn but reading the data too now.
|
||||
if (hasData && !readData)
|
||||
{
|
||||
reader.Reset();
|
||||
stream.Position = 0;
|
||||
reader.ReadObjectBegin();
|
||||
|
||||
goto READ;
|
||||
}
|
||||
|
||||
reader.ReadObjectEnd();
|
||||
|
||||
return packet.Equals(IncomingPacket.Empty) ? new IncomingPacket(transportEvent != TransportEventTypes.Unknown ? transportEvent : TransportEventTypes.Message, (SocketIOEventTypes)type, nsp, id) : packet;
|
||||
}
|
||||
finally
|
||||
{
|
||||
BufferPool.Release(buff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SkipData(IJsonReader reader, SocketIOEventTypes type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case SocketIOEventTypes.Unknown:
|
||||
// TODO: Error?
|
||||
break;
|
||||
|
||||
case SocketIOEventTypes.Connect:
|
||||
// No Data | Object
|
||||
SkipObject(reader);
|
||||
break;
|
||||
|
||||
case SocketIOEventTypes.Disconnect:
|
||||
// No Data
|
||||
break;
|
||||
|
||||
case SocketIOEventTypes.Error:
|
||||
// String | Object
|
||||
switch(reader.Token)
|
||||
{
|
||||
case JsonToken.StringLiteral:
|
||||
reader.ReadString();
|
||||
break;
|
||||
|
||||
case JsonToken.BeginObject:
|
||||
SkipObject(reader);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Array
|
||||
SkipArray(reader, false, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private object[] ReadParameters(Socket socket, Subscription subscription, IJsonReader reader, bool isInArray)
|
||||
{
|
||||
var desc = subscription != null ? subscription.callbacks.FirstOrDefault() : default(CallbackDescriptor);
|
||||
int paramCount = desc.ParamTypes != null ? desc.ParamTypes.Length : 0;
|
||||
object[] args = null;
|
||||
|
||||
if (paramCount > 0)
|
||||
{
|
||||
args = new object[paramCount];
|
||||
|
||||
for (int i = 0; i < desc.ParamTypes.Length; ++i)
|
||||
{
|
||||
Type type = desc.ParamTypes[i];
|
||||
|
||||
if (type == typeof(Socket))
|
||||
args[i] = socket;
|
||||
else if (type == typeof(SocketManager))
|
||||
args[i] = socket.Manager;
|
||||
else
|
||||
args[i] = reader.ReadValue(desc.ParamTypes[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isInArray)
|
||||
{
|
||||
if (reader.Token != JsonToken.EndOfArray)
|
||||
SkipArray(reader, true, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
SkipObject(reader);
|
||||
}
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
private (string, object[]) ReadData(SocketManager manager, IncomingPacket packet, IJsonReader reader)
|
||||
{
|
||||
Socket socket = manager.GetSocket(packet.Namespace);
|
||||
|
||||
string eventName = packet.EventName;
|
||||
Subscription subscription = socket.GetSubscription(eventName);
|
||||
|
||||
object[] args = null;
|
||||
|
||||
switch (packet.SocketIOEvent)
|
||||
{
|
||||
case SocketIOEventTypes.Unknown:
|
||||
// TODO: Error?
|
||||
break;
|
||||
|
||||
case SocketIOEventTypes.Connect:
|
||||
// No Data | Object
|
||||
args = ReadParameters(socket, subscription, reader, false);
|
||||
//SkipObject(reader);
|
||||
break;
|
||||
|
||||
case SocketIOEventTypes.Disconnect:
|
||||
// No Data
|
||||
break;
|
||||
|
||||
case SocketIOEventTypes.Error:
|
||||
// String | Object
|
||||
switch(reader.Token)
|
||||
{
|
||||
case JsonToken.StringLiteral:
|
||||
args = new object[] { new Error(reader.ReadString()) };
|
||||
break;
|
||||
|
||||
case JsonToken.BeginObject:
|
||||
args = ReadParameters(socket, subscription, reader, false);
|
||||
//if (subscription == null && args == null)
|
||||
// SkipObject(reader);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case SocketIOEventTypes.Ack:
|
||||
eventName = IncomingPacket.GenerateAcknowledgementNameFromId(packet.Id);
|
||||
subscription = socket.GetSubscription(eventName);
|
||||
|
||||
reader.ReadArrayBegin();
|
||||
|
||||
args = ReadParameters(socket, subscription, reader, true);
|
||||
|
||||
reader.ReadArrayEnd();
|
||||
break;
|
||||
|
||||
default:
|
||||
// Array
|
||||
reader.ReadArrayBegin();
|
||||
eventName = reader.ReadString();
|
||||
|
||||
subscription = socket.GetSubscription(eventName);
|
||||
|
||||
args = ReadParameters(socket, subscription, reader, true);
|
||||
|
||||
reader.ReadArrayEnd();
|
||||
break;
|
||||
}
|
||||
|
||||
return (eventName, args);
|
||||
}
|
||||
|
||||
private void SkipArray(IJsonReader reader, bool alreadyStarted, bool readFinalArrayToken)
|
||||
{
|
||||
if (!alreadyStarted)
|
||||
reader.ReadArrayBegin();
|
||||
|
||||
int arrayBegins = 1;
|
||||
|
||||
while (arrayBegins > 0)
|
||||
{
|
||||
switch (reader.Token)
|
||||
{
|
||||
case JsonToken.BeginArray: arrayBegins++; break;
|
||||
case JsonToken.EndOfArray: arrayBegins--; break;
|
||||
}
|
||||
|
||||
if (readFinalArrayToken || arrayBegins >= 1)
|
||||
reader.NextToken();
|
||||
}
|
||||
}
|
||||
|
||||
private void SkipObject(IJsonReader reader)
|
||||
{
|
||||
reader.ReadObjectBegin();
|
||||
int objectBegins = 1;
|
||||
|
||||
while (objectBegins > 0)
|
||||
{
|
||||
switch (reader.Token)
|
||||
{
|
||||
case JsonToken.BeginObject: objectBegins++; break;
|
||||
case JsonToken.EndOfObject: objectBegins--; break;
|
||||
}
|
||||
reader.NextToken();
|
||||
}
|
||||
}
|
||||
|
||||
public OutgoingPacket CreateOutgoing(TransportEventTypes transportEvent, string payload)
|
||||
{
|
||||
return new OutgoingPacket { Payload = "" + (char)('0' + (byte)transportEvent) + payload };
|
||||
}
|
||||
|
||||
public OutgoingPacket CreateOutgoing(Socket socket, SocketIOEventTypes socketIOEvent, int id, string name, object arg)
|
||||
{
|
||||
return CreateOutgoing(socket, socketIOEvent, id, name, arg != null ? new object[] { arg } : null);
|
||||
}
|
||||
|
||||
public OutgoingPacket CreateOutgoing(Socket socket, SocketIOEventTypes socketIOEvent, int id, string name, object[] args)
|
||||
{
|
||||
var memBufferTargetLength = count == 0 ? 256 : Math.Max(256, (sumLength / count) / 2);
|
||||
|
||||
var memBuffer = BufferPool.Get((long)memBufferTargetLength, true);
|
||||
var stream = new BestHTTP.Extensions.BufferPoolMemoryStream(memBuffer, 0, memBuffer.Length, true, true, false, true);
|
||||
|
||||
var buffer = BufferPool.Get(MsgPackWriter.DEFAULT_BUFFER_SIZE, true);
|
||||
|
||||
var context = new SerializationContext
|
||||
{
|
||||
Options = SerializationOptions.SuppressTypeInformation,
|
||||
EnumSerializerFactory = (enumType) => new EnumNumberSerializer(enumType)/*,
|
||||
ExtensionTypeHandler = CustomMessagePackExtensionTypeHandler.Instance*/
|
||||
};
|
||||
|
||||
var writer = new MsgPackWriter(stream, context, buffer);
|
||||
|
||||
switch (socketIOEvent)
|
||||
{
|
||||
case SocketIOEventTypes.Connect:
|
||||
// No Data | Object
|
||||
if (args != null && args.Length > 0 && args[0] != null)
|
||||
writer.WriteObjectBegin(id >= 0 ? 4 : 3);
|
||||
else
|
||||
writer.WriteObjectBegin(id >= 0 ? 3 : 2);
|
||||
break;
|
||||
|
||||
case SocketIOEventTypes.Disconnect: writer.WriteObjectBegin(id > 0 ? 3 : 2); break;
|
||||
case SocketIOEventTypes.Error: writer.WriteObjectBegin(id > 0 ? 4 : 3); break;
|
||||
default: writer.WriteObjectBegin(id >= 0 ? 4 : 3); break;
|
||||
}
|
||||
|
||||
writer.WriteMember("type");
|
||||
writer.Write((int)socketIOEvent);
|
||||
|
||||
writer.WriteMember("nsp");
|
||||
writer.Write(socket.Namespace);
|
||||
|
||||
if (id >= 0)
|
||||
{
|
||||
writer.WriteMember("id");
|
||||
writer.Write(id);
|
||||
}
|
||||
|
||||
switch (socketIOEvent)
|
||||
{
|
||||
case SocketIOEventTypes.Connect:
|
||||
// No Data | Object
|
||||
if (args != null && args.Length > 0 && args[0] != null)
|
||||
{
|
||||
writer.WriteMember("data");
|
||||
writer.WriteValue(args[0], args[0].GetType());
|
||||
}
|
||||
break;
|
||||
|
||||
case SocketIOEventTypes.Disconnect:
|
||||
// No Data
|
||||
break;
|
||||
|
||||
case SocketIOEventTypes.Error:
|
||||
writer.WriteMember("data");
|
||||
|
||||
// String | Object
|
||||
if (args != null && args.Length > 0)
|
||||
writer.WriteValue(args[0], args[0].GetType());
|
||||
else
|
||||
{
|
||||
writer.WriteObjectBegin(0);
|
||||
writer.WriteObjectEnd();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
writer.WriteMember("data");
|
||||
|
||||
// Array
|
||||
|
||||
int argCount = (args != null ? args.Length : 0);
|
||||
writer.WriteArrayBegin(!string.IsNullOrEmpty(name) ? 1 + argCount : argCount);
|
||||
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
writer.Write(name);
|
||||
|
||||
if (args != null && args.Length > 0)
|
||||
{
|
||||
foreach (var arg in args)
|
||||
{
|
||||
if (arg != null)
|
||||
writer.WriteValue(arg, arg.GetType());
|
||||
else
|
||||
writer.WriteNull();
|
||||
}
|
||||
}
|
||||
|
||||
writer.WriteArrayEnd();
|
||||
break;
|
||||
}
|
||||
|
||||
writer.WriteObjectEnd();
|
||||
|
||||
writer.Flush();
|
||||
|
||||
BufferPool.Release(buffer);
|
||||
|
||||
// get how much bytes got written to the buffer
|
||||
int length = (int)stream.Position;
|
||||
|
||||
buffer = stream.GetBuffer();
|
||||
|
||||
sumLength += (ulong)length;
|
||||
count++;
|
||||
|
||||
if(sumLength >= int.MaxValue)
|
||||
{
|
||||
sumLength /= count;
|
||||
count = 1;
|
||||
}
|
||||
|
||||
return new OutgoingPacket { PayloadData = new BufferSegment(buffer, 0, length) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c140b7f57ea9266438bfa03cd086bacf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user