public async ValueTask <IReadOnlyCollection <IMessage> > RouteAsync(RouteHierarchy routes, IMessage serializedMessage, bool publish, CancellationToken cancellation) { if (routes == null) { throw new ArgumentNullException(nameof(routes)); } if (serializedMessage == null) { throw new ArgumentNullException(nameof(serializedMessage)); } if (!routes.Any()) { throw new ArgumentException("The collection must not be empty.", nameof(routes)); } if (routes.Any(p => p == null)) { throw new ArgumentException("The collection must not contain null values.", nameof(routes)); } try { using (var guard = await _disposeHelper.GuardDisposalAsync(cancellation)) { return(await InternalRouteAsync(routes, serializedMessage, publish, cancellation)); } } catch (OperationCanceledException) when(_disposeHelper.IsDisposed) { throw new ObjectDisposedException(GetType().FullName); } }
private async ValueTask <IReadOnlyCollection <IMessage> > InternalRouteAsync(RouteHierarchy routes, IMessage serializedMessage, bool publish, CancellationToken cancellation) { var localEndPoint = await GetLocalEndPointAsync(cancellation); var tasks = new List <ValueTask <(IMessage response, bool handled)> >(); var handledEndPoints = new HashSet <EndPointAddress>(); _logger?.LogTrace($"Routing a message ({(publish ? "publish" : "p2p")}) with routes: {routes}"); foreach (var route in routes) { var matches = await MatchRouteAsync(route, publish, handledEndPoints, cancellation); if (matches.Any()) { if (!publish) { _logger?.LogTrace($"Found {matches.Count()} matches for route '{route}'."); for (var i = matches.Count - 1; i >= 0; i--) { var(endPoint, options) = matches[i]; if (endPoint == EndPointAddress.UnknownAddress) { continue; } if ((options & RouteRegistrationOptions.PublishOnly) == RouteRegistrationOptions.PublishOnly) { continue; } var(response, handled) = await InternalRouteAsync(route, serializedMessage, publish : false, endPoint, cancellation); if (handled) { return(response.Yield().ToArray()); } } } else { _logger?.LogTrace($"Found {matches.Count()} matches (considering handled end-points) for route '{route}'."); var endPoints = matches.Select(p => p.EndPoint); handledEndPoints.UnionWith(endPoints); tasks.AddRange(endPoints.Select(endPoint => InternalRouteAsync(route, serializedMessage, publish: true, endPoint, cancellation))); } } } var result = await ValueTaskHelper.WhenAll(tasks, preserveOrder : false); _logger?.LogTrace($"Successfully routed a message ({(publish ? "publish" : "p2p")}) with routes: {routes}"); return(result.Where(p => p.handled).Select(p => p.response).ToArray()); }