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); }
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( 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; } } }