1
0
mirror of https://github.com/JKorf/CryptoExchange.Net synced 2025-06-10 01:16:24 +00:00
2024-02-03 15:35:27 +01:00

183 lines
6.7 KiB
C#

using CryptoExchange.Net.Interfaces;
using CryptoExchange.Net.Objects;
using CryptoExchange.Net.Objects.Sockets;
using CryptoExchange.Net.Sockets;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.WebSockets;
using System.Text;
namespace CryptoExchange.Net.Converters
{
/// <summary>
/// Socket message converter
/// </summary>
public abstract class SocketConverter
{
private static JsonSerializer _serializer = JsonSerializer.Create(SerializerOptions.WithConverters);
public abstract MessageInterpreterPipeline InterpreterPipeline { get; }
/// <inheritdoc />
public BaseParsedMessage? ReadJson(WebSocketMessageType websocketMessageType, Stream stream, Dictionary<string, Type> processors, bool outputOriginalData)
{
// Start reading the data
// Once we reach the properties that identify the message we save those in a dict
// Once all id properties have been read callback to see what the deserialization type should be
// Deserialize to the correct type
if (InterpreterPipeline.PreProcessCallback != null)
stream = InterpreterPipeline.PreProcessCallback(websocketMessageType, stream);
using var sr = new StreamReader(stream, Encoding.UTF8, false, (int)stream.Length, true);
foreach (var callback in InterpreterPipeline.PreInspectCallbacks)
{
var result = callback.Callback(stream);
if (result.Matched)
{
var data = sr.ReadToEnd();
var messageType = typeof(ParsedMessage<>).MakeGenericType(typeof(string));
var preInstance = (BaseParsedMessage)Activator.CreateInstance(messageType, data);
if (outputOriginalData)
{
stream.Position = 0;
preInstance.OriginalData = data;
}
preInstance.Identifier = result.Identifier;
preInstance.Parsed = true;
return preInstance;
}
}
using var jsonTextReader = new JsonTextReader(sr);
JToken token;
try
{
token = JToken.Load(jsonTextReader);
}
catch(Exception ex)
{
// Not a json message
return null;
}
var accessor = new JTokenAccessor(token);
if (InterpreterPipeline.GetIdentity != null)
{
var identity = InterpreterPipeline.GetIdentity(accessor);
if (identity != null)
{
if (processors.TryGetValue(identity, out var type))
{
var idInstance = InterpreterPipeline.ObjectInitializer(token, type);
if (outputOriginalData)
{
stream.Position = 0;
idInstance.OriginalData = sr.ReadToEnd();
}
idInstance.Identifier = identity;
idInstance.Parsed = true;
return idInstance;
}
}
}
PostInspectResult? inspectResult = null;
object? usedParser = null;
if (token.Type == JTokenType.Object)
{
foreach (var callback in InterpreterPipeline.PostInspectCallbacks.OfType<PostInspectCallback>())
{
bool allFieldsPresent = true;
foreach (var field in callback.TypeFields)
{
var value = accessor.GetStringValue(field.Key);
if (value == null)
{
if (field.Required)
{
allFieldsPresent = false;
break;
}
}
}
if (allFieldsPresent)
{
inspectResult = callback.Callback(accessor, processors);
usedParser = callback;
if (inspectResult.Type != null)
break;
}
}
}
else
{
foreach (var callback in InterpreterPipeline.PostInspectCallbacks.OfType<PostInspectArrayCallback>())
{
var typeIdArrayDict = new Dictionary<int, string>();
bool allFieldsPresent = true;
var maxIndex = callback.TypeFields.Max();
if (((JArray)token).Count <= maxIndex)
continue;
foreach (var field in callback.TypeFields)
{
var value = token[field];
if (value == null)
{
allFieldsPresent = false;
break;
}
typeIdArrayDict[field] = value.ToString();
}
if (allFieldsPresent)
{
inspectResult = callback.Callback(typeIdArrayDict, processors);
usedParser = callback;
break;
}
}
}
if (usedParser == null)
{
//throw new Exception("No parser found for message");
return null;
}
BaseParsedMessage instance;
if (inspectResult.Type != null)
instance = InterpreterPipeline.ObjectInitializer(token, inspectResult.Type);
else
instance = new ParsedMessage<object>(null);
if (outputOriginalData)
{
stream.Position = 0;
instance.OriginalData = sr.ReadToEnd();
}
instance.Identifier = inspectResult.Identifier;
instance.Parsed = inspectResult.Type != null;
return instance;
}
public static BaseParsedMessage InstantiateMessageObject(JToken token, Type type)
{
var resultMessageType = typeof(ParsedMessage<>).MakeGenericType(type);
var instance = (BaseParsedMessage)Activator.CreateInstance(resultMessageType, type == null ? null : token.ToObject(type, _serializer));
return instance;
}
}
}