Exemple #1
0
 public bool TryGetOnlineConnection(UniqueId id, out IAppConnection connection)
 {
     lock (_connections)
     {
         return(_connections.TryGetValue(id, out connection));
     }
 }
Exemple #2
0
 public AppConnectionProcessor(IAppConnection connection, IClientRequestHandler clientRequestHandler)
 {
     _connection           = connection;
     Id                    = _connection.Id;
     _log                  = LogManager.GetLogger <AppConnectionProcessor>(Id.ToString());
     _clientRequestHandler = clientRequestHandler;
 }
        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);
        }
 public AppConnectionProcessor(IAppConnection connection, IClientRequestHandler clientRequestHandler)
 {
     _connection           = connection;
     Id                    = _connection.Id;
     _log                  = LogManager.GetLogger <AppConnectionProcessor>(Id.ToString());
     _clientRequestHandler = clientRequestHandler;
     Completion            = TaskRunner.RunInBackground(ProcessAsync);
 }
        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 async Task HandleAsync(
            IMethodDiscoveryRequest request,
            IAppConnection sourceConnection,
            ITransportChannel sourceChannel)
        {
            Log.Info("Handling method discovery request {{{0}}} from {{{1}}}", request, sourceConnection);
            var appId = sourceConnection.Info.ApplicationId;
            IEnumerable <IProvidedMethod> matchingProvidedMethods =
                request.ConsumedMethod.HasValue
                    ? _registryService.GetMatchingProvidedMethods(appId, request.ConsumedMethod.Value)
                    : _registryService.GetMatchingProvidedMethods(appId);

            if (request.InputMessageId.HasValue)
            {
                matchingProvidedMethods = matchingProvidedMethods
                                          .Where(x => string.Equals(x.Method.InputMessage.Id, request.InputMessageId.Value));
            }
            if (request.OutputMessageId.HasValue)
            {
                matchingProvidedMethods = matchingProvidedMethods
                                          .Where(x => string.Equals(x.Method.OutputMessage.Id, request.OutputMessageId.Value));
            }
            IEnumerable <IDiscoveredMethod> discoveredMethods;

            if (request.DiscoveryMode == DiscoveryMode.Online)
            {
                var onlineConnections = _connectionTracker.GetOnlineConnections();
                discoveredMethods = matchingProvidedMethods
                                    .Join(
                    onlineConnections,
                    x => x.ProvidedService.Application.Id,
                    y => y.Info.ApplicationId,
                    (method, connection) => (method, connection))
                                    .Select(pm => Convert(pm.method, pm.connection.Id));
            }
            else
            {
                discoveredMethods = matchingProvidedMethods
                                    .Select(pm => Convert(pm, Maybe <UniqueId> .Nothing));
            }
            using (var response = _protocol.MessageFactory.CreateMethodDiscoveryResponse(discoveredMethods.ToList()))
            {
                Log.Info("Completed method 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;
                }
            }
        }
Exemple #7
0
        private ValueTask <IAppConnection> ResolveTargetConnectionAsync(
            IConsumedMethodReference method,
            IAppConnection source)
        {
            var targetMethods = _registryService.GetMatchingProvidedMethods(source.Info.ApplicationId, method);
            var targetApps    = targetMethods.Select(x => x.ProvidedService.Application.Id).ToList();

            return(_appLifecycleManager.GetOrSpawnConnectionAsync(targetApps));
        }
Exemple #8
0
 private ValueTask <IAppConnection> ResolveTargetConnectionAsync(
     IProvidedMethodReference method,
     IAppConnection source)
 {
     if (method.ProvidedService.ConnectionId.HasValue)
     {
         var connectionId = method.ProvidedService.ConnectionId.Value;
         if (!_appLifecycleManager.TryGetOnlineConnection(connectionId, out var connection))
         {
             throw new InvalidOperationException($"The requested connection {connectionId} is not online");
         }
         return(new ValueTask <IAppConnection>(connection));
     }
     return(_appLifecycleManager.GetOrSpawnConnectionAsync(new[] { method.ProvidedService.ApplicationId }));
 }
Exemple #9
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");
        }
