private async ValueTask <IAppConnection> ResolveTargetConnectionAsync(
            IProvidedMethodReference methodReference,
            IAppConnection source,
            IContextLinkageOptions contextLinkageOptions)
        {
            var method     = _registryService.GetProvidedMethod(methodReference);
            var launchMode = GetLaunchMode(method);
            var appId      = methodReference.ProvidedService.ApplicationId;

            if (methodReference.ProvidedService.ConnectionId.HasValue)
            {
                var connectionId = methodReference.ProvidedService.ConnectionId.Value;
                if (!_appLifecycleManager.TryGetOnlineConnection(connectionId, out var connection))
                {
                    throw new InvalidOperationException($"The requested app {appId} connection {connectionId} is not online");
                }
                return(connection);
            }
            Task <ResolvedConnection> resolveTask;

            lock (_resolveConnectionSync)
            {
                if (launchMode != LaunchMode.MultiInstance)
                {
                    var onlineConnections = _appLifecycleManager
                                            .GetOnlineConnections()
                                            .Where(x => x.Info.ApplicationId.Equals(appId) &&
                                                   !x.Id.Equals(source.Id)).ToArray();

                    if (_contextLinkageManager.IsContextShouldBeConsidered(contextLinkageOptions, source))
                    {
                        onlineConnections = _contextLinkageManager
                                            .GetAppsInContexts(contextLinkageOptions, source, true)
                                            .Join(onlineConnections, x => x.ConnectionId.Value, y => y.Id, (x, y) => y)
                                            .ToArray();
                    }

                    if (onlineConnections.Any())
                    {
                        return(onlineConnections.First());
                    }
                }

                if (launchMode == LaunchMode.None || !_appLifecycleManager.CanBeLaunched(appId))
                {
                    throw new InvalidOperationException(
                              $"The requested app {appId} is not online and cannot be launched");
                }

                var resolveMode = ConvertToResolveMode(launchMode);

                resolveTask = _appLifecycleManager.LaunchAndConnectAsync(appId, resolveMode, source.Info);
            }
            var resolvedConnection = await resolveTask.ConfigureAwait(false);

            return(resolvedConnection.AppConnection);
        }
예제 #2
0
        private async ValueTask <IAppConnection> ResolveTargetConnectionAsync(
            IProvidedMethodReference methodReference,
            IAppConnection source,
            ITransportChannel sourceChannel,
            IContextLinkageOptions contextLinkageOptions)
        {
            if (methodReference.ProvidedService.ConnectionId.HasValue)
            {
                var connectionId = methodReference.ProvidedService.ConnectionId.Value;
                if (!_appLifecycleManager.TryGetOnlineConnection(connectionId, out var connection))
                {
                    throw new InvalidOperationException($"The requested connection {connectionId} is not online");
                }
                return(connection);
            }

            var appId = methodReference.ProvidedService.ApplicationId;

            if (methodReference.ProvidedService.ApplicationInstanceId.HasValue)
            {
                var appInstanceId = methodReference.ProvidedService.ApplicationInstanceId.Value;
                if (appId.HasValue && _appLifecycleManager.TryGetConnectionInProgress(appInstanceId, appId.Value, out var connectionInProgress))
                {
                    return(await connectionInProgress);
                }
                var connections = _appLifecycleManager.GetAppInstanceConnections(appInstanceId).ToList();
                if (connections.Count == 0)
                {
                    throw new InvalidOperationException($"App instance {appInstanceId} is doesn't have online connections");
                }

                if (appId.HasValue)
                {
                    var connection = connections.FirstOrDefault(c => c.Info.ApplicationId.Equals(appId.Value));
                    if (connection == null)
                    {
                        throw new InvalidOperationException($"App instance {appInstanceId} is doesn't have connection with {appId.Value} application id");
                    }
                    return(connection);
                }

                if (connections.Count == 1)
                {
                    return(connections.Single());
                }

                throw new InvalidOperationException($"App instance {appInstanceId} has several connections, you need to specify ApplicationId to make call to specific connection");
            }

            if (!appId.HasValue)
            {
                throw new InvalidOperationException($"AppId is required to resolve target connection for {methodReference} provided method reference");
            }
            var appIdValue = appId.Value;

            var method     = _registryService.GetProvidedMethod(methodReference);
            var launchMode = GetLaunchMode(method);

            Task <ResolvedConnection> resolveTask;

            lock (_resolveConnectionSync)
            {
                if (launchMode != LaunchMode.MultiInstance)
                {
                    var onlineConnections = _appLifecycleManager
                                            .GetOnlineConnections()
                                            .Where(x => x.Info.ApplicationId.Equals(appIdValue) &&
                                                   !x.Id.Equals(source.Id)).ToArray();

                    if (_contextLinkageManager.IsContextShouldBeConsidered(contextLinkageOptions, source))
                    {
                        onlineConnections = _contextLinkageManager
                                            .GetAppsInContexts(contextLinkageOptions, source, true)
                                            .Join(onlineConnections, x => x.ConnectionId.Value, y => y.Id, (x, y) => y)
                                            .ToArray();
                    }

                    if (onlineConnections.Any())
                    {
                        return(onlineConnections.First());
                    }
                }

                if (launchMode == LaunchMode.None || !_appLifecycleManager.CanBeLaunched(appIdValue))
                {
                    throw new InvalidOperationException(
                              $"The requested app {appIdValue} is not online and cannot be launched");
                }

                var resolveMode = ConvertToResolveMode(launchMode);

                resolveTask = _appLifecycleManager.LaunchAndConnectAsync(appIdValue, resolveMode, source.Info);
            }
            var resolvedConnection = await resolveTask.ConfigureAwait(false);

            return(resolvedConnection.AppConnection);
        }
