diff --git a/CryptoExchange.Net/Converters/SystemTextJson/ObjectStringConverter.cs b/CryptoExchange.Net/Converters/SystemTextJson/ObjectStringConverter.cs index 53a77ee..2789c23 100644 --- a/CryptoExchange.Net/Converters/SystemTextJson/ObjectStringConverter.cs +++ b/CryptoExchange.Net/Converters/SystemTextJson/ObjectStringConverter.cs @@ -24,7 +24,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson if (string.IsNullOrEmpty(value)) return default; - return (T?)JsonDocument.Parse(value!).Deserialize(typeof(T), options); + return JsonDocument.Parse(value!).Deserialize(options); } /// diff --git a/CryptoExchange.Net/Sockets/Default/SocketConnection.cs b/CryptoExchange.Net/Sockets/Default/SocketConnection.cs index 1abe24a..faa769c 100644 --- a/CryptoExchange.Net/Sockets/Default/SocketConnection.cs +++ b/CryptoExchange.Net/Sockets/Default/SocketConnection.cs @@ -522,19 +522,13 @@ namespace CryptoExchange.Net.Sockets.Default } Type? deserializationType = null; - foreach (var subscription in _listeners) + foreach (var listener in _listeners) { - foreach (var route in subscription.MessageRouter.Routes) - { - if (!route.TypeIdentifier.Equals(typeIdentifier, StringComparison.Ordinal)) - continue; - - deserializationType = route.DeserializationType; + var routes = listener.MessageRouter[typeIdentifier]; + if (routes.Count > 0) { + deserializationType = routes[0].DeserializationType; break; } - - if (deserializationType != null) - break; } if (deserializationType == null) @@ -581,11 +575,13 @@ namespace CryptoExchange.Net.Sockets.Default var topicFilter = messageConverter.GetTopicFilter(result); bool processed = false; - foreach (var processor in _listeners) + foreach (var listener in _listeners) { + var routes = listener.MessageRouter[typeIdentifier]; + bool isQuery = false; Query? query = null; - if (processor is Query cquery) + if (listener is Query cquery) { isQuery = true; query = cquery; @@ -593,11 +589,8 @@ namespace CryptoExchange.Net.Sockets.Default var complete = false; - foreach (var route in processor.MessageRouter.Routes) + foreach (var route in routes) { - if (route.TypeIdentifier != typeIdentifier) - continue; - // Forward message rules: // | Message Topic | Route Topic Filter | Topics Match | Forward | Description // | N | N | - | Y | No topic filter applied @@ -623,7 +616,7 @@ namespace CryptoExchange.Net.Sockets.Default if (isQuery && query!.Completed) continue; - processor.Handle(this, receiveTime, originalData, result, route); + listener.Handle(this, receiveTime, originalData, result, route); if (isQuery && !route.MultipleReaders) { complete = true; diff --git a/CryptoExchange.Net/Sockets/Default/Subscription.cs b/CryptoExchange.Net/Sockets/Default/Subscription.cs index fd460e6..d2585ac 100644 --- a/CryptoExchange.Net/Sockets/Default/Subscription.cs +++ b/CryptoExchange.Net/Sockets/Default/Subscription.cs @@ -70,10 +70,20 @@ namespace CryptoExchange.Net.Sockets.Default /// public bool Authenticated { get; } + + private MessageRouter _router; /// /// Router for this subscription /// - public MessageRouter MessageRouter { get; set; } + public MessageRouter MessageRouter + { + get => _router; + set + { + _router = value; + _router.BuildRouteMap(); + } + } /// /// Cancellation token registration diff --git a/CryptoExchange.Net/Sockets/MessageRouter.cs b/CryptoExchange.Net/Sockets/MessageRouter.cs index 4c29763..95f44a4 100644 --- a/CryptoExchange.Net/Sockets/MessageRouter.cs +++ b/CryptoExchange.Net/Sockets/MessageRouter.cs @@ -1,6 +1,9 @@ using CryptoExchange.Net.Objects; using CryptoExchange.Net.Sockets.Default; using System; +#if NET8_0_OR_GREATER +using System.Collections.Frozen; +#endif using System.Collections.Generic; using System.Linq; @@ -16,6 +19,12 @@ namespace CryptoExchange.Net.Sockets /// public MessageRoute[] Routes { get; } +#if NET8_0_OR_GREATER + private FrozenDictionary>? _routeMap; +#else + private Dictionary>? _routeMap; +#endif + /// /// ctor /// @@ -24,6 +33,34 @@ namespace CryptoExchange.Net.Sockets Routes = routes; } + /// + /// Build the route mapping + /// + public void BuildRouteMap() + { + var newMap = new Dictionary>(); + foreach (var route in Routes) + { + if (!newMap.ContainsKey(route.TypeIdentifier)) + newMap.Add(route.TypeIdentifier, new List()); + newMap[route.TypeIdentifier].Add(route); + } + +#if NET8_0_OR_GREATER + _routeMap = newMap.ToFrozenDictionary(); +#else + _routeMap = newMap; +#endif + } + + /// + /// Get routes matching the type identifier + /// + public List this[string identifier] + { + get => (_routeMap ?? throw new InvalidOperationException("Route map not initialized before use")).TryGetValue(identifier, out var routes) ? routes: []; + } + /// /// Create message router without specific message handler /// diff --git a/CryptoExchange.Net/Sockets/Query.cs b/CryptoExchange.Net/Sockets/Query.cs index 8769814..49e3f3c 100644 --- a/CryptoExchange.Net/Sockets/Query.cs +++ b/CryptoExchange.Net/Sockets/Query.cs @@ -59,10 +59,19 @@ namespace CryptoExchange.Net.Sockets /// public object? Response { get; set; } + private MessageRouter _router; /// - /// Router for this query + /// Router for this subscription /// - public MessageRouter MessageRouter { get; set; } + public MessageRouter MessageRouter + { + get => _router; + set + { + _router = value; + _router.BuildRouteMap(); + } + } /// /// The query request object