diff --git a/examples/fdc3-chart-and-grid/js-chart/chart.js b/examples/fdc3-chart-and-grid/js-chart/chart.js index 3ec2672dd..4a086af95 100644 --- a/examples/fdc3-chart-and-grid/js-chart/chart.js +++ b/examples/fdc3-chart-and-grid/js-chart/chart.js @@ -61,7 +61,7 @@ async function requestData() { currentChannel = await window.fdc3.getCurrentChannel(); if(!currentChannel) { - await window.fdc3.joinUserChannel("default"); + await window.fdc3.joinUserChannel("fdc3.channel.1"); } contextListener = await window.fdc3.addContextListener(ContextTypes.Instrument, (context, metadata) => { diff --git a/examples/fdc3-chart-and-grid/js-datagrid/src/app/main-view/services/mock-data.service.ts b/examples/fdc3-chart-and-grid/js-datagrid/src/app/main-view/services/mock-data.service.ts index 4fa628323..8c31996ae 100644 --- a/examples/fdc3-chart-and-grid/js-datagrid/src/app/main-view/services/mock-data.service.ts +++ b/examples/fdc3-chart-and-grid/js-datagrid/src/app/main-view/services/mock-data.service.ts @@ -19,26 +19,26 @@ export class MockDataService{ private connecting: Promise; constructor(){ - this.market = new Market(); - this.connecting = new Promise(async(resolve, reject) => { - try{ - resolve(await this.checkFdc3Connection()); - } catch(err) { - reject(err); - }; - }); + this.market = new Market(); + this.connecting = new Promise(async(resolve, reject) => { + try{ + resolve(await this.checkFdc3Connection()); + } catch(err) { + reject(err); + }; + }); - interval(1000).subscribe(() => { - this.marketData = this.market.generateNewMarketNumbers(); - this.subject.next(this.marketData); - }); + interval(1000).subscribe(() => { + this.marketData = this.market.generateNewMarketNumbers(); + this.subject.next(this.marketData); + }); } private async checkFdc3Connection(): Promise { if(!this.connected) { this.currentChannel = await window.fdc3.getCurrentChannel(); if (!this.currentChannel) { - await window.fdc3.joinUserChannel("default"); + await window.fdc3.joinUserChannel("fdc3.channel.1"); } this.connected = true; } diff --git a/examples/fdc3-pricing-and-chat/js-chat/chat.js b/examples/fdc3-pricing-and-chat/js-chat/chat.js index 379dfad17..a6331b350 100644 --- a/examples/fdc3-pricing-and-chat/js-chat/chat.js +++ b/examples/fdc3-pricing-and-chat/js-chat/chat.js @@ -94,5 +94,5 @@ window.app = function () { window.addEventListener('load', async function () { intentListener = await window.fdc3.addIntentListener("StartChat", window.app.handleChatIntent); - await window.fdc3.joinUserChannel("default"); + await window.fdc3.joinUserChannel("fdc3.channel.1"); }); \ No newline at end of file diff --git a/examples/fdc3-pricing-and-chat/js-pricing/pricing.js b/examples/fdc3-pricing-and-chat/js-pricing/pricing.js index 99c9b0c41..ea2f40d38 100644 --- a/examples/fdc3-pricing-and-chat/js-pricing/pricing.js +++ b/examples/fdc3-pricing-and-chat/js-pricing/pricing.js @@ -16,7 +16,7 @@ import "bootstrap/dist/css/bootstrap.css"; window.addEventListener('load', async function () { const pricingForm = document.querySelector("#pricing"); - await this.window.fdc3.joinUserChannel("default"); + await this.window.fdc3.joinUserChannel("fdc3.channel.1"); pricingForm.addEventListener('submit', app.submitPrice); }); diff --git a/examples/fdc3-trade-simulator/js-order-book/src/app/components/market-watch/market-watch.component.ts b/examples/fdc3-trade-simulator/js-order-book/src/app/components/market-watch/market-watch.component.ts index ad3462aa9..9e57512e6 100644 --- a/examples/fdc3-trade-simulator/js-order-book/src/app/components/market-watch/market-watch.component.ts +++ b/examples/fdc3-trade-simulator/js-order-book/src/app/components/market-watch/market-watch.component.ts @@ -275,7 +275,6 @@ export class MarketWatchComponent implements OnInit, OnDestroy{ let price: number = 0; let size = data.quantity; for (let element of ELEMENT_DATA) { - console.log("current size:", size); if (size == 0) { break; } @@ -303,7 +302,6 @@ export class MarketWatchComponent implements OnInit, OnDestroy{ } for (let innerElement of element.Children) { - console.log("current size:", size); if (innerElement.Symbol != data.symbol) { continue; } @@ -318,7 +316,6 @@ export class MarketWatchComponent implements OnInit, OnDestroy{ price = price + innerElement.AskSize * (innerElement.AskPrice == undefined ? 0 : innerElement.AskPrice); size = size - innerElement.AskSize; innerElement.AskSize = 0; - console.log("current size: hello", size); innerElement.LastTrade = data.timestamp; } } diff --git a/examples/fdc3-trade-simulator/js-trader-app/src/app/components/trade-idea-generator/dialog.html b/examples/fdc3-trade-simulator/js-trader-app/src/app/components/trade-idea-generator/dialog.html index 14b907d70..00dfa1887 100644 --- a/examples/fdc3-trade-simulator/js-trader-app/src/app/components/trade-idea-generator/dialog.html +++ b/examples/fdc3-trade-simulator/js-trader-app/src/app/components/trade-idea-generator/dialog.html @@ -4,7 +4,6 @@

Hi {{data.trader}}

Please confirm your intent to this symbol {{data.symbol}} with quantity: {{data.quantity}}

- - - + + \ No newline at end of file diff --git a/examples/fdc3-trade-simulator/js-trader-app/src/app/components/trade-idea-generator/trade-idea-generator.component.html b/examples/fdc3-trade-simulator/js-trader-app/src/app/components/trade-idea-generator/trade-idea-generator.component.html index 56dfb2a5b..213c209d0 100644 --- a/examples/fdc3-trade-simulator/js-trader-app/src/app/components/trade-idea-generator/trade-idea-generator.component.html +++ b/examples/fdc3-trade-simulator/js-trader-app/src/app/components/trade-idea-generator/trade-idea-generator.component.html @@ -43,9 +43,8 @@

Trading App

- + + \ No newline at end of file diff --git a/examples/fdc3-trade-simulator/js-trader-app/src/app/components/trade-idea-generator/trade-idea-generator.component.ts b/examples/fdc3-trade-simulator/js-trader-app/src/app/components/trade-idea-generator/trade-idea-generator.component.ts index a43b0a271..411f11ca5 100644 --- a/examples/fdc3-trade-simulator/js-trader-app/src/app/components/trade-idea-generator/trade-idea-generator.component.ts +++ b/examples/fdc3-trade-simulator/js-trader-app/src/app/components/trade-idea-generator/trade-idea-generator.component.ts @@ -46,8 +46,8 @@ export class TradeIdeaGeneratorComponent implements OnDestroy { } async ngOnDestroy() { - this.listeners.forEach(async (listener, _) => { - await listener.unsubscribe(); + this.listeners.forEach((listener, _) => { + listener.unsubscribe(); }); this.listeners.clear(); @@ -130,7 +130,7 @@ export class TradeIdeaGeneratorComponent implements OnDestroy { return !this.wrapValue && inputValue >= this.maximumValue; } - public async broadcastTradeIdea() : Promise { + private async broadcastTradeIdea(action: string) : Promise { if (!this.currentValue || this.currentValue <= 0) { this.feedbackSubject.next('Please select at least 1 quantity.'); return; @@ -150,13 +150,11 @@ export class TradeIdeaGeneratorComponent implements OnDestroy { data: {trader: this.trader!, quantity: this.currentValue, symbol: this.symbols.value as string} }); - dialogRef.afterClosed().subscribe(async result => { + dialogRef.afterClosed().subscribe(async (result: boolean) => { if (!result) { return; } - const action = result as string; - const context: Context = { type: "fdc3.trade", data: { @@ -201,6 +199,14 @@ export class TradeIdeaGeneratorComponent implements OnDestroy { } }); } + + public async buySymbol() : Promise { + await this.broadcastTradeIdea("BUY"); + } + + public async sellSymbol() : Promise { + await this.broadcastTradeIdea("SELL"); + } } @Component({ diff --git a/package.json b/package.json index 9f1793197..980144e37 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "examples/js-chart-and-grid-messagerouter/js-*", "examples/fdc3-chart-and-grid/js-*", "examples/fdc3-pricing-and-chat/js-*", - "examples/fdc3-trade-simulator/js-*", + "examples/fdc3-trade-simulator/js-*", "src/messaging/js/*", "src/shell/js/*", "src/fdc3/js/*", diff --git a/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/Channels/Channel.cs b/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/Channels/Channel.cs index a1922e838..732b21192 100644 --- a/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/Channels/Channel.cs +++ b/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/Channels/Channel.cs @@ -50,13 +50,13 @@ public async ValueTask Connect() await MessagingService.ConnectAsync(); + await MessagingService.RegisterServiceAsync(_topics.GetCurrentContext, GetCurrentContext); + var broadcastHandler = new Func(HandleBroadcast); var broadcastSubscription = MessagingService.SubscribeAsync(_topics.Broadcast, broadcastHandler); - await MessagingService.RegisterServiceAsync(_topics.GetCurrentContext, GetCurrentContext); _broadcastSubscription = await broadcastSubscription; - LogConnected(); } diff --git a/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/DependencyInjection/Fdc3DesktopAgentOptions.cs b/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/DependencyInjection/Fdc3DesktopAgentOptions.cs index 1788803be..c148b2a2a 100644 --- a/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/DependencyInjection/Fdc3DesktopAgentOptions.cs +++ b/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/DependencyInjection/Fdc3DesktopAgentOptions.cs @@ -13,6 +13,7 @@ */ using Microsoft.Extensions.Options; +using MorganStanley.ComposeUI.Fdc3.DesktopAgent.Protocol; namespace MorganStanley.ComposeUI.Fdc3.DesktopAgent.DependencyInjection; @@ -28,6 +29,11 @@ public sealed class Fdc3DesktopAgentOptions : IOptions /// public Uri? UserChannelConfigFile { get; set; } + /// + /// Sets the UserChannel set. + /// + public ChannelItem[]? UserChannelConfig { get; set; } + /// /// Indicates a timeout value for getting the IntentResult from the backend in milliseconds. /// When set to any value, it sets the timeout for the getResult() client calls, which should wait either for this timeout or the task which gets the appropriate resolved IntentResolution. diff --git a/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/Fdc3DesktopAgent.cs b/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/Fdc3DesktopAgent.cs index eb1346604..dd1245b87 100644 --- a/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/Fdc3DesktopAgent.cs +++ b/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/Fdc3DesktopAgent.cs @@ -44,6 +44,8 @@ using ImplementationMetadata = MorganStanley.ComposeUI.Fdc3.DesktopAgent.Protocol.ImplementationMetadata; using Constants = MorganStanley.ComposeUI.Fdc3.DesktopAgent.Infrastructure.Internal.Constants; using FileSystem = System.IO.Abstractions.FileSystem; +using System.Reflection; +using System; namespace MorganStanley.ComposeUI.Fdc3.DesktopAgent; @@ -87,128 +89,107 @@ public Fdc3DesktopAgent( _logger = _loggerFactory.CreateLogger() ?? NullLogger.Instance; } - public async ValueTask AddUserChannel(UserChannel userChannel) + public async ValueTask AddUserChannel(Func addUserChannelFactory, string channelId) { - //TODO: Decide if we need to check from the existing userchannel set if the id is contained - //if (_userChannelSet != null && !_userChannelSet.TryGetValue(userChannel.Id, out _)) - //{ - // return; - //} - - if (!_userChannels.TryAdd(userChannel.Id, userChannel)) + ChannelItem? channelItem = null; + if (_userChannelSet != null && !_userChannelSet.TryGetValue(channelId, out channelItem) || channelItem == null) { - if (_logger.IsEnabled(LogLevel.Debug)) - { - _logger.LogDebug($"User channel with id: {userChannel.Id} cannot be added."); - } + return null; + } - return; + //Checking if the endpoint is already registered, because it can cause issues with multiple threads executing this same task to register the appropriate services storing the latest context messages, etc on the Channel objects. + if (_userChannels.TryGetValue(channelId, out var userChannel)) + { + return userChannel; } + userChannel = _userChannels.GetOrAdd(channelId, addUserChannelFactory(channelId)); + try { - await userChannel.Connect(); + await userChannel!.Connect(); + return userChannel; } - catch (MessageRouterException exception) + catch (MessageRouterDuplicateEndpointException exception) { - if (!exception.Message.Contains("Duplicate endpoint")) - { - throw; - } - if (_logger.IsEnabled(LogLevel.Warning)) { - _logger.LogWarning(exception, $"Endpoint is already registered {userChannel.Id}."); + _logger.LogWarning(exception, $"{channelId} is already registed as service endpoint."); } + + return userChannel; } catch (Exception exception) { _logger.LogError(exception, $"Exception thrown while executing {nameof(AddUserChannel)}."); - _userChannels.TryRemove(userChannel.Id, out _); + _userChannels.TryRemove(channelId, out _); throw; } } - public async ValueTask AddPrivateChannel(PrivateChannel privateChannel) + public async ValueTask AddPrivateChannel(Func addPrivateChannelFactory, string privateChannelId) { - if (!_privateChannels.TryAdd(privateChannel.Id, privateChannel)) + //Checking if the endpoint is already registered, because it can cause issues while registering services storing the latest context messages, etc on the Channel objects. + if (_privateChannels.TryGetValue(privateChannelId, out var privateChannel)) { - if (_logger.IsEnabled(LogLevel.Debug)) - { - _logger.LogDebug($"Private channel with id: {privateChannel.Id} cannot be added."); - } - return; } + privateChannel = _privateChannels.GetOrAdd(privateChannelId, addPrivateChannelFactory(privateChannelId)); + try { - await privateChannel.Connect(); + await privateChannel!.Connect(); } - catch (MessageRouterException exception) + catch (MessageRouterDuplicateEndpointException exception) { - if (!exception.Message.Contains("Duplicate endpoint")) - { - throw; - } - if (_logger.IsEnabled(LogLevel.Warning)) { - _logger.LogWarning(exception, $"Endpoint is already registered {privateChannel.Id}."); + _logger.LogWarning(exception, $"{privateChannelId} is already registed as service endpoint."); } } catch (Exception exception) { _logger.LogError(exception, $"Exception thrown while executing {nameof(AddPrivateChannel)}."); - _privateChannels.TryRemove(privateChannel.Id, out _); + _privateChannels.TryRemove(privateChannelId, out _); throw; } } - public async ValueTask AddAppChannel( - AppChannel appChannel, - string instanceId) + public async ValueTask AddAppChannel(Func addAppChannelFactory, CreateAppChannelRequest request) { - if (!_runningModules.TryGetValue(new Guid(instanceId), out _)) + if (!_runningModules.TryGetValue(new Guid(request.InstanceId), out _)) { return CreateAppChannelResponse.Failed(ChannelError.CreationFailed); } - if (!_appChannels.TryAdd(appChannel.Id, appChannel)) + //Checking if the endpoint is already registered, because it can cause issues while registering services storing the latest context messages, etc on the Channel objects. + if (_appChannels.TryGetValue(request.ChannelId, out var appChannel)) { - if (_logger.IsEnabled(LogLevel.Debug)) - { - _logger.LogDebug($"App channel with id: {appChannel.Id} cannot be added."); - } - return CreateAppChannelResponse.Created(); } + appChannel = _appChannels.GetOrAdd(request.ChannelId, addAppChannelFactory(request.ChannelId)); + try { - await appChannel.Connect(); - return CreateAppChannelResponse.Created(); + await appChannel!.Connect(); } - catch (MessageRouterException exception) + catch (MessageRouterDuplicateEndpointException exception) { - if (!exception.Message.Contains("Duplicate endpoint")) - { - throw; - } - if (_logger.IsEnabled(LogLevel.Warning)) { - _logger.LogWarning(exception, $"Endpoint is already registered {appChannel.Id}."); + _logger.LogWarning(exception, $"{request.ChannelId} is already registed as service endpoint."); } - - return CreateAppChannelResponse.Created(); } catch (Exception exception) { _logger.LogError(exception, $"An exception was thrown while executing {nameof(AddAppChannel)}."); - _appChannels.TryRemove(appChannel.Id, out _); + _appChannels.TryRemove(request.ChannelId, out _); return CreateAppChannelResponse.Failed(ChannelError.CreationFailed); } + + return CreateAppChannelResponse.Created(); } public async Task StartAsync(CancellationToken cancellationToken) @@ -544,27 +525,22 @@ public ValueTask GetUserChannels(GetUserChannelsRequest return ValueTask.FromResult(GetUserChannelsResponse.Success(result)); } - public async ValueTask JoinUserChannel(UserChannel channel, string instanceId) + public async ValueTask JoinUserChannel(Func addUserChannelFactory, JoinUserChannelRequest request) { - if (!Guid.TryParse(instanceId, out var id) || !_runningModules.TryGetValue(id, out _)) + if (!Guid.TryParse(request.InstanceId, out var id) || !_runningModules.TryGetValue(id, out _)) { return JoinUserChannelResponse.Failed(ChannelError.AccessDenied); } - //TODO remove if regarding this ChannelItem? channelItem = null; - if (_userChannelSet != null && !_userChannelSet.TryGetValue(channel.Id, out channelItem)) + if (_userChannelSet != null && !_userChannelSet.TryGetValue(request.ChannelId, out channelItem)) { - //TODO delete this if statement - if (!_userChannels.TryGetValue(channel.Id, out _)) - { - return JoinUserChannelResponse.Failed(ChannelError.CreationFailed); - } + return JoinUserChannelResponse.Failed(ChannelError.NoChannelFound); } try { - await AddUserChannel(channel); + await AddUserChannel(addUserChannelFactory, request.ChannelId); } catch (Exception exception) { @@ -606,7 +582,7 @@ public async ValueTask FindInstances(FindInstancesRequest if (!Guid.TryParse(request.Fdc3InstanceId, out var instanceId) || !_runningModules.TryGetValue(instanceId, out _)) { - return FindInstancesResponse.Failure(Fdc3DesktopAgentErrors.MissingId); //AccessDenied? + return FindInstancesResponse.Failure(Fdc3DesktopAgentErrors.MissingId); } try @@ -641,14 +617,14 @@ public async ValueTask GetAppMetadata(GetAppMetadataRequ if (!Guid.TryParse(request.Fdc3InstanceId, out var instanceId) || !_runningModules.TryGetValue(instanceId, out _)) { - return GetAppMetadataResponse.Failure(Fdc3DesktopAgentErrors.MissingId); //AccessDenied? + return GetAppMetadataResponse.Failure(Fdc3DesktopAgentErrors.MissingId); } if (request.AppIdentifier.InstanceId != null) { if (!Guid.TryParse(request.AppIdentifier.InstanceId, out var fdc3InstanceId)) { - return GetAppMetadataResponse.Failure(Fdc3DesktopAgentErrors.MissingId); //AccessDenied? + return GetAppMetadataResponse.Failure(Fdc3DesktopAgentErrors.MissingId); } if (!_runningModules.TryGetValue(fdc3InstanceId, out var app)) @@ -1305,7 +1281,7 @@ private ValueTask GetAppInfo(IAppIdentifier appIdentifier) Fdc3Version = Constants.SupportedFdc3Version, OptionalFeatures = new OptionalDesktopAgentFeatures { - OriginatingAppMetadata = false, //TODO + OriginatingAppMetadata = false, UserChannelMembershipAPIs = Constants.SupportUserChannelMembershipAPI }, Provider = Constants.DesktopAgentProvider, @@ -1336,27 +1312,48 @@ private AppMetadata GetAppMetadata(Fdc3App app, string? instanceId, IntentMetada private async Task?> ReadUserChannelSet(CancellationToken cancellationToken = default) { - var uri = _options.UserChannelConfigFile ?? new Uri($"file://{Directory.GetCurrentDirectory()}/userChannelSet.json"); + var uri = _options.UserChannelConfigFile; IEnumerable? userChannelSet = null; - if (uri.IsFile) + if (uri == null && _options.UserChannelConfig == null) { - var path = uri.IsAbsoluteUri ? uri.AbsolutePath : Path.GetFullPath(uri.ToString()); - - if (!_fileSystem.File.Exists(path)) + var assembly = Assembly.GetExecutingAssembly(); + using var stream = assembly.GetManifestResourceStream(ResourceNames.DefaultUserChannelSet); + if (stream == null) { - _logger.LogError($"{Fdc3DesktopAgentErrors.NoUserChannelSetFound}, no user channel set was configured."); - return null; + return null; } + + using var streamReader = new StreamReader(stream); - await using var stream = _fileSystem.File.OpenRead(path); - userChannelSet = JsonSerializer.Deserialize(stream, _jsonSerializerOptions); + var result = streamReader.ReadToEnd(); + userChannelSet = JsonSerializer.Deserialize(result, _jsonSerializerOptions); + } + else if (_options.UserChannelConfig != null) + { + userChannelSet = _options.UserChannelConfig; } - else if (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps) + else if (uri != null) { - var response = await _httpClient.GetAsync(uri, cancellationToken); - await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken); - userChannelSet = JsonSerializer.Deserialize(stream, _jsonSerializerOptions); + if (uri.IsFile) + { + var path = uri.IsAbsoluteUri ? uri.AbsolutePath : Path.GetFullPath(uri.ToString()); + + if (!_fileSystem.File.Exists(path)) + { + _logger.LogError($"{Fdc3DesktopAgentErrors.NoUserChannelSetFound}, no user channel set was configured."); + return null; + } + + await using var stream = _fileSystem.File.OpenRead(path); + userChannelSet = JsonSerializer.Deserialize(stream, _jsonSerializerOptions); + } + else if (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps) + { + var response = await _httpClient.GetAsync(uri, cancellationToken); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken); + userChannelSet = JsonSerializer.Deserialize(stream, _jsonSerializerOptions); + } } return new((userChannelSet ?? Array.Empty()).ToDictionary(x => x.Id, y => y)); diff --git a/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/Infrastructure/Internal/Constants.cs b/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/Infrastructure/Internal/Constants.cs index e7e7e6892..2ecb26f0c 100644 --- a/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/Infrastructure/Internal/Constants.cs +++ b/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/Infrastructure/Internal/Constants.cs @@ -19,7 +19,7 @@ namespace MorganStanley.ComposeUI.Fdc3.DesktopAgent.Infrastructure.Internal; internal static class Constants { public static string DesktopAgentProvider = "ComposeUI"; - public static string SupportedFdc3Version = "2.0.0"; + public static string SupportedFdc3Version = "2.0"; public static string? ComposeUIVersion = Assembly.GetExecutingAssembly().GetName().Version?.ToString(); /// diff --git a/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/Infrastructure/Internal/Fdc3DesktopAgentMessageRouterService.cs b/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/Infrastructure/Internal/Fdc3DesktopAgentMessageRouterService.cs index 395abff68..6a733e71e 100644 --- a/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/Infrastructure/Internal/Fdc3DesktopAgentMessageRouterService.cs +++ b/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/Infrastructure/Internal/Fdc3DesktopAgentMessageRouterService.cs @@ -69,10 +69,9 @@ public Fdc3DesktopAgentMessageRouterService( _logger = _loggerFactory.CreateLogger() ?? NullLogger.Instance; } - public async ValueTask HandleAddUserChannel(string id) + public async ValueTask HandleAddUserChannel(string id) { - var userChannel = new UserChannel(id, _messageRouter, _loggerFactory.CreateLogger()); - await _desktopAgent.AddUserChannel(userChannel); + var userChannel = await _desktopAgent.AddUserChannel((channelId) => new UserChannel(channelId, _messageRouter, _loggerFactory.CreateLogger()), id); return userChannel; } @@ -141,11 +140,10 @@ internal async ValueTask HandleCreatePrivateChanne { try { - var channel = new PrivateChannel(Guid.NewGuid().ToString(), _messageRouter, _loggerFactory.CreateLogger()); + var privateChannelId = Guid.NewGuid().ToString(); + await _desktopAgent.AddPrivateChannel((channelId) => new PrivateChannel(channelId, _messageRouter, _loggerFactory.CreateLogger()), privateChannelId); - await _desktopAgent.AddPrivateChannel(channel); - - return CreatePrivateChannelResponse.Created(channel.Id); + return CreatePrivateChannelResponse.Created(privateChannelId); } catch (Exception ex) { @@ -163,8 +161,7 @@ internal async ValueTask HandleCreatePrivateChanne return CreateAppChannelResponse.Failed(ChannelError.CreationFailed); } - var channel = new AppChannel(request.ChannelId, _messageRouter, _loggerFactory.CreateLogger()); - return await _desktopAgent.AddAppChannel(channel, request.InstanceId); + return await _desktopAgent.AddAppChannel((channelId) => new AppChannel(channelId, _messageRouter, _loggerFactory.CreateLogger()), request); } internal async ValueTask HandleGetUserChannels( @@ -186,8 +183,7 @@ internal async ValueTask HandleCreatePrivateChanne return JoinUserChannelResponse.Failed(Fdc3DesktopAgentErrors.PayloadNull); } - var channel = new UserChannel(request.ChannelId, _messageRouter, _loggerFactory.CreateLogger()); - return await _desktopAgent.JoinUserChannel(channel, request.InstanceId); + return await _desktopAgent.JoinUserChannel((channelId) => new UserChannel(channelId, _messageRouter, _loggerFactory.CreateLogger()), request); } internal async ValueTask HandleFindInstances(FindInstancesRequest? request, MessageContext? context) diff --git a/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/Infrastructure/Internal/IFdc3DesktopAgentBridge.cs b/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/Infrastructure/Internal/IFdc3DesktopAgentBridge.cs index a09038050..63f5816ba 100644 --- a/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/Infrastructure/Internal/IFdc3DesktopAgentBridge.cs +++ b/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/Infrastructure/Internal/IFdc3DesktopAgentBridge.cs @@ -37,24 +37,25 @@ internal interface IFdc3DesktopAgentBridge /// /// Handles the AddUserChannel call in the bridge. /// - /// + /// + /// /// - public ValueTask AddUserChannel(UserChannel userChannel); + public ValueTask AddUserChannel(Func addUserChannelFactory, string channelId); /// /// Handles the AddPrivateChannel call in the bridge. /// - /// + /// /// - public ValueTask AddPrivateChannel(PrivateChannel privateChannel); + public ValueTask AddPrivateChannel(Func addPrivateChannelFactory, string privateChannelId); /// /// Handles the AddAppChannel call in the bridge. /// - /// - /// The instanceId of the app which requested the response from the server. + /// + /// /// - public ValueTask AddAppChannel(AppChannel appChannel, string instanceId); + public ValueTask AddAppChannel(Func addAppChannelFactory, CreateAppChannelRequest request); /// /// Handles the FindChannel call in the bridge. @@ -116,10 +117,10 @@ internal interface IFdc3DesktopAgentBridge /// /// Handles the JoinUserChannel call in the bridge. /// - /// - /// + /// + /// /// - public ValueTask JoinUserChannel(UserChannel channel, string instanceId); + public ValueTask JoinUserChannel(Func addUserChannelFactory, JoinUserChannelRequest request); /// /// Handles the GetInfo call in the bridge. diff --git a/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/MorganStanley.ComposeUI.DesktopAgent.csproj b/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/MorganStanley.ComposeUI.DesktopAgent.csproj index fe0fef781..c116b84b8 100644 --- a/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/MorganStanley.ComposeUI.DesktopAgent.csproj +++ b/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/MorganStanley.ComposeUI.DesktopAgent.csproj @@ -35,12 +35,9 @@ - - - - - Always - + + Always + diff --git a/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/ResourceNames.cs b/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/ResourceNames.cs index 243229041..57715ad82 100644 --- a/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/ResourceNames.cs +++ b/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/ResourceNames.cs @@ -19,4 +19,5 @@ namespace MorganStanley.ComposeUI.Fdc3.DesktopAgent; public static class ResourceNames { public static readonly string Fdc3Bundle = @$"{Assembly.GetCallingAssembly().ManifestModule.Assembly.GetName()?.Name}.fdc3-iife-bundle.js"; + public static readonly string DefaultUserChannelSet = @$"{Assembly.GetCallingAssembly().ManifestModule.Assembly.GetName()?.Name}.userChannelSet.json"; } diff --git a/src/fdc3/dotnet/DesktopAgent/test/MorganStanley.ComposeUI.DesktopAgent.Tests/EndToEndTests.cs b/src/fdc3/dotnet/DesktopAgent/test/MorganStanley.ComposeUI.DesktopAgent.Tests/EndToEndTests.cs index 5ba09e509..1e287483e 100644 --- a/src/fdc3/dotnet/DesktopAgent/test/MorganStanley.ComposeUI.DesktopAgent.Tests/EndToEndTests.cs +++ b/src/fdc3/dotnet/DesktopAgent/test/MorganStanley.ComposeUI.DesktopAgent.Tests/EndToEndTests.cs @@ -1098,7 +1098,7 @@ public async Task JoinUserChannelReturnsAccessDenied() } [Fact] - public async Task JoinUserChannelReturnsCreationFailedError() + public async Task JoinUserChannelReturnsNoChannelFoundError() { //TODO: should add some identifier to the query => "fdc3:" + instance.Manifest.Id var origin = await _moduleLoader.StartModule(new StartRequest("appId1")); @@ -1117,7 +1117,7 @@ public async Task JoinUserChannelReturnsCreationFailedError() var result = response!.ReadJson(_options); result.Should().NotBeNull(); - result.Should().BeEquivalentTo(JoinUserChannelResponse.Failed(ChannelError.CreationFailed)); + result.Should().BeEquivalentTo(JoinUserChannelResponse.Failed(ChannelError.NoChannelFound)); await _moduleLoader.StopModule(new(origin.InstanceId)); } diff --git a/src/fdc3/dotnet/DesktopAgent/test/MorganStanley.ComposeUI.DesktopAgent.Tests/Fdc3DesktopAgentTests.cs b/src/fdc3/dotnet/DesktopAgent/test/MorganStanley.ComposeUI.DesktopAgent.Tests/Fdc3DesktopAgentTests.cs index 0506fd63e..670e5a057 100644 --- a/src/fdc3/dotnet/DesktopAgent/test/MorganStanley.ComposeUI.DesktopAgent.Tests/Fdc3DesktopAgentTests.cs +++ b/src/fdc3/dotnet/DesktopAgent/test/MorganStanley.ComposeUI.DesktopAgent.Tests/Fdc3DesktopAgentTests.cs @@ -80,12 +80,12 @@ public async Task AddUserChannel_wont_throw_and_adds_channel() mockMessageService.Setup(_ => _.ConnectAsync(It.IsAny())) .Returns((CancellationToken cancellationToken) => ValueTask.CompletedTask); - var mockUserChannel = new Mock( - "fdc3.channel.1", + + var action = async () => await _fdc3.AddUserChannel((channelId) => new Mock( + channelId, mockMessageService.Object, - NullLogger.Instance); + NullLogger.Instance).Object, "fdc3.channel.1"); - var action = async () => await _fdc3.AddUserChannel(mockUserChannel.Object); await action.Should().NotThrowAsync(); var channelExists = _fdc3.FindChannel(channelId: "fdc3.channel.1", ChannelType.User); @@ -106,12 +106,11 @@ public async Task FindChannel_returns_true() mockMessageService.Setup(_ => _.ConnectAsync(It.IsAny())) .Returns((CancellationToken cancellationToken) => ValueTask.CompletedTask); - var mockUserChannel = new Mock( - "fdc3.channel.1", + await _fdc3.AddUserChannel((channelId) => new Mock( + channelId, mockMessageService.Object, - NullLogger.Instance); + NullLogger.Instance).Object, "fdc3.channel.1"); - await _fdc3.AddUserChannel(mockUserChannel.Object); var result = _fdc3.FindChannel(channelId: "fdc3.channel.1", ChannelType.User); result.Should().BeTrue(); } @@ -600,12 +599,12 @@ public async Task AppChannel_is_created() var mockMessaging = new Mock(); - var appChannel = new AppChannel( - "my.channelId", + + var result = await _fdc3.AddAppChannel((channelId) => new AppChannel( + channelId, mockMessaging.Object, - new Mock>().Object); + new Mock>().Object), new CreateAppChannelRequest() { ChannelId = "my.channelId" , InstanceId = originFdc3InstanceId}); - var result = await _fdc3.AddAppChannel(appChannel, originFdc3InstanceId); result.Should().BeEquivalentTo(CreateAppChannelResponse.Created()); } @@ -622,12 +621,11 @@ public async Task AppChannel_is_failed_while_creation_request() mockMessaging.Setup(_ => _.ConnectAsync(It.IsAny())) .Throws(new Exception("dummy")); - var appChannel = new AppChannel( - "my.channelId", + var result = await _fdc3.AddAppChannel((channelId) => new AppChannel( + channelId, mockMessaging.Object, - new Mock>().Object); + new Mock>().Object), new CreateAppChannelRequest() { ChannelId = "my.channelId", InstanceId = originFdc3InstanceId }); - var result = await _fdc3.AddAppChannel(appChannel, originFdc3InstanceId); result.Should().BeEquivalentTo(new CreateAppChannelResponse { Success = false, Error = ChannelError.CreationFailed }); await _mockModuleLoader.Object.StopModule(new(origin.InstanceId)); @@ -734,15 +732,14 @@ public async Task GetUserChannels_succeeds() [Fact] public async Task JoinUserChannel_returns_access_denied_error_as_instance_id_not_found() { - var channel = new UserChannel("test", new Mock().Object, null); - var result = await _fdc3.JoinUserChannel(channel, Guid.NewGuid().ToString()); + var result = await _fdc3.JoinUserChannel((channelId) => new UserChannel(channelId, new Mock().Object, null), new() { InstanceId = Guid.NewGuid().ToString(), ChannelId = "test"}); result.Should().NotBeNull(); result.Should().BeEquivalentTo(JoinUserChannelResponse.Failed(ChannelError.AccessDenied)); } [Fact] - public async Task JoinUserChannel_returns_creation_failed_error_as_channel_id_not_found() + public async Task JoinUserChannel_returns_no_channel_found_error_as_channel_id_not_found() { await _fdc3.StartAsync(CancellationToken.None); @@ -751,10 +748,10 @@ public async Task JoinUserChannel_returns_creation_failed_error_as_channel_id_no var originFdc3InstanceId = Fdc3InstanceIdRetriever.Get(origin); var channel = new UserChannel("test", new Mock().Object, null); - var result = await _fdc3.JoinUserChannel(channel, originFdc3InstanceId); + var result = await _fdc3.JoinUserChannel((channelId) => new UserChannel(channelId, new Mock().Object, null), new() { InstanceId = originFdc3InstanceId, ChannelId = "test" }); result.Should().NotBeNull(); - result.Should().BeEquivalentTo(JoinUserChannelResponse.Failed(ChannelError.CreationFailed)); + result.Should().BeEquivalentTo(JoinUserChannelResponse.Failed(ChannelError.NoChannelFound)); await _mockModuleLoader.Object.StopModule(new(origin.InstanceId)); } @@ -772,8 +769,7 @@ public async Task JoinUserChannel_returns_creation_failed_error_as_couldnt_conne mockMessagingService.Setup(_ => _.ConnectAsync(It.IsAny())) .Throws(new Exception("DummyException")); - var channel = new UserChannel("fdc3.channel.1", mockMessagingService.Object, null); - var result = await _fdc3.JoinUserChannel(channel, originFdc3InstanceId); + var result = await _fdc3.JoinUserChannel((channelId) => new UserChannel(channelId, mockMessagingService.Object, null), new() { InstanceId = originFdc3InstanceId, ChannelId = "fdc3.channel.1" }); result.Should().NotBeNull(); result.Should().BeEquivalentTo(JoinUserChannelResponse.Failed(ChannelError.CreationFailed)); @@ -790,8 +786,7 @@ public async Task JoinUserChannel_succeeds() var origin = await _mockModuleLoader.Object.StartModule(new StartRequest("appId1")); var originFdc3InstanceId = Fdc3InstanceIdRetriever.Get(origin); - var channel = new UserChannel("fdc3.channel.1", new Mock().Object, null); - var result = await _fdc3.JoinUserChannel(channel, originFdc3InstanceId); + var result = await _fdc3.JoinUserChannel((channelId) => new UserChannel(channelId, new Mock().Object, null), new() { InstanceId = originFdc3InstanceId, ChannelId = "fdc3.channel.1" }); result.Should().NotBeNull(); result.Should().BeEquivalentTo(JoinUserChannelResponse.Joined(new DisplayMetadata() diff --git a/src/fdc3/dotnet/DesktopAgent/test/MorganStanley.ComposeUI.DesktopAgent.Tests/Infrastructure/Internal/Fdc3DesktopAgentMessageRouterService.Tests.cs b/src/fdc3/dotnet/DesktopAgent/test/MorganStanley.ComposeUI.DesktopAgent.Tests/Infrastructure/Internal/Fdc3DesktopAgentMessageRouterService.Tests.cs index f1b39be0e..86f32f9f4 100644 --- a/src/fdc3/dotnet/DesktopAgent/test/MorganStanley.ComposeUI.DesktopAgent.Tests/Infrastructure/Internal/Fdc3DesktopAgentMessageRouterService.Tests.cs +++ b/src/fdc3/dotnet/DesktopAgent/test/MorganStanley.ComposeUI.DesktopAgent.Tests/Infrastructure/Internal/Fdc3DesktopAgentMessageRouterService.Tests.cs @@ -1085,7 +1085,7 @@ public async Task HandleJoinUserChannel_returns_access_denied_error_as_instance_ } [Fact] - public async Task HandleJoinUserChannel_returns_creation_failed_error_as_channel_id_not_found() + public async Task HandleJoinUserChannel_returns_no_channel_found_error_as_channel_id_not_found() { await _fdc3.StartAsync(CancellationToken.None); @@ -1102,7 +1102,7 @@ public async Task HandleJoinUserChannel_returns_creation_failed_error_as_channel var result = await _fdc3.HandleJoinUserChannel(request, new()); result.Should().NotBeNull(); - result.Should().BeEquivalentTo(JoinUserChannelResponse.Failed(ChannelError.CreationFailed)); + result.Should().BeEquivalentTo(JoinUserChannelResponse.Failed(ChannelError.NoChannelFound)); await _mockModuleLoader.Object.StopModule(new(origin.InstanceId)); } diff --git a/src/fdc3/js/composeui-fdc3/src/ComposeUIDesktopAgent.ts b/src/fdc3/js/composeui-fdc3/src/ComposeUIDesktopAgent.ts index 8e4e8ab53..10b9d99c9 100644 --- a/src/fdc3/js/composeui-fdc3/src/ComposeUIDesktopAgent.ts +++ b/src/fdc3/js/composeui-fdc3/src/ComposeUIDesktopAgent.ts @@ -1,4 +1,4 @@ -/* +/* * Morgan Stanley makes this available to you under the Apache License, * Version 2.0 (the "License"). You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0. @@ -83,12 +83,12 @@ export class ComposeUIDesktopAgent implements DesktopAgent { throw new Error("Not implemented"); } - public findIntent(intent: string, context?: Context, resultType?: string): Promise { - return this.intentsClient.findIntent(intent, context, resultType); + public async findIntent(intent: string, context?: Context, resultType?: string): Promise { + return await this.intentsClient.findIntent(intent, context, resultType); } - public findIntentsByContext(context: Context, resultType?: string): Promise> { - return this.intentsClient.findIntentsByContext(context, resultType); + public async findIntentsByContext(context: Context, resultType?: string): Promise> { + return await this.intentsClient.findIntentsByContext(context, resultType); } public async findInstances(app: AppIdentifier): Promise> { @@ -104,7 +104,7 @@ export class ComposeUIDesktopAgent implements DesktopAgent { } public async raiseIntent(intent: string, context: Context, app?: string | AppIdentifier): Promise { - return this.intentsClient.raiseIntent(intent, context, app); + return await this.intentsClient.raiseIntent(intent, context, app); } //TODO @@ -181,9 +181,8 @@ export class ComposeUIDesktopAgent implements DesktopAgent { return appChannel!; } - //TODO public async createPrivateChannel(): Promise { - return this.channelFactory.createPrivateChannel(); + return await this.channelFactory.createPrivateChannel(); } public async getCurrentChannel(): Promise { @@ -200,7 +199,7 @@ export class ComposeUIDesktopAgent implements DesktopAgent { } public async getInfo(): Promise { - return this.metadataClient.getInfo(); + return await this.metadataClient.getInfo(); } public async getAppMetadata(app: AppIdentifier): Promise { diff --git a/src/fdc3/js/composeui-fdc3/src/index.ts b/src/fdc3/js/composeui-fdc3/src/index.ts index c2d753b03..ad4aa3435 100644 --- a/src/fdc3/js/composeui-fdc3/src/index.ts +++ b/src/fdc3/js/composeui-fdc3/src/index.ts @@ -16,6 +16,6 @@ import { ComposeUIDesktopAgent } from "./ComposeUIDesktopAgent"; import { createMessageRouter } from "@morgan-stanley/composeui-messaging-client"; -let fdc3 = new ComposeUIDesktopAgent("default", createMessageRouter()); -fdc3.joinUserChannel("default"); +let fdc3 = new ComposeUIDesktopAgent("fdc3.channel.1", createMessageRouter()); +fdc3.joinUserChannel("fdc3.channel.1"); export default fdc3; diff --git a/src/messaging/dotnet/src/Core/Exceptions/ThrowHelper.cs b/src/messaging/dotnet/src/Core/Exceptions/ThrowHelper.cs index 0c32ed855..9c2105b10 100644 --- a/src/messaging/dotnet/src/Core/Exceptions/ThrowHelper.cs +++ b/src/messaging/dotnet/src/Core/Exceptions/ThrowHelper.cs @@ -19,7 +19,7 @@ namespace MorganStanley.ComposeUI.Messaging.Exceptions; /// public static class ThrowHelper { - public static MessageRouterException DuplicateEndpoint(string endpoint) => + public static MessageRouterDuplicateEndpointException DuplicateEndpoint(string endpoint) => new(MessageRouterErrors.DuplicateEndpoint, $"Duplicate endpoint registration: '{endpoint}'"); public static MessageRouterException DuplicateRequestId() => diff --git a/src/messaging/dotnet/src/Core/MessageRouterDuplicateEndpointException.cs b/src/messaging/dotnet/src/Core/MessageRouterDuplicateEndpointException.cs new file mode 100644 index 000000000..c4a64c7be --- /dev/null +++ b/src/messaging/dotnet/src/Core/MessageRouterDuplicateEndpointException.cs @@ -0,0 +1,29 @@ +// Morgan Stanley makes this available to you under the Apache License, +// Version 2.0 (the "License"). You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0. +// +// See the NOTICE file distributed with this work for additional information +// regarding copyright ownership. Unless required by applicable law or agreed +// to in writing, software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +// or implied. See the License for the specific language governing permissions +// and limitations under the License. + +namespace MorganStanley.ComposeUI.Messaging; + +/// +/// Represents an exception thrown by the Message Router client when duplicated endpoint registration tries to happen. +/// +public class MessageRouterDuplicateEndpointException : MessageRouterException +{ + /// + /// Creates a new instance of with the provided error name and message. + /// + /// + /// + public MessageRouterDuplicateEndpointException(string name, string message) + : base(name, message) + { + } +} diff --git a/src/messaging/dotnet/test/Client.Tests/Client/MessageRouterClient.Tests.cs b/src/messaging/dotnet/test/Client.Tests/Client/MessageRouterClient.Tests.cs index cee1aa3cf..74939c951 100644 --- a/src/messaging/dotnet/test/Client.Tests/Client/MessageRouterClient.Tests.cs +++ b/src/messaging/dotnet/test/Client.Tests/Client/MessageRouterClient.Tests.cs @@ -514,7 +514,7 @@ public async Task RegisterServiceAsync_throws_a_MessageRouterException_if_the_en _connectionMock.Handle(); await _messageRouter.RegisterServiceAsync("test-service", Mock.Of()); - var exception = await Assert.ThrowsAsync( + var exception = await Assert.ThrowsAsync( async () => await _messageRouter.RegisterServiceAsync("test-service", Mock.Of())).WaitAsync(TestTimeout); exception.Name.Should().Be(MessageRouterErrors.DuplicateEndpoint); diff --git a/src/shell/dotnet/Shell/Properties/launchSettings.json b/src/shell/dotnet/Shell/Properties/launchSettings.json index c774ab1d3..b4f4c5dee 100644 --- a/src/shell/dotnet/Shell/Properties/launchSettings.json +++ b/src/shell/dotnet/Shell/Properties/launchSettings.json @@ -1,4 +1,4 @@ -{ +{ "profiles": { "Chart and grid": { "commandName": "Project", diff --git a/src/shell/dotnet/Shell/appsettings.json b/src/shell/dotnet/Shell/appsettings.json index f3ac2225b..d8b13a9dd 100644 --- a/src/shell/dotnet/Shell/appsettings.json +++ b/src/shell/dotnet/Shell/appsettings.json @@ -9,7 +9,7 @@ "FDC3": { "EnableFdc3": true, "DesktopAgent": { - "ChannelId": "default" + "ChannelId": "fdc3.channel.1" }, "AppDirectory": { "Source": "https://directory.fdc3.finos.org/v2/apps/"