using CryptoExchange.Net.Objects; using System; using System.Collections.Generic; using System.Linq; namespace CryptoExchange.Net.Sockets.Default.Routing { /// /// Message router /// public class MessageRouter { private ProcessorRouter? _routingTable; /// /// The routes registered for this router /// public MessageRoute[] Routes { get; } /// /// ctor /// private MessageRouter(params MessageRoute[] routes) { Routes = routes; } private RouteCollection? GetRoutes(string typeIdentifier) => (_routingTable ?? throw new NullReferenceException("Routing table not build before handling")).GetRoutes(typeIdentifier); /// /// Build the route mapping /// public void BuildQueryRouter() { _routingTable = new QueryRouter(Routes); } /// /// Build the route mapping /// public void BuildSubscriptionRouter() { _routingTable = new SubscriptionRouter(Routes); } /// /// Handle message /// public bool Handle(string typeIdentifier, string? topicFilter, SocketConnection connection, DateTime receiveTime, string? originalData, object data, out CallResult? result) { var routeCollection = GetRoutes(typeIdentifier); if (routeCollection == null) throw new InvalidOperationException($"No routes for {typeIdentifier} message type"); return routeCollection.Handle(topicFilter, connection, receiveTime, originalData, data, out result); } /// /// Whether the router has a matching route for the specified message type and topic /// public bool CanHandle(string typeIdentifier, string? topicFilter) { return GetRoutes(typeIdentifier)?.CanHandle(topicFilter) == true; } /// /// Create a void handler /// public static MessageRouter CreateVoid(string typeIdentifier) { return new MessageRouter(new EventRoute(typeIdentifier, null, (con, time, originalData, msg) => CallResult.Ok(default!))); } /// /// Create a router for handling event messages /// public static MessageRouter CreateForEvent(string typeIdentifier, Func handler, bool multipleReaders = false) { return new MessageRouter(new EventRoute(typeIdentifier, null, handler) { MultipleReaders = multipleReaders }); } /// /// Create a router for handling event messages /// public static MessageRouter CreateForEvent(IEnumerable typeIdentifier, Func handler, bool multipleReaders = false) { return new MessageRouter(typeIdentifier.Select(x => new EventRoute(x, null, handler) { MultipleReaders = multipleReaders }).ToArray()); } /// /// Create a router for handling event messages /// public static MessageRouter CreateForEvent(IEnumerable typeIdentifier, IEnumerable topicFilters, Func handler, bool multipleReaders = false) { return new MessageRouter(typeIdentifier.SelectMany(x => { var routes = new List(); foreach (var topicFilter in topicFilters) { routes.Add(new EventRoute(x, topicFilter, handler) { MultipleReaders = multipleReaders }); } return routes; }).ToArray()); } /// /// Create a router for handling event messages /// public static MessageRouter CreateForEvent(string typeIdentifier, string? topicFilter, Func handler, bool multipleReaders = false) { return new MessageRouter(new EventRoute(typeIdentifier, topicFilter, handler) { MultipleReaders = multipleReaders }); } /// /// Create a router for handling event messages /// public static MessageRouter CreateForEvent(string typeIdentifier, IEnumerable topicFilters, Func handler, bool multipleReaders = false) { return new MessageRouter(topicFilters.Select(x => new EventRoute(typeIdentifier, x, handler) { MultipleReaders = multipleReaders }).ToArray()); } /// /// Create a router for handling query responses /// public static MessageRouter CreateForQuery(IEnumerable typeIdentifier, Func?> handler, bool multipleReaders = false) { return new MessageRouter(typeIdentifier.Select(x => new QueryRoute(x, null, handler) { MultipleReaders = multipleReaders }).ToArray()); } /// /// Create a router for handling query responses /// public static MessageRouter CreateForQuery(string typeIdentifier, Func?> handler, bool multipleReaders = false) { return new MessageRouter(new QueryRoute(typeIdentifier, null, handler) { MultipleReaders = multipleReaders }); } /// /// Create a router for handling query responses /// public static MessageRouter CreateForQuery(string typeIdentifier, string? topicFilter, Func?> handler, bool multipleReaders = false) { return new MessageRouter(new QueryRoute(typeIdentifier, topicFilter, handler) { MultipleReaders = multipleReaders }); } /// /// Create a router for handling query responses /// public static MessageRouter CreateForQuery(string typeIdentifier, Func?> handler, bool multipleReaders = false) { return new MessageRouter(new QueryRoute(typeIdentifier, null, handler) { MultipleReaders = multipleReaders }); } /// /// Create a router for handling query responses /// public static MessageRouter CreateForQuery(string typeIdentifier, string? topicFilter, Func?> handler, bool multipleReaders = false) { return new MessageRouter(new QueryRoute(typeIdentifier, topicFilter, handler) { MultipleReaders = multipleReaders }); } /// /// Create message matcher with specific routes /// public static MessageRouter Create(params MessageRoute[] routes) { return new MessageRouter(routes); } /// /// Whether this matcher contains a specific link /// public bool ContainsCheck(MessageRoute route) => Routes.Any(x => x.TypeIdentifier == route.TypeIdentifier && x.TopicFilter == route.TopicFilter); } }