Exemple #10
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 async Task HandleAsync(IInvocationStart request, IAppConnection sourceConnection, ITransportChannel sourceChannel)
        {
            IAppConnection    targetConnection = null;
            ITransportChannel targetChannel    = null;

            try
            {
                Log.Info("Handling invocation {0} from {{{1}}}: {{{2}}}", sourceChannel.Id, sourceConnection, request);
                targetConnection = await request.Target.Handle(_resolveTargetConnectionHandler, sourceConnection).ConfigureAwait(false);

                targetChannel = await targetConnection.CreateChannelAsync().ConfigureAwait(false);

                Log.Debug("Created channel {0} for invocation {1} from {{{2}}} to {{{3}}}: {{{4}}}", targetChannel.Id, sourceChannel.Id, sourceConnection, targetConnection, request);
                using (var invocationStarting = _protocolMessageFactory.CreateInvocationStarting())
                {
                    var serialized = _protocolSerializer.Serialize(invocationStarting);
                    try
                    {
                        await sourceChannel.Out.WriteAsync(new TransportMessageFrame(serialized)).ConfigureAwait(false);

                        Log.Trace("Sent starting event for invocation {0}", sourceChannel.Id);
                    }
                    catch
                    {
                        serialized.Dispose();
                        throw;
                    }
                }
                using (var invocationRequested = request.Target.Handle(_createRequestHandler, sourceConnection))
                {
                    var serialized = _protocolSerializer.Serialize(invocationRequested);
                    try
                    {
                        await targetChannel.Out.WriteAsync(new TransportMessageFrame(serialized)).ConfigureAwait(false);

                        Log.Trace("Sent requested event for invocation {0} to {1}", targetChannel.Id, targetConnection);
                    }
                    catch
                    {
                        serialized.Dispose();
                        throw;
                    }
                }
                var propagateTask1 = TaskRunner.RunInBackground(() => PropagateAsync(sourceChannel.In, targetChannel.Out));
                var propagateTask2 = TaskRunner.RunInBackground(() => PropagateAsync(targetChannel.In, sourceChannel.Out));
                await Task.WhenAll(propagateTask1, propagateTask2).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                sourceChannel.Out.TryTerminate(ex);
                targetChannel?.Out.TryTerminate(ex);
                throw;
            }
            finally
            {
                try
                {
                    await Task
                    .WhenAll(
                        targetChannel?.In.ConsumeAsync((Action <TransportMessageFrame>)DisposeFrame).IgnoreExceptions() ?? TaskConstants.Completed,
                        sourceChannel.In.ConsumeAsync((Action <TransportMessageFrame>)DisposeFrame).IgnoreExceptions(),
                        targetChannel?.Completion ?? TaskConstants.Completed,
                        sourceChannel.Completion)
                    .ConfigureAwait(false);

                    Log.Info("Completed invocation {0} from {{{1}}} to {{{2}}}: {{{3}}}", sourceChannel.Id, sourceConnection, targetConnection, request);
                }
                catch (OperationCanceledException)
                {
                    Log.Info("Canceled invocation {0} from {{{1}}} to {{{2}}}: {{{3}}}", sourceChannel.Id, sourceConnection, targetConnection, request);
                    throw;
                }
                catch (Exception ex)
                {
                    Log.Warn("Failed invocation {0} from {{{1}}} to {{{2}}}: {{{3}}}. Error: {4}", sourceChannel.Id, sourceConnection, targetConnection, request, ex.FormatTypeAndMessage());
                    throw;
                }
            }
        }
 public bool IsContextShouldBeConsidered(IContextLinkageOptions contextLinkageOptions, IAppConnection sourceConnection)
 {
     return(contextLinkageOptions != null &&
            contextLinkageOptions.Mode != ContextLinkageDiscoveryMode.None &&
            GetApplicationContexts(contextLinkageOptions, sourceConnection).Any());
 }
Exemple #13
0
 public ResolvedConnection(IAppConnection appConnection, bool isNewInstance)
 {
     AppConnection = appConnection;
     IsNewInstance = isNewInstance;
 }
Exemple #14
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;
                }
            }
        }
