Example #1
0
        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);
            }
        }
Example #2
0
        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());
        }