private async ValueTask <IAppConnection> ResolveTargetConnectionAsync(
            IConsumedMethodReference method,
            IAppConnection source)
        {
            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 (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 candidate = singleInstanceMethods.FirstOrDefault(x => !x.ProvidedService.Application.Id.Equals(source.Info.ApplicationId));
                resolveMode = ResolveMode.SingleInstance;
                if (candidate == null)
                {
                    candidate   = singleInstanceMethods.FirstOrDefault();
                    resolveMode = ResolveMode.SingleInstance;
                }
                if (candidate == null)
                {
                    candidate   = targetMethods.FirstOrDefault(x => GetLaunchMode(x) == LaunchMode.MultiInstance);
                    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
                                     .ResolveConnectionAsync(appId, resolveMode, source.Info)
                                     .ConfigureAwait(false);

            return(resolvedConnection.AppConnection);
        }
Example #2
0
        private IEnumerable <string> FilterAvailableApps(string[] providerApps)
        {
            var launchableProviderApps = _appLifecycleManager.FilterCanBeLaunched(providerApps);
            var onlineApps             = _appLifecycleManager.GetOnlineConnections().Select(x => x.Info.ApplicationId).Distinct();
            var onlineProviderApps     = providerApps.Intersect(onlineApps);
            var availableProviderApps  = launchableProviderApps.Union(onlineProviderApps);

            return(availableProviderApps);
        }
Example #3
0
        private async ValueTask <IAppConnection> ResolveTargetConnectionAsync(
            IConsumedMethodReference method,
            IAppConnection source,
            ITransportChannel sourceChannel,
            IContextLinkageOptions contextLinkageOptions)
        {
            Log.Debug("Resolving target connection for call {{{0}}} from {{{1}}} for {2} invocation", method, source, sourceChannel.Id);
            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}}} for {3} invocation", method, source, connection, sourceChannel.Id);
                return(connection);
            }

            lock (_resolveConnectionSync)
            {
                Log.Debug("Resolving target connection for call {{{0}}} (invocation {2}) from {{{1}}} to offline connection", method, source, sourceChannel.Id);
                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}}} for {sourceChannel.Id} invocation");
                }
                Log.Debug("Resolved target connection for call {{{0}}} from {{{1}}} to provided method {{{2}}} for {3} invocation", method, source, candidate, sourceChannel.Id);
                appId = candidate.ProvidedService.Application.Id;
            }

            var launchAppTask = _appLifecycleManager.LaunchAndConnectAsync(appId, resolveMode, source.Info);

            var completedTask = await Task.WhenAny(launchAppTask, source.IncomingChannels.Completion).ConfigureAwait(false);

            if (completedTask == launchAppTask)
            {
                var resolvedConnection = await launchAppTask.ConfigureAwait(false);

                return(resolvedConnection.AppConnection);
            }

            throw new TaskCanceledException($"Launch of application {appId} canceled because source connection {source.Info} is completed");
        }