Exemple #15
0
        public async Task HandleAsync(
            IMethodDiscoveryRequest request,
            IAppConnection sourceConnection,
            ITransportChannel sourceChannel)
        {
            Log.Info("Handling method discovery request {{{0}}} from {{{1}}}", request, sourceConnection);
            var appId = sourceConnection.Info.ApplicationId;
            IEnumerable <IProvidedMethod> matchingProvidedMethods =
                request.ConsumedMethod.HasValue
                    ? _registryService.GetMatchingProvidedMethods(appId, request.ConsumedMethod.Value)
                    : _registryService.GetMatchingProvidedMethods(appId);

            if (request.InputMessageId.HasValue)
            {
                matchingProvidedMethods = matchingProvidedMethods
                                          .Where(x => string.Equals(x.Method.InputMessage.Id, request.InputMessageId.Value));
            }
            if (request.OutputMessageId.HasValue)
            {
                matchingProvidedMethods = matchingProvidedMethods
                                          .Where(x => string.Equals(x.Method.OutputMessage.Id, request.OutputMessageId.Value));
            }
            IEnumerable <IDiscoveredMethod> discoveredMethods;

            bool online = request.DiscoveryMode == DiscoveryMode.Online;

            if (_contextLinkageManager.IsContextShouldBeConsidered(request.ContextLinkageOptions, sourceConnection))
            {
                discoveredMethods = _contextLinkageManager.GetAppsInContexts(request.ContextLinkageOptions, sourceConnection, online)
                                    .Join(matchingProvidedMethods, x => x.AppId, y => y.ProvidedService.Application.Id,
                                          (connection, method) => (method, connection))
                                    .Select(pm => Convert(pm.method, pm.connection.ConnectionId,
                                                          new Maybe <UniqueId>(pm.connection.AppInstanceId)));
            }
            else
            {
                if (online)
                {
                    var onlineConnections = _appLifecycleManager.GetOnlineConnections();
                    discoveredMethods = matchingProvidedMethods
                                        .Join(
                        onlineConnections,
                        x => x.ProvidedService.Application.Id,
                        y => y.Info.ApplicationId,
                        (method, connection) => (method, connection))
                                        .Select(pm => Convert(pm.method, pm.connection.Id, pm.connection.Info.ApplicationInstanceId));
                }
                else
                {
                    var providedMethods       = matchingProvidedMethods.ToArray();
                    var providerApps          = providedMethods.Select(x => x.ProvidedService.Application.Id).Distinct().ToArray();
                    var availableProviderApps = FilterAvailableApps(providerApps);
                    discoveredMethods = providedMethods
                                        .Join(availableProviderApps, x => x.ProvidedService.Application.Id, y => y, (x, y) => x)
                                        .Select(pm => Convert(pm, Maybe <UniqueId> .Nothing, Maybe <UniqueId> .Nothing));
                }
            }

            using (var response = _protocol.MessageFactory.CreateMethodDiscoveryResponse(discoveredMethods.ToList()))
            {
                Log.Info("Completed method 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;
                }
            }
        }
 private IInvocationStartRequested CreateInvocationTarget(IConsumedMethodReference reference, IAppConnection sourceConnection)
 {
     return(_protocolMessageFactory.CreateInvocationStartRequested(
                reference.ConsumedService.ServiceId,
                reference.MethodId,
                reference.ConsumedService.ServiceAlias,
                sourceConnection.Info.ApplicationId,
                sourceConnection.Info.ApplicationInstanceId,
                sourceConnection.Id));
 }
        public async Task HandleAsync(IInvocationStart request, IAppConnection sourceConnection, ITransportChannel sourceChannel)
        {
            IAppConnection       targetConnection = null;
            ITransportChannel    targetChannel    = null;
            InvocationDescriptor callDescriptor   = null;
            var startMs = _stopwatch.ElapsedMilliseconds;

            try
            {
                Log.Info("Handling invocation {0} from {{{1}}}: {{{2}}}", sourceChannel.Id, sourceConnection, request);
                targetConnection = await request.Target.Handle(_resolveTargetConnectionHandler, sourceConnection).ConfigureAwait(false);

                targetChannel = await targetConnection.CreateChannelAsync().ConfigureAwait(false);

                Log.Debug("Created channel {0} for invocation {1} from {{{2}}} to {{{3}}}: {{{4}}}", targetChannel.Id, sourceChannel.Id, sourceConnection, targetConnection, request);
                using (var invocationStarting = _protocolMessageFactory.CreateInvocationStarting())
                {
                    var serialized = _protocolSerializer.Serialize(invocationStarting);
                    try
                    {
                        await sourceChannel.Out.WriteAsync(new TransportMessageFrame(serialized)).ConfigureAwait(false);

                        Log.Trace("Sent starting event for invocation {0}", sourceChannel.Id);
                    }
                    catch
                    {
                        serialized.Dispose();
                        throw;
                    }
                }
                using (var invocationRequested = request.Target.Handle(_createRequestHandler, sourceConnection))
                {
                    startMs        = _stopwatch.ElapsedMilliseconds;
                    callDescriptor = new InvocationDescriptor(
                        sourceConnection.Info,
                        targetConnection.Info,
                        invocationRequested.ServiceId,
                        invocationRequested.ServiceAlias.GetValueOrDefault(),
                        invocationRequested.MethodId);
                    _appLifecycleManager.OnInvocationStarted(new InvocationStartedEventDescriptor(callDescriptor));
                    var serialized = _protocolSerializer.Serialize(invocationRequested);
                    try
                    {
                        await targetChannel.Out.WriteAsync(new TransportMessageFrame(serialized)).ConfigureAwait(false);

                        Log.Trace("Sent requested event for invocation {0} to {1}", targetChannel.Id, targetConnection);
                    }
                    catch
                    {
                        serialized.Dispose();
                        throw;
                    }
                }
                var propagateTask1 = TaskRunner.RunInBackground(() => PropagateAsync(sourceChannel.In, targetChannel.Out));
                var propagateTask2 = TaskRunner.RunInBackground(() => PropagateAsync(targetChannel.In, sourceChannel.Out));
                await Task.WhenAll(propagateTask1, propagateTask2).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                sourceChannel.Out.TryTerminate(ex);
                targetChannel?.Out.TryTerminate(ex);
                throw;
            }
            finally
            {
                try
                {
                    await Task
                    .WhenAll(
                        targetChannel?.In.ConsumeAsync((Action <TransportMessageFrame>)DisposeFrame).IgnoreExceptions() ?? TaskConstants.Completed,
                        sourceChannel.In.ConsumeAsync((Action <TransportMessageFrame>)DisposeFrame).IgnoreExceptions(),
                        targetChannel?.Completion ?? TaskConstants.Completed,
                        sourceChannel.Completion)
                    .ConfigureAwait(false);

                    Log.Info("Completed invocation {0} from {{{1}}} to {{{2}}}: {{{3}}}", sourceChannel.Id, sourceConnection, targetConnection, request);
                    OnActionFinished(callDescriptor, InvocationResult.Succeeded, startMs);
                }
                catch (OperationCanceledException)
                {
                    Log.Info("Canceled invocation {0} from {{{1}}} to {{{2}}}: {{{3}}}", sourceChannel.Id, sourceConnection, targetConnection, request);
                    OnActionFinished(callDescriptor, InvocationResult.Canceled, startMs);
                    throw;
                }
                catch (Exception ex)
                {
                    Log.Warn("Failed invocation {0} from {{{1}}} to {{{2}}}: {{{3}}}. Error: {4}", sourceChannel.Id, sourceConnection, targetConnection, request, ex.FormatTypeAndMessage());
                    OnActionFinished(callDescriptor, InvocationResult.Failed, startMs);
                    throw;
                }
            }
        }
 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 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), IProvidedMethod> > groupedMethods;

            if (request.DiscoveryMode == DiscoveryMode.Offline)
            {
                groupedMethods = methodMatches
                                 .GroupBy(
                    x => (
                        x.Consumed.ConsumedService,
                        x.Provided.ProvidedService,
                        ConnectionId: Maybe <UniqueId> .Nothing),
                    x => x.Provided);
            }
            else
            {
                var onlineConnections = _connectionTracker.GetOnlineConnections();
                groupedMethods = methodMatches
                                 .Join(onlineConnections, x => x.Provided.ProvidedService.Application.Id, y => y.Info.ApplicationId, (x, y) => (Match: x, ConnectionId: y.Id))
                                 .GroupBy(
                    x => (
                        x.Match.Consumed.ConsumedService,
                        x.Match.Provided.ProvidedService,
                        new Maybe <UniqueId>(x.ConnectionId)),
                    x => x.Match.Provided);
            }
            var discoveredServices =
                from s in groupedMethods
                let consumedService = s.Key.ConsumedService
                                      let providedService = s.Key.ProvidedService
                                                            let connectionId = s.Key.ConnectionId
                                                                               select _protocol.MessageFactory.CreateDiscoveredService(
                    _protocol.MessageFactory.CreateConsumedServiceReference(
                        consumedService.Service.Id,
                        consumedService.Alias),
                    _protocol.MessageFactory.CreateProvidedServiceReference(
                        providedService.Service.Id,
                        providedService.Alias,
                        providedService.Application.Id,
                        connectionId),
                    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))).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;
                }
            }
        }
        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]);
            }
        }