protected override void Cleanup()
 {
     ConsumedService.GetValueOrDefault()?.Dispose();
     ConsumedService       = default;
     DiscoveryMode         = default;
     ContextLinkageOptions = default;
 }
        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);
        }
        public IServiceDiscoveryRequest CreateServiceDiscoveryRequest(
            Maybe <IConsumedServiceReference> consumedService,
            DiscoveryMode mode,
            IContextLinkageOptions contextLinkageOptions)
        {
            var obj = ServiceDiscoveryRequest.Rent();

            obj.ConsumedService       = consumedService;
            obj.DiscoveryMode         = mode;
            obj.ContextLinkageOptions = contextLinkageOptions;
            return(obj);
        }
        private IReadOnlyCollection <string> GetApplicationContexts(IContextLinkageOptions contextLinkageOptions, IAppConnection sourceConnection)
        {
            switch (contextLinkageOptions.Mode)
            {
            case ContextLinkageDiscoveryMode.CurrentContext:
                return(_contextsSet.GetContextsOf(sourceConnection.Info.ApplicationInstanceId)
                       .Select(context => context.Id).ToArray());

            case ContextLinkageDiscoveryMode.SpecificContext when contextLinkageOptions.SpecificContext.HasValue:
                return(new[] { contextLinkageOptions.SpecificContext.Value });

            default:
                return(new string[0]);
            }
        }
        public IMethodDiscoveryRequest CreateMethodDiscoveryRequest(
            Maybe <string> inputMessageId,
            Maybe <string> outputMessageId,
            Maybe <IConsumedMethodReference> method,
            DiscoveryMode discoveryMode,
            IContextLinkageOptions contextLinkageOptions)
        {
            var obj = MethodDiscoveryRequest.Rent();

            obj.InputMessageId        = inputMessageId;
            obj.OutputMessageId       = outputMessageId;
            obj.ConsumedMethod        = method;
            obj.DiscoveryMode         = discoveryMode;
            obj.ContextLinkageOptions = contextLinkageOptions;
            return(obj);
        }
        private ContextLinkageOptions ConvertToProto(IContextLinkageOptions obj)
        {
            var proto = ContextLinkageOptions.Rent();

            if (obj != null)
            {
                switch (obj.Mode)
                {
                case ContextLinkageDiscoveryMode.None:
                    proto.ClearMode();
                    break;

                case ContextLinkageDiscoveryMode.SpecificContext:
                    proto.SpecificContextId = obj.SpecificContext.Value;
                    break;

                case ContextLinkageDiscoveryMode.CurrentContext:
                    proto.CurrentContext = Empty.Instance;
                    break;
                }
            }
            return(proto);
        }
        public IInvocationStart CreateInvocationStartRequest(IInvocationTarget target, IContextLinkageOptions contextLinkageOptions)
        {
            var obj = InvocationStart.Rent();

            obj.Target = target;
            obj.ContextLinkageOptions = contextLinkageOptions ?? CreateContextLinkageOptions(ContextLinkageDiscoveryMode.None);
            return(obj);
        }
        private async ValueTask <IAppConnection> ResolveTargetConnectionAsync(
            IConsumedMethodReference method,
            IAppConnection source,
            IContextLinkageOptions contextLinkageOptions)
        {
            Log.Debug("Resolving target connection for call {{{0}}} from {{{1}}}", method, source);
            string      appId;
            ResolveMode resolveMode;
            var         targetMethods         = _registryService.GetMatchingProvidedMethods(source.Info.ApplicationId, method);
            var         onlineProvidedMethods =
                _appLifecycleManager
                .GetOnlineConnections()
                .Where(x => !x.Id.Equals(source.Id))
                .Join(
                    targetMethods.Where(x => GetLaunchMode(x) != LaunchMode.MultiInstance),
                    x => x.Info.ApplicationId, y => y.ProvidedService.Application.Id,
                    (x, y) => (Method: y, AppConnection: x))
                .ToArray();

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

            if (onlineProvidedMethods.Any())
            {
                var connection = onlineProvidedMethods.First().AppConnection;
                Log.Debug("Resolved target connection for call {{{0}}} from {{{1}}} to online connection: {{{2}}}", method, source, connection);
                return(connection);
            }

            lock (_resolveConnectionSync)
            {
                Log.Debug("Resolving target connection for call {{{0}}} from {{{1}}} to offline connection", method, source);
                var appIds = _appLifecycleManager.FilterCanBeLaunched(
                    targetMethods.Select(x => x.ProvidedService.Application.Id).Distinct());
                targetMethods = targetMethods.Join(appIds, x => x.ProvidedService.Application.Id, y => y, (x, y) => x).ToArray();

                var singleInstanceMethods = targetMethods.Where(x => GetLaunchMode(x) == LaunchMode.SingleInstance).ToArray();

                var onlineConnections = new HashSet <string>(_appLifecycleManager.GetOnlineConnections().Select(connection => connection.Info.ApplicationId));

                var candidate = singleInstanceMethods.FirstOrDefault(x => !x.ProvidedService.Application.Id.Equals(source.Info.ApplicationId) && !onlineConnections.Contains(x.ProvidedService.Application.Id));
                resolveMode = ResolveMode.SingleInstance;

                if (candidate == null)
                {
                    candidate   = singleInstanceMethods.FirstOrDefault(x => !onlineConnections.Contains(x.ProvidedService.Application.Id));
                    resolveMode = ResolveMode.SingleInstance;
                }

                if (candidate == null)
                {
                    candidate   = targetMethods.FirstOrDefault(x => GetLaunchMode(x) == LaunchMode.MultiInstance);
                    resolveMode = ResolveMode.MultiInstance;
                }

                if (candidate == null)
                {
                    candidate   = targetMethods.FirstOrDefault(x => GetLaunchMode(x) != LaunchMode.None);
                    resolveMode = ResolveMode.MultiInstance;
                }

                if (candidate == null)
                {
                    throw new InvalidOperationException($"Cannot resolve target for invocation {{{method}}} from {{{source}}}");
                }
                Log.Debug("Resolved target connection for call {{{0}}} from {{{1}}} to provided method {{{2}}}", method, source, candidate);
                appId = candidate.ProvidedService.Application.Id;
            }
            var resolvedConnection = await _appLifecycleManager
                                     .LaunchAndConnectAsync(appId, resolveMode, source.Info)
                                     .ConfigureAwait(false);

            return(resolvedConnection.AppConnection);
        }
示例#9
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);
        }
 public IReadOnlyCollection <(UniqueId AppInstanceId, string AppId, Maybe <UniqueId> ConnectionId)> GetAppsInContexts(IContextLinkageOptions contextLinkageOptions, IAppConnection sourceConnection, bool online)
 {
     return(GetApplicationContexts(contextLinkageOptions, sourceConnection)
            .Select(id => _contextsSet.GetContext(id))
            .Where(context => context != null)
            .SelectMany(context => context.GetAppsInContext(online))
            .Distinct().ToArray());
 }
 public bool IsContextShouldBeConsidered(IContextLinkageOptions contextLinkageOptions, IAppConnection sourceConnection)
 {
     return(contextLinkageOptions != null &&
            contextLinkageOptions.Mode != ContextLinkageDiscoveryMode.None &&
            GetApplicationContexts(contextLinkageOptions, sourceConnection).Any());
 }