예제 #3
0
        public async Task HandleAsync(
            IServiceDiscoveryRequest request,
            IAppConnection sourceConnection,
            ITransportChannel sourceChannel)
        {
            IReadOnlyCollection <(IConsumedMethod Consumed, IProvidedMethod Provided)> methodMatches;

            if (request.ConsumedService.HasValue)
            {
                methodMatches = _registryService.GetMethodMatches(
                    sourceConnection.Info.ApplicationId,
                    request.ConsumedService.Value);
            }
            else
            {
                methodMatches = _registryService.GetMethodMatches(sourceConnection.Info.ApplicationId);
            }
            IEnumerable <IGrouping <(IConsumedService ConsumedService, IProvidedService ProvidedService, Maybe <UniqueId> ConnectionId, Maybe <UniqueId> ApplicationInstanceId), IProvidedMethod> > groupedMethods;

            var online = request.DiscoveryMode == DiscoveryMode.Online;

            if (_contextLinkageManager.IsContextShouldBeConsidered(request.ContextLinkageOptions, sourceConnection))
            {
                groupedMethods = _contextLinkageManager.GetAppsInContexts(request.ContextLinkageOptions, sourceConnection, online)
                                 .Join(methodMatches, x => x.AppId, y => y.Provided.ProvidedService.Service.Id,
                                       (x, y) => (y.Consumed, y.Provided, x.AppInstanceId, x.ConnectionId))
                                 .GroupBy(x => (x.Consumed.ConsumedService, x.Provided.ProvidedService, x.ConnectionId, new Maybe <UniqueId>(x.AppInstanceId)), x => x.Provided);
            }
            else
            {
                if (online)
                {
                    var onlineConnections = _appLifecycleManager.GetOnlineConnections();
                    groupedMethods = methodMatches
                                     .Join(onlineConnections, x => x.Provided.ProvidedService.Application.Id,
                                           y => y.Info.ApplicationId,
                                           (x, y) => (Match: x, ConnectionId: y.Id, y.Info.ApplicationInstanceId))
                                     .GroupBy(
                        x => (
                            x.Match.Consumed.ConsumedService,
                            x.Match.Provided.ProvidedService,
                            new Maybe <UniqueId>(x.ConnectionId),
                            new Maybe <UniqueId>(x.ApplicationInstanceId)),
                        x => x.Match.Provided);
                }
                else
                {
                    var providerApps = methodMatches.Select(x => x.Provided.ProvidedService.Application.Id).Distinct()
                                       .ToArray();
                    var availableProviderApps = FilterAvailableApps(providerApps);
                    groupedMethods = methodMatches
                                     .Join(
                        availableProviderApps,
                        x => x.Provided.ProvidedService.Application.Id,
                        y => y,
                        (x, y) => x)
                                     .GroupBy(
                        x => (
                            x.Consumed.ConsumedService,
                            x.Provided.ProvidedService,
                            ConnectionId: Maybe <UniqueId> .Nothing,
                            ApplicationInstanceId: Maybe <UniqueId> .Nothing),
                        x => x.Provided);
                }
            }

            var discoveredServices =
                from s in groupedMethods
                let consumedService = s.Key.ConsumedService
                                      let providedService = s.Key.ProvidedService
                                                            let connectionId = s.Key.ConnectionId
                                                                               let applicationInstanceId = s.Key.ApplicationInstanceId
                                                                                                           select _protocol.MessageFactory.CreateDiscoveredService(
                    _protocol.MessageFactory.CreateConsumedServiceReference(
                        consumedService.Service.Id,
                        consumedService.Alias),
                    _protocol.MessageFactory.CreateProvidedServiceReference(
                        providedService.Service.Id,
                        providedService.Alias,
                        providedService.Application.Id,
                        connectionId,
                        applicationInstanceId),
                    s.Key.ProvidedService.Title,
                    s.Select(m =>
                             _protocol.MessageFactory.CreateDiscoveredServiceMethod(
                                 m.Method.Name,
                                 m.Title,
                                 m.Method.InputMessage.Id,
                                 m.Method.OutputMessage.Id,
                                 Convert(m.Method.Type),
                                 m.Options.Select(o => _protocol.MessageFactory.CreateOption(o.Id, o.Value)).ToList()))
                    .ToList());

            using (var response = _protocol.MessageFactory.CreateServiceDiscoveryResponse(discoveredServices.ToList()))
            {
                Log.Info("Completed service discovery request {{{0}}} from {{{1}}}: {2}", request, sourceConnection, response);
                var serializedResponse = _protocol.Serializer.Serialize(response);
                try
                {
                    await sourceChannel.Out
                    .WriteAsync(new TransportMessageFrame(serializedResponse))
                    .ConfigureAwait(false);
                }
                catch
                {
                    serializedResponse.Dispose();
                    throw;
                }
            }
        }