From 1a67434816658ea377a68c04fe6746c66e064c31 Mon Sep 17 00:00:00 2001 From: lilla28 Date: Thu, 29 Aug 2024 14:37:05 +0200 Subject: [PATCH] fix(fdc3) - Add factory methods for creating channels if necessary, fixed example dialog, added MessageRouterDuplicatEndpointException, added descriptions, removed comments, and todos --- examples/fdc3-appdirectory/apps.json | 869 +----------------- .../fdc3-chart-and-grid/js-chart/chart.js | 2 +- .../main-view/services/mock-data.service.ts | 26 +- .../fdc3-pricing-and-chat/js-chat/chat.js | 2 +- .../js-pricing/pricing.js | 2 +- .../market-watch/market-watch.component.ts | 24 - .../trade-idea-generator/dialog.html | 5 +- .../trade-idea-generator.component.html | 5 +- .../trade-idea-generator.component.ts | 24 +- package.json | 2 +- .../Channels/Channel.cs | 4 +- .../Fdc3DesktopAgentOptions.cs | 6 + .../Fdc3DesktopAgent.cs | 259 ++---- .../Fdc3DesktopAgentMessageRouterService.cs | 18 +- .../Internal/IFdc3DesktopAgentBridge.cs | 21 +- ...organStanley.ComposeUI.DesktopAgent.csproj | 9 +- .../ResourceNames.cs | 1 + .../ChannelTestBase.cs | 155 ---- ...annelTestFixture.cs => ChannelTestBase.cs} | 2 + .../EndToEndTests.cs | 2 +- .../Fdc3DesktopAgentTests.cs | 343 +------ ...3DesktopAgentMessageRouterService.Tests.cs | 2 +- .../src/ComposeUIDesktopAgent.ts | 17 +- src/fdc3/js/composeui-fdc3/src/index.ts | 4 +- .../src/infrastructure/ComposeUIChannel.ts | 2 - .../ComposeUIContextListener.ts | 1 - .../infrastructure/ComposeUIIntentListener.ts | 1 - .../dotnet/src/Core/Exceptions/ThrowHelper.cs | 2 +- ...MessageRouterDuplicateEndpointException.cs | 29 + .../Client/MessageRouterClient.Tests.cs | 2 +- .../Shell/Properties/launchSettings.json | 2 +- src/shell/dotnet/Shell/appsettings.json | 2 +- 32 files changed, 229 insertions(+), 1616 deletions(-) delete mode 100644 src/fdc3/dotnet/DesktopAgent/test/MorganStanley.ComposeUI.DesktopAgent.Tests/ChannelTestBase.cs rename src/fdc3/dotnet/DesktopAgent/test/MorganStanley.ComposeUI.DesktopAgent.Tests/Channels/{ChannelTestFixture.cs => ChannelTestBase.cs} (99%) create mode 100644 src/messaging/dotnet/src/Core/MessageRouterDuplicateEndpointException.cs diff --git a/examples/fdc3-appdirectory/apps.json b/examples/fdc3-appdirectory/apps.json index e1c4bff40..471b874c5 100644 --- a/examples/fdc3-appdirectory/apps.json +++ b/examples/fdc3-appdirectory/apps.json @@ -18,859 +18,6 @@ "url": "http://localhost:4200/" } }, - { - "appId": "ChannelsAppId", - "name": "ChannelsApp", - "title": "Channels App", - "description": "Part of the FDC3 2.0 Conformance Tests - developed for FINOS by Scott Logic", - "type": "web", - "details": { - "url": "https://finos.github.io/FDC3-conformance-framework/v2.0/channels/" - }, - "hostManifests": { - "sail": { - "inject-api": "2.0", - "searchable": false, - "forceNewWindow": true - }, - "Finsemble": { - "foreign": { - "components": { - "App Launcher": { - "launchableByUser": false - }, - "Window Manager": { - "FSBLHeader": true, - "titlebarType": "injected" - } - } - }, - "interop": { - "joinMultipleChannels": false - } - } - }, - "version": "1.0.0", - "publisher": "FINOS", - "icons": [ - { - "src": "https://directory.fdc3.finos.org/assets/images/finos-black.png" - } - ] - }, - { - "appId": "IntentAppAId", - "name": "IntentAppA", - "title": "Intent App A", - "description": "Part of the FDC3 2.0 Conformance Tests - developed for FINOS by Scott Logic", - "type": "web", - "details": { - "url": "https://finos.github.io/FDC3-conformance-framework/v2.0/intent-a" - }, - "hostManifests": { - "sail": { - "inject-api": "2.0", - "searchable": false, - "forceNewWindow": true - }, - "Finsemble": { - "window": { - "top": "center", - "right": 0, - "width": 600, - "height": 400 - }, - "foreign": { - "components": { - "App Launcher": { - "launchableByUser": false - }, - "Window Manager": { - "FSBLHeader": true, - "titlebarType": "injected" - } - } - } - } - }, - "version": "1.0.0", - "publisher": "FINOS", - "icons": [ - { - "src": "https://directory.fdc3.finos.org/assets/images/finos-black.png" - } - ], - "interop": { - "intents": { - "listensFor": { - "aTestingIntent": { - "displayName": "A Testing Intent", - "contexts": [ - "testContextX", - "testContextZ" - ] - }, - "sharedTestingIntent1": { - "displayName": "Shared Testing Intent", - "contexts": [ - "testContextX" - ] - } - } - } - } - }, - { - "appId": "IntentAppBId", - "name": "IntentAppB", - "title": "Intent App B", - "description": "Part of the FDC3 2.0 Conformance Tests - developed for FINOS by Scott Logic", - "type": "web", - "details": { - "url": "https://finos.github.io/FDC3-conformance-framework/v2.0/intent-b" - }, - "hostManifests": { - "sail": { - "inject-api": "2.0", - "searchable": false, - "forceNewWindow": true - }, - "Finsemble": { - "window": { - "top": "center", - "right": 0, - "width": 600, - "height": 400 - }, - "foreign": { - "components": { - "App Launcher": { - "launchableByUser": false - }, - "Window Manager": { - "FSBLHeader": true, - "titlebarType": "injected" - } - } - } - } - }, - "version": "1.0.0", - "publisher": "FINOS", - "icons": [ - { - "src": "https://directory.fdc3.finos.org/assets/images/finos-black.png" - } - ], - "interop": { - "intents": { - "listensFor": { - "bTestingIntent": { - "displayName": "B Testing Intent", - "contexts": [ - "testContextY" - ] - }, - "sharedTestingIntent1": { - "displayName": "Shared Testing Intent", - "contexts": [ - "testContextX", - "testContextY" - ], - "resultType": "testContextY" - } - } - } - } - }, - { - "appId": "IntentAppCId", - "name": "IntentAppC", - "title": "Intent App C", - "description": "Part of the FDC3 2.0 Conformance Tests - developed for FINOS by Scott Logic", - "type": "web", - "details": { - "url": "https://finos.github.io/FDC3-conformance-framework/v2.0/intent-c" - }, - "hostManifests": { - "sail": { - "inject-api": "2.0", - "searchable": false, - "forceNewWindow": true - }, - "Finsemble": { - "window": { - "top": "center", - "right": 0, - "width": 600, - "height": 400 - }, - "foreign": { - "components": { - "App Launcher": { - "launchableByUser": false - }, - "Window Manager": { - "FSBLHeader": true, - "titlebarType": "injected" - } - } - } - } - }, - "version": "1.0.0", - "publisher": "FINOS", - "icons": [ - { - "src": "https://directory.fdc3.finos.org/assets/images/finos-black.png" - } - ], - "interop": { - "intents": { - "listensFor": { - "cTestingIntent": { - "displayName": "C Testing Intent", - "contexts": [ - "testContextX" - ], - "resultType": "testContextZ" - } - } - } - } - }, - { - "appId": "IntentAppDId", - "name": "IntentAppD", - "title": "Intent App D", - "description": "Part of the FDC3 2.0 Conformance Tests - developed for FINOS by Scott Logic", - "type": "web", - "details": { - "url": "https://finos.github.io/FDC3-conformance-framework/v2.0/intent-d" - }, - "hostManifests": { - "sail": { - "inject-api": "2.0", - "searchable": false, - "forceNewWindow": true - }, - "Finsemble": { - "window": { - "top": "center", - "right": 0, - "width": 600, - "height": 400 - }, - "foreign": { - "components": { - "App Launcher": { - "launchableByUser": false - }, - "Window Manager": { - "FSBLHeader": true, - "titlebarType": "injected" - } - } - } - } - }, - "version": "1.0.0", - "publisher": "FINOS", - "icons": [ - { - "src": "https://directory.fdc3.finos.org/assets/images/finos-black.png" - } - ], - "interop": { - "intents": { - "listensFor": { - "sharedTestingIntent2": { - "displayName": "Shared Testing Intent", - "contexts": [ - "testContextX" - ], - "resultType": "testContextZ" - } - } - } - } - }, - { - "appId": "IntentAppEId", - "name": "IntentAppE", - "title": "Intent App E", - "description": "Part of the FDC3 2.0 Conformance Tests - developed for FINOS by Scott Logic", - "type": "web", - "details": { - "url": "https://finos.github.io/FDC3-conformance-framework/v2.0/intent-e" - }, - "hostManifests": { - "sail": { - "inject-api": "2.0", - "searchable": false, - "forceNewWindow": true - }, - "Finsemble": { - "window": { - "top": "center", - "right": 0, - "width": 600, - "height": 400 - }, - "foreign": { - "components": { - "App Launcher": { - "launchableByUser": false - }, - "Window Manager": { - "FSBLHeader": true, - "titlebarType": "injected" - } - } - } - } - }, - "version": "1.0.0", - "publisher": "FINOS", - "icons": [ - { - "src": "https://directory.fdc3.finos.org/assets/images/finos-black.png" - } - ], - "interop": { - "intents": { - "listensFor": { - "sharedTestingIntent2": { - "displayName": "Shared Testing Intent", - "contexts": [ - "testContextY" - ], - "resultType": "channel" - } - } - } - } - }, - { - "appId": "IntentAppFId", - "name": "IntentAppF", - "title": "Intent App F", - "description": "Part of the FDC3 2.0 Conformance Tests - developed for FINOS by Scott Logic", - "type": "web", - "details": { - "url": "https://finos.github.io/FDC3-conformance-framework/v2.0/intent-f" - }, - "hostManifests": { - "sail": { - "inject-api": "2.0", - "searchable": false, - "forceNewWindow": true - }, - "Finsemble": { - "window": { - "top": "center", - "right": 0, - "width": 600, - "height": 400 - }, - "foreign": { - "components": { - "App Launcher": { - "launchableByUser": false - }, - "Window Manager": { - "FSBLHeader": true, - "titlebarType": "injected" - } - } - } - } - }, - "version": "1.0.0", - "publisher": "FINOS", - "icons": [ - { - "src": "https://directory.fdc3.finos.org/assets/images/finos-black.png" - } - ], - "interop": { - "intents": { - "listensFor": { - "sharedTestingIntent2": { - "displayName": "Shared Testing Intent", - "contexts": [ - "testContextY" - ], - "resultType": "channel" - } - } - } - } - }, - { - "appId": "IntentAppGId", - "name": "IntentAppG", - "title": "Intent App G", - "description": "Part of the FDC3 2.0 Conformance Tests - developed for FINOS by Scott Logic", - "type": "web", - "details": { - "url": "https://finos.github.io/FDC3-conformance-framework/v2.0/intent-g" - }, - "hostManifests": { - "sail": { - "inject-api": "2.0", - "searchable": false, - "forceNewWindow": true - }, - "Finsemble": { - "window": { - "top": "center", - "right": 0, - "width": 600, - "height": 400 - }, - "foreign": { - "components": { - "App Launcher": { - "launchableByUser": false - }, - "Window Manager": { - "FSBLHeader": true, - "titlebarType": "injected" - } - } - } - } - }, - "version": "1.0.0", - "publisher": "FINOS", - "icons": [ - { - "src": "https://directory.fdc3.finos.org/assets/images/finos-black.png" - } - ], - "interop": { - "intents": { - "listensFor": { - "sharedTestingIntent2": { - "displayName": "Shared Testing Intent", - "contexts": [ - "testContextY" - ] - } - } - } - } - }, - { - "appId": "IntentAppHId", - "name": "IntentAppH", - "title": "Intent App H", - "description": "Part of the FDC3 2.0 Conformance Tests - developed for FINOS by Scott Logic", - "type": "web", - "details": { - "url": "https://finos.github.io/FDC3-conformance-framework/v2.0/intent-h" - }, - "hostManifests": { - "sail": { - "inject-api": "2.0", - "searchable": false, - "forceNewWindow": true - }, - "Finsemble": { - "window": { - "top": "center", - "right": 0, - "width": 600, - "height": 400 - }, - "foreign": { - "components": { - "App Launcher": { - "launchableByUser": false - }, - "Window Manager": { - "FSBLHeader": true, - "titlebarType": "injected" - } - } - } - } - }, - "version": "1.0.0", - "publisher": "FINOS", - "icons": [ - { - "src": "https://directory.fdc3.finos.org/assets/images/finos-black.png" - } - ], - "interop": { - "intents": { - "listensFor": { - "sharedTestingIntent2": { - "displayName": "Shared Testing Intent", - "contexts": [ - "testContextY" - ], - "resultType": "testContextZ" - } - } - } - } - }, - { - "appId": "IntentAppIId", - "name": "IntentAppI", - "title": "Intent App I", - "description": "Part of the FDC3 2.0 Conformance Tests - developed for FINOS by Scott Logic", - "type": "web", - "details": { - "url": "https://finos.github.io/FDC3-conformance-framework/v2.0/intent-i" - }, - "hostManifests": { - "sail": { - "inject-api": "2.0", - "searchable": false, - "forceNewWindow": true - }, - "Finsemble": { - "window": { - "top": "center", - "right": 0, - "width": 600, - "height": 400 - }, - "foreign": { - "components": { - "App Launcher": { - "launchableByUser": false - }, - "Window Manager": { - "FSBLHeader": true, - "titlebarType": "injected" - } - } - } - } - }, - "version": "1.0.0", - "publisher": "FINOS", - "icons": [ - { - "src": "https://directory.fdc3.finos.org/assets/images/finos-black.png" - } - ], - "interop": { - "intents": { - "listensFor": { - "sharedTestingIntent2": { - "displayName": "Shared Testing Intent", - "contexts": [ - "testContextY" - ], - "resultType": "testContextZ" - } - } - } - } - }, - { - "appId": "IntentAppJId", - "name": "IntentAppJ", - "title": "Intent App J", - "description": "Part of the FDC3 2.0 Conformance Tests - developed for FINOS by Scott Logic", - "type": "web", - "details": { - "url": "https://finos.github.io/FDC3-conformance-framework/v2.0/intent-j" - }, - "hostManifests": { - "sail": { - "inject-api": "2.0", - "searchable": false, - "forceNewWindow": true - }, - "Finsemble": { - "window": { - "top": "center", - "right": 0, - "width": 600, - "height": 400 - }, - "foreign": { - "components": { - "App Launcher": { - "launchableByUser": false - }, - "Window Manager": { - "FSBLHeader": true, - "titlebarType": "injected" - } - } - } - } - }, - "version": "1.0.0", - "publisher": "FINOS", - "icons": [ - { - "src": "https://directory.fdc3.finos.org/assets/images/finos-black.png" - } - ], - "interop": { - "intents": { - "listensFor": { - "privateChannelIsPrivate": { - "displayName": "J Testing Intent", - "contexts": [ - "privateChannelDetails" - ], - "resultType": "privateChannelIsPrivateResult" - } - } - } - } - }, - { - "appId": "IntentAppKId", - "name": "IntentAppK", - "title": "Intent App K", - "description": "Part of the FDC3 2.0 Conformance Tests - developed for FINOS by Scott Logic", - "type": "web", - "details": { - "url": "https://finos.github.io/FDC3-conformance-framework/v2.0/intent-k" - }, - "hostManifests": { - "sail": { - "inject-api": "2.0", - "searchable": false, - "forceNewWindow": true - }, - "Finsemble": { - "window": { - "top": "center", - "right": 0, - "width": 600, - "height": 400 - }, - "foreign": { - "components": { - "App Launcher": { - "launchableByUser": false - }, - "Window Manager": { - "FSBLHeader": true, - "titlebarType": "injected" - } - } - } - } - }, - "version": "1.0.0", - "publisher": "FINOS", - "icons": [ - { - "src": "https://directory.fdc3.finos.org/assets/images/finos-black.png" - } - ], - "interop": { - "intents": { - "listensFor": { - "kTestingIntent": { - "displayName": "K Testing Intent", - "contexts": [ - "testContextX" - ], - "resultType": "channel" - } - } - } - } - }, - { - "appId": "MetadataAppId", - "name": "MetadataApp", - "title": "App Title", - "description": "Part of the FDC3 2.0 Conformance Tests - developed for FINOS by Scott Logic", - "details": { - "url": "https://finos.github.io/FDC3-conformance-framework/v2.0/metadata" - }, - "hostManifests": { - "sail": { - "inject-api": "2.0", - "searchable": false, - "forceNewWindow": true - }, - "Finsemble": { - "window": { - "top": "center", - "right": 0, - "width": 600, - "height": 400 - }, - "foreign": { - "components": { - "App Launcher": { - "launchableByUser": false - }, - "Window Manager": { - "FSBLHeader": true, - "titlebarType": "injected" - } - } - }, - "interop": { - "intents": { - "listensFor": {} - } - } - } - }, - "version": "1.0.0", - "tooltip": "placeholder", - "publisher": "FINOS", - "type": "web", - "icons": [ - { - "src": "https://directory.fdc3.finos.org/assets/images/finos-black.png" - } - ], - "screenshots": [ - { - "src": "https://directory.fdc3.finos.org/assets/images/finos-black.png" - } - ] - }, - { - "appId": "MockAppId", - "name": "MockApp", - "description": "Part of the FDC3 2.0 Conformance Tests - developed for FINOS by Scott Logic", - "details": { - "url": "https://finos.github.io/FDC3-conformance-framework/v2.0/general" - }, - "hostManifests": { - "sail": { - "inject-api": "2.0", - "searchable": false, - "forceNewWindow": true - }, - "Finsemble": { - "window": { - "top": "center", - "right": 0, - "width": 600, - "height": 400 - }, - "foreign": { - "components": { - "App Launcher": { - "launchableByUser": false - }, - "Window Manager": { - "FSBLHeader": true, - "titlebarType": "injected" - } - } - }, - "interop": { - "joinMultipleChannels": false - } - } - }, - "version": "1.0.0", - "publisher": "FINOS", - "type": "web", - "icons": [ - { - "src": "https://directory.fdc3.finos.org/assets/images/finos-black.png" - } - ] - }, - { - "appId": "OpenAppAId", - "name": "OpenAppA", - "title": "Open App A", - "description": "Part of the FDC3 2.0 Conformance Tests - developed for FINOS by Scott Logic", - "type": "web", - "details": { - "url": "https://finos.github.io/FDC3-conformance-framework/v2.0/open-a" - }, - "hostManifests": { - "sail": { - "inject-api": "2.0", - "searchable": false, - "forceNewWindow": true - }, - "Finsemble": { - "window": { - "top": "center", - "right": 0, - "width": 600, - "height": 400 - }, - "foreign": { - "components": { - "App Launcher": { - "launchableByUser": false - }, - "Window Manager": { - "FSBLHeader": true, - "titlebarType": "injected" - } - } - } - } - }, - "version": "1.0.0", - "publisher": "FINOS", - "icons": [ - { - "src": "https://directory.fdc3.finos.org/assets/images/finos-black.png" - } - ] - }, - { - "appId": "OpenAppBId", - "name": "OpenAppB", - "title": "Open App B", - "description": "Part of the FDC3 2.0 Conformance Tests - developed for FINOS by Scott Logic", - "type": "web", - "details": { - "url": "https://finos.github.io/FDC3-conformance-framework/v2.0/open-b" - }, - "hostManifests": { - "sail": { - "inject-api": "2.0", - "searchable": false, - "forceNewWindow": true - }, - "Finsemble": { - "window": { - "top": "center", - "right": 0, - "width": 600, - "height": 400 - }, - "foreign": { - "components": { - "App Launcher": { - "launchableByUser": false - }, - "Window Manager": { - "FSBLHeader": true, - "titlebarType": "injected" - } - } - } - } - }, - "version": "1.0.0", - "publisher": "FINOS", - "icons": [ - { - "src": "https://directory.fdc3.finos.org/assets/images/finos-black.png" - } - ] - }, { "appId": "Conformance2", "name": "Conformance2", @@ -905,6 +52,22 @@ "version": "1.0.0", "publisher": "FINOS", "icons": [ { "src": "https://fdc3.finos.org/assets/fdc3-logo.png" } ] + }, + { + "appId": "js-trader-app", + "name": "Js Trader App Example", + "type": "web", + "details": { + "url": "http://localhost:4201/" + } + }, + { + "appId": "js-order-book", + "name": "Js Order Book Example", + "type": "web", + "details": { + "url": "http://localhost:4202/" + } } ] } \ No newline at end of file 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 039d9519b..58a592973 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 @@ -231,10 +231,7 @@ export class MarketWatchComponent implements OnInit, OnDestroy{ type: topic, result: { success: false, -<<<<<<< HEAD action: "BUY", -======= ->>>>>>> f312aa3 (feat(app-channels) - Implement fdc3.getOrCreateChannel(), stopping started instances in the tests, refactored channel tests) error: "No symbol found." } }); @@ -244,8 +241,6 @@ export class MarketWatchComponent implements OnInit, OnDestroy{ if (data.action === 'BUY') { const sumQuantity = symbols.reduce((sum, current) => { - console.log(current); - console.log(sum); if (current.Children && current.Children.length > 0) { let s: number = current.Children.reduce((t, currentSymbol) => { if(currentSymbol.AskSize) { @@ -259,7 +254,6 @@ export class MarketWatchComponent implements OnInit, OnDestroy{ return sum + 0; }, 0); - console.log("Sum of the available symbols on the market:", sumQuantity); if (sumQuantity < data.quantity) { await this.channel!.broadcast( @@ -267,10 +261,7 @@ export class MarketWatchComponent implements OnInit, OnDestroy{ type: topic, result: { success: false, -<<<<<<< HEAD action: "BUY", -======= ->>>>>>> f312aa3 (feat(app-channels) - Implement fdc3.getOrCreateChannel(), stopping started instances in the tests, refactored channel tests) error: "Too much ticks were requested; not enough symbols are available on the target." } }); @@ -281,7 +272,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; } @@ -300,10 +290,7 @@ export class MarketWatchComponent implements OnInit, OnDestroy{ type: topic, result: { success: true, -<<<<<<< HEAD action: "BUY", -======= ->>>>>>> f312aa3 (feat(app-channels) - Implement fdc3.getOrCreateChannel(), stopping started instances in the tests, refactored channel tests) tradePrice: price } }); @@ -312,7 +299,6 @@ export class MarketWatchComponent implements OnInit, OnDestroy{ } for (let innerElement of element.Children) { - console.log("current size:", size); if (innerElement.Symbol != data.symbol) { continue; } @@ -327,7 +313,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; } } @@ -337,10 +322,7 @@ export class MarketWatchComponent implements OnInit, OnDestroy{ type: topic, result: { success: true, -<<<<<<< HEAD action: "BUY", -======= ->>>>>>> f312aa3 (feat(app-channels) - Implement fdc3.getOrCreateChannel(), stopping started instances in the tests, refactored channel tests) tradePrice: price } }); @@ -376,7 +358,6 @@ export class MarketWatchComponent implements OnInit, OnDestroy{ if(symbolElement) { symbolElement.BidSize = symbolElement.BidSize + data.quantity; symbolElement.LastTrade = data.timestamp; -<<<<<<< HEAD await this.channel!.broadcast( { type: topic, @@ -385,14 +366,11 @@ export class MarketWatchComponent implements OnInit, OnDestroy{ action: "SELL", } }); -======= ->>>>>>> f312aa3 (feat(app-channels) - Implement fdc3.getOrCreateChannel(), stopping started instances in the tests, refactored channel tests) this.subject.next( { Symbol: data.symbol, DataSource: [...ELEMENT_DATA] }); -<<<<<<< HEAD } else { await this.channel!.broadcast( { @@ -403,8 +381,6 @@ export class MarketWatchComponent implements OnInit, OnDestroy{ error: "Trader is not able to place its symbol for selling." } }); -======= ->>>>>>> f312aa3 (feat(app-channels) - Implement fdc3.getOrCreateChannel(), stopping started instances in the tests, refactored channel tests) } return; 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 04695f66f..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: { @@ -182,7 +180,6 @@ export class TradeIdeaGeneratorComponent implements OnDestroy { return; } -<<<<<<< HEAD const result = context['result']; if (result.action as string == "BUY") { const price: number = result.tradePrice as number; @@ -190,11 +187,6 @@ export class TradeIdeaGeneratorComponent implements OnDestroy { } else { this.feedbackSubject.next(this.trader + " has indicated that " + this.currentValue + " symbol of: " + this.symbols.value as string + " is/are available for buying."); } -======= - const price: number = context['result'].tradePrice as number; - this.feedbackSubject.next(this.trader + " has bought " + this.currentValue + " symbol of: " + this.symbols.value as string + " for $" + price + "."); - console.log(this.feedback); ->>>>>>> f312aa3 (feat(app-channels) - Implement fdc3.getOrCreateChannel(), stopping started instances in the tests, refactored channel tests) }); this.listeners.set(topic, listener); } @@ -207,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 2e691d006..eb56cf919 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 bf6c1c4e7..3d112e305 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..98ad2832e 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)) @@ -1146,62 +1122,6 @@ void FilterAppIntents(Fdc3App app) return result; } - private Dictionary GetAppIntentsFromRunningModules( - Func, IEnumerable>?> selector, - IAppIdentifier? targetAppIdentifier, - Dictionary appIntents) - { - foreach (var app in _runningModules) - { - if (targetAppIdentifier?.InstanceId != null - && Guid.TryParse(targetAppIdentifier.InstanceId, out var instanceId) - && instanceId != app.Key) - { - continue; - } - - var intentMetadataCollection = selector(app.Value, appIntents); - - if (intentMetadataCollection == null) - { - continue; - } - - appIntents = GetAppIntentsFromIntentMetadataCollection( - app.Value, - app.Key.ToString(), - intentMetadataCollection, - appIntents); - } - - return appIntents; - } - - private async Task> GetAppIntentsFromAppDirectory( - Func, IEnumerable>?> selector, - IAppIdentifier? targetAppIdentifier, - Dictionary appIntents) - { - foreach (var app in await _appDirectory.GetApps()) - { - if (targetAppIdentifier != null && targetAppIdentifier.AppId != app.AppId) - { - continue; - } - - var intentMetadataCollection = selector(app, appIntents); - - if (intentMetadataCollection == null) - { - continue; - } - - appIntents = GetAppIntentsFromIntentMetadataCollection(app, null, intentMetadataCollection, appIntents); - } - - return appIntents; - } - private Dictionary GetAppIntentsFromIntentMetadataCollection( Fdc3App app, string? instanceId, @@ -1245,38 +1165,6 @@ private Dictionary GetAppIntentsFromIntentMetadataCollection( return appIntents; } - private async Task GetAppIntentsFromAppDirectory( - Action selector, - IAppIdentifier? targetAppIdentifier) - { - foreach (var app in await _appDirectory.GetApps()) - { - if (targetAppIdentifier != null && targetAppIdentifier.AppId != app.AppId) - { - continue; - } - - selector(app, null); - } - } - - private void GetAppIntentsFromRunningModules( - Action selector, - IAppIdentifier? targetAppIdentifier) - { - foreach (var app in _runningModules) - { - if (targetAppIdentifier?.InstanceId != null - && Guid.TryParse(targetAppIdentifier.InstanceId, out var instanceId) - && instanceId != app.Key) - { - continue; - } - - selector(app.Value, app.Key.ToString()); - } - } - private ValueTask GetAppInfo(IAppIdentifier appIdentifier) { if (!Guid.TryParse(appIdentifier.InstanceId!, out var instanceId)) @@ -1305,7 +1193,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 +1224,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 (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps) + else if (_options.UserChannelConfig != null) { - var response = await _httpClient.GetAsync(uri, cancellationToken); - await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken); - userChannelSet = JsonSerializer.Deserialize(stream, _jsonSerializerOptions); + userChannelSet = _options.UserChannelConfig; + } + else if (uri != null) + { + 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/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/ChannelTestBase.cs b/src/fdc3/dotnet/DesktopAgent/test/MorganStanley.ComposeUI.DesktopAgent.Tests/ChannelTestBase.cs deleted file mode 100644 index d99eaa13a..000000000 --- a/src/fdc3/dotnet/DesktopAgent/test/MorganStanley.ComposeUI.DesktopAgent.Tests/ChannelTestBase.cs +++ /dev/null @@ -1,155 +0,0 @@ -/* - * 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. - */ - -using Finos.Fdc3.Context; -using MorganStanley.ComposeUI.Fdc3.DesktopAgent.Channels; -using MorganStanley.ComposeUI.Fdc3.DesktopAgent.Contracts; -using MorganStanley.ComposeUI.Messaging.Abstractions; - -namespace MorganStanley.ComposeUI.Fdc3.DesktopAgent.Tests; - -<<<<<<<< HEAD:src/fdc3/dotnet/DesktopAgent/test/MorganStanley.ComposeUI.DesktopAgent.Tests/UserChannelTests.cs -public class UserChannelTests -======== -public abstract class ChannelTestBase ->>>>>>>> c3fdef5 (fix(fdc3) - Removed unneccessary fields, renamed base class):src/fdc3/dotnet/DesktopAgent/test/MorganStanley.ComposeUI.DesktopAgent.Tests/ChannelTestBase.cs -{ - private const string TestChannel = "testChannel"; - UserChannel _channel = new UserChannel(TestChannel, new Mock().Object, null); - ChannelTopics _topics = Fdc3Topic.UserChannel(TestChannel); - - [Theory] - [InlineData(new object?[] { null })] - [InlineData(new object?[] { "testType" })] - public async void CallingGetCurrentContextOnNewUserChannelReturnsNull(string? contextType) - { - var request = new GetCurrentContextRequest() { ContextType = contextType }; - var ctx = await _channel.GetCurrentContext(_topics.GetCurrentContext, MessageBuffer.Factory.CreateJson(request), null); - ctx.Should().BeNull(); - } - - [Fact] - public void NewUserChannelCanHandleContext() - { - var context = GetContext(); - new Action(() => _channel.HandleBroadcast(context)).Should().NotThrow(); - } - - [Fact] - public async void BroadcastedChannelCanReturnLatestBroadcast() - { - var context = await PreBroadcastContext(); - - var ctx = await _channel.GetCurrentContext(_topics.GetCurrentContext, null, null); - ctx.Should().BeEquivalentTo(context); - } - - [Fact] - public async void BroadcastedUserChannelCanReturnLatestBroadcastForType() - { - var context = await PreBroadcastContext(); - var ctx = await _channel.GetCurrentContext(_topics.GetCurrentContext, ContextType, null); - ctx.Should().BeEquivalentTo(context); - } - - [Fact] - public async void BroadcastedUserChannelReturnsNullForDifferentType() - { - await PreBroadcastContext(); - var ctx = await _channel.GetCurrentContext(_topics.GetCurrentContext, OtherContextType, null); - ctx.Should().BeNull(); - } - - [Fact] - public async void BroadcastedUserChannelCanHandleBroadcast() - { - await PreBroadcastContext(); - var context = GetContext(); - new Action(() => _channel.HandleBroadcast(context)).Should().NotThrow(); - } - - [Fact] - public async void BroadcastedUserChannelUpdatesLatestBroadcast() - { - var context = await DoubleBroadcastContext(); - var ctx = await _channel.GetCurrentContext(_topics.GetCurrentContext, null, null); - ctx.Should().BeEquivalentTo(context); - } - - [Fact] - public async void BroadcastedUserChannelUpdatesLatestBroadcastForType() - { - var context = await DoubleBroadcastContext(); - var ctx = await _channel.GetCurrentContext(_topics.GetCurrentContext, ContextType, null); - ctx.Should().BeEquivalentTo(context); - } - - [Fact] - public async void BroadcastedUserChannelCanHandleDifferentBroadcast() - { - await PreBroadcastContext(); - new Action(() => _channel.HandleBroadcast(GetDifferentContext())).Should().NotThrow(); - } - - [Fact] - public async void ChannelWithDifferentBroadcastsUpdatesLatestBroadcast() - { - var (_, second) = await BroadcastDifferentContexts(); - var ctx = await _channel.GetCurrentContext(_topics.GetCurrentContext, null, null); - ctx.Should().BeEquivalentTo(second); - } - - [Fact] - public async void ChannelWithDifferentBroadcastsReturnsAppropriateContext() - { - var (first, second) = await BroadcastDifferentContexts(); - - var ctx1 = await _channel.GetCurrentContext(_topics.GetCurrentContext, ContextType, null); - var ctx2 = await _channel.GetCurrentContext(_topics.GetCurrentContext, DifferentContextType, null); - - ctx1.Should().BeEquivalentTo(first); - ctx2.Should().BeEquivalentTo(second); - } - - private int _counter; - private MessageBuffer ContextType => MessageBuffer.Factory.CreateJson(new GetCurrentContextRequest { ContextType = new Contact().Type }); - private MessageBuffer OtherContextType => MessageBuffer.Factory.CreateJson(new GetCurrentContextRequest { ContextType = new Email(null).Type }); - private MessageBuffer GetContext() => MessageBuffer.Factory.CreateJson(new Contact(new ContactID() { Email = $"test{_counter}@test.org", FdsId = $"test{_counter++}" }, "Testy Tester")); - private MessageBuffer DifferentContextType => MessageBuffer.Factory.CreateJson(new GetCurrentContextRequest { ContextType = new Currency().Type }); - private MessageBuffer GetDifferentContext() => MessageBuffer.Factory.CreateJson(new Currency(new CurrencyID() { CURRENCY_ISOCODE = "HUF" })); - - private async ValueTask PreBroadcastContext() - { - var context = GetContext(); - await _channel.HandleBroadcast(context); - return context; - } - - private async ValueTask DoubleBroadcastContext() - { - await _channel.HandleBroadcast(GetContext()); - var context = GetContext(); - await _channel.HandleBroadcast(context); - return context; - } - - private async ValueTask<(MessageBuffer first, MessageBuffer second)> BroadcastDifferentContexts() - { - var first = GetContext(); - var second = GetDifferentContext(); - await _channel.HandleBroadcast(first); - await _channel.HandleBroadcast(second); - return (first, second); - } -} \ No newline at end of file diff --git a/src/fdc3/dotnet/DesktopAgent/test/MorganStanley.ComposeUI.DesktopAgent.Tests/Channels/ChannelTestFixture.cs b/src/fdc3/dotnet/DesktopAgent/test/MorganStanley.ComposeUI.DesktopAgent.Tests/Channels/ChannelTestBase.cs similarity index 99% rename from src/fdc3/dotnet/DesktopAgent/test/MorganStanley.ComposeUI.DesktopAgent.Tests/Channels/ChannelTestFixture.cs rename to src/fdc3/dotnet/DesktopAgent/test/MorganStanley.ComposeUI.DesktopAgent.Tests/Channels/ChannelTestBase.cs index 17af3d0b9..170097cd5 100644 --- a/src/fdc3/dotnet/DesktopAgent/test/MorganStanley.ComposeUI.DesktopAgent.Tests/Channels/ChannelTestFixture.cs +++ b/src/fdc3/dotnet/DesktopAgent/test/MorganStanley.ComposeUI.DesktopAgent.Tests/Channels/ChannelTestBase.cs @@ -15,8 +15,10 @@ using Finos.Fdc3.Context; using MorganStanley.ComposeUI.Fdc3.DesktopAgent.Channels; using MorganStanley.ComposeUI.Fdc3.DesktopAgent.Contracts; +using MorganStanley.ComposeUI.Messaging.Abstractions; namespace MorganStanley.ComposeUI.Fdc3.DesktopAgent.Tests.Channels; + public abstract class ChannelTestBase { internal Channel Channel { get; init; } 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 1f1064f5e..ac9a94b47 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 @@ -1064,7 +1064,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")); 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 b84405bb7..5844e1cc3 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 @@ -104,12 +104,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); @@ -130,12 +130,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(); } @@ -624,12 +623,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()); } @@ -646,12 +645,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 }); } @@ -753,15 +751,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); @@ -770,7 +767,7 @@ 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.NoChannelFound)); @@ -789,8 +786,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)); @@ -805,8 +801,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() @@ -1215,304 +1210,4 @@ public async Task GetAppMetadata_returns_AppMetadata_based_on_appId() Name = "app1" }); } - - [Fact] - public async Task FindInstances_returns_PayloadNull_error_as_no_request() - { - FindInstancesRequest? request = null; - - var result = await _fdc3.FindInstances(request); - - result.Should().NotBeNull(); - result.Error.Should().Be(Fdc3DesktopAgentErrors.PayloadNull); - } - - [Fact] - public async Task FindInstances_returns_MissingId_as_invalid_id() - { - var request = new FindInstancesRequest - { - AppIdentifier = new AppIdentifier - { - AppId = "appId1", - }, - Fdc3InstanceId = "notValidInstanceId", - }; - - var result = await _fdc3.FindInstances(request); - - result.Should().NotBeNull(); - result.Error.Should().Be(Fdc3DesktopAgentErrors.MissingId); - } - - [Fact] - public async Task FindInstances_returns_MissingId_error_as_no_instance_found_which_is_contained_by_the_container() - { - var request = new FindInstancesRequest - { - AppIdentifier = new AppIdentifier - { - AppId = "appId1", - }, - Fdc3InstanceId = Guid.NewGuid().ToString() - }; - - var result = await _fdc3.FindInstances(request); - - result.Should().NotBeNull(); - result.Error.Should().Be(Fdc3DesktopAgentErrors.MissingId); - } - - [Fact] - public async Task FindInstances_returns_NoAppsFound_error_as_no_appId_found() - { - await _fdc3.StartAsync(CancellationToken.None); - - //TODO: should add some identifier to the query => "fdc3:" + instance.Manifest.Id - var origin = await _mockModuleLoader.Object.StartModule(new StartRequest("appId1")); - var originFdc3InstanceId = Fdc3InstanceIdRetriever.Get(origin); - - var request = new FindInstancesRequest - { - AppIdentifier = new AppIdentifier - { - AppId = "noAppId", - }, - Fdc3InstanceId = originFdc3InstanceId - }; - - var result = await _fdc3.FindInstances(request); - - result.Should().NotBeNull(); - result.Error.Should().Be(ResolveError.NoAppsFound); - - await _mockModuleLoader.Object.StopModule(new(origin.InstanceId)); - } - - [Fact] - public async Task FindInstances_succeeds_with_one_app() - { - await _fdc3.StartAsync(CancellationToken.None); - - //TODO: should add some identifier to the query => "fdc3:" + instance.Manifest.Id - var origin = await _mockModuleLoader.Object.StartModule(new StartRequest("appId1")); - var originFdc3InstanceId = Fdc3InstanceIdRetriever.Get(origin); - - var request = new FindInstancesRequest - { - AppIdentifier = new AppIdentifier - { - AppId = "appId1", - }, - Fdc3InstanceId = originFdc3InstanceId - }; - - var result = await _fdc3.FindInstances(request); - - result.Should().NotBeNull(); - result.Instances.Should().HaveCount(1); - result.Instances!.ElementAt(0).InstanceId.Should().Be(originFdc3InstanceId); - - await _mockModuleLoader.Object.StopModule(new(origin.InstanceId)); - } - - [Fact] - public async Task FindInstances_succeeds_with_empty_array() - { - await _fdc3.StartAsync(CancellationToken.None); - - //TODO: should add some identifier to the query => "fdc3:" + instance.Manifest.Id - var origin = await _mockModuleLoader.Object.StartModule(new StartRequest("appId1")); - var originFdc3InstanceId = Fdc3InstanceIdRetriever.Get(origin); - - var request = new FindInstancesRequest - { - AppIdentifier = new AppIdentifier - { - AppId = "appId2", - }, - Fdc3InstanceId = originFdc3InstanceId - }; - - var result = await _fdc3.FindInstances(request); - - result.Should().NotBeNull(); - result.Instances.Should().HaveCount(0); - result.Error.Should().BeNull(); - - await _mockModuleLoader.Object.StopModule(new(origin.InstanceId)); - } - - [Fact] - public async Task GetAppMetadata_returns_PayLoadNull_error_as_request_null() - { - GetAppMetadataRequest? request = null; - - var result = await _fdc3.GetAppMetadata(request); - - result.Should().NotBeNull(); - result.Error.Should().Be(Fdc3DesktopAgentErrors.PayloadNull); - } - - [Fact] - public async Task GetAppMetadata_returns_MissingId_error_as_initiator_id_not_found() - { - var request = new GetAppMetadataRequest - { - AppIdentifier = new AppIdentifier - { - AppId = "appId1", - }, - Fdc3InstanceId = Guid.NewGuid().ToString(), - }; - - var result = await _fdc3.GetAppMetadata(request); - - result.Should().NotBeNull(); - result.Error.Should().Be(Fdc3DesktopAgentErrors.MissingId); - } - - [Fact] - public async Task GetAppMetadata_returns_MissingId_error_as_the_searched_instanceId_not_valid() - { - await _fdc3.StartAsync(CancellationToken.None); - - //TODO: should add some identifier to the query => "fdc3:" + instance.Manifest.Id - var origin = await _mockModuleLoader.Object.StartModule(new StartRequest("appId1")); - var originFdc3InstanceId = Fdc3InstanceIdRetriever.Get(origin); - - var request = new GetAppMetadataRequest - { - AppIdentifier = new AppIdentifier - { - AppId = "appId1", - InstanceId = "notValidInstanceId" - }, - Fdc3InstanceId = originFdc3InstanceId, - }; - - var result = await _fdc3.GetAppMetadata(request); - - result.Should().NotBeNull(); - result.Error.Should().Be(Fdc3DesktopAgentErrors.MissingId); - - await _mockModuleLoader.Object.StopModule(new(origin.InstanceId)); - } - - [Fact] - public async Task GetAppMetadata_returns_TargetInstanceUnavailable_error_as_the_searched_instanceId_not_found() - { - await _fdc3.StartAsync(CancellationToken.None); - - //TODO: should add some identifier to the query => "fdc3:" + instance.Manifest.Id - var origin = await _mockModuleLoader.Object.StartModule(new StartRequest("appId1")); - var originFdc3InstanceId = Fdc3InstanceIdRetriever.Get(origin); - - var request = new GetAppMetadataRequest - { - AppIdentifier = new AppIdentifier - { - AppId = "appId1", - InstanceId = Guid.NewGuid().ToString() - }, - Fdc3InstanceId = originFdc3InstanceId, - }; - - var result = await _fdc3.GetAppMetadata(request); - - result.Should().NotBeNull(); - result.Error.Should().Be(ResolveError.TargetInstanceUnavailable); - - await _mockModuleLoader.Object.StopModule(new(origin.InstanceId)); - } - - [Fact] - public async Task GetAppMetadata_returns_AppMetadata_based_on_instanceId() - { - await _fdc3.StartAsync(CancellationToken.None); - - //TODO: should add some identifier to the query => "fdc3:" + instance.Manifest.Id - var origin = await _mockModuleLoader.Object.StartModule(new StartRequest("appId1")); - var originFdc3InstanceId = Fdc3InstanceIdRetriever.Get(origin); - - var request = new GetAppMetadataRequest - { - AppIdentifier = new AppIdentifier - { - AppId = "appId1", - InstanceId = originFdc3InstanceId - }, - Fdc3InstanceId = originFdc3InstanceId, - }; - - var result = await _fdc3.GetAppMetadata(request); - - result.Error.Should().BeNull(); - result.AppMetadata.Should().BeEquivalentTo( - new AppMetadata() - { - AppId = "appId1", - InstanceId = originFdc3InstanceId, - Name = "app1" - }); - - await _mockModuleLoader.Object.StopModule(new(origin.InstanceId)); - } - - [Fact] - public async Task GetAppMetadata_returns_TargetAppUnavailable_error_as_the_searched_appId_not_found() - { - await _fdc3.StartAsync(CancellationToken.None); - - //TODO: should add some identifier to the query => "fdc3:" + instance.Manifest.Id - var origin = await _mockModuleLoader.Object.StartModule(new StartRequest("appId1")); - var originFdc3InstanceId = Fdc3InstanceIdRetriever.Get(origin); - - var request = new GetAppMetadataRequest - { - AppIdentifier = new AppIdentifier - { - AppId = "notExistentAppId", - }, - Fdc3InstanceId = originFdc3InstanceId, - }; - - var result = await _fdc3.GetAppMetadata(request); - - result.Error.Should().NotBeNull(); - result.Error.Should().Be(ResolveError.TargetAppUnavailable); - - await _mockModuleLoader.Object.StopModule(new(origin.InstanceId)); - } - - [Fact] - public async Task GetAppMetadata_returns_AppMetadata_based_on_appId() - { - await _fdc3.StartAsync(CancellationToken.None); - - //TODO: should add some identifier to the query => "fdc3:" + instance.Manifest.Id - var origin = await _mockModuleLoader.Object.StartModule(new StartRequest("appId1")); - var originFdc3InstanceId = Fdc3InstanceIdRetriever.Get(origin); - - var request = new GetAppMetadataRequest - { - AppIdentifier = new AppIdentifier - { - AppId = "appId1", - }, - Fdc3InstanceId = originFdc3InstanceId, - }; - - var result = await _fdc3.GetAppMetadata(request); - - result.Error.Should().BeNull(); - result.AppMetadata.Should().BeEquivalentTo( - new AppMetadata() - { - AppId = "appId1", - Name = "app1" - }); - - await _mockModuleLoader.Object.StopModule(new(origin.InstanceId)); - } } \ No newline at end of file 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 ae34ff0c4..68a22f6c6 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 @@ -1105,7 +1105,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); 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/fdc3/js/composeui-fdc3/src/infrastructure/ComposeUIChannel.ts b/src/fdc3/js/composeui-fdc3/src/infrastructure/ComposeUIChannel.ts index e8bd0e6ad..fe2dbfbcf 100644 --- a/src/fdc3/js/composeui-fdc3/src/infrastructure/ComposeUIChannel.ts +++ b/src/fdc3/js/composeui-fdc3/src/infrastructure/ComposeUIChannel.ts @@ -40,7 +40,6 @@ export class ComposeUIChannel implements Channel { this.lastContexts.set(context.type, context); this.lastContext = context; const topic = ComposeUITopic.broadcast(this.id, this.type); - console.log("Broadcast from channel: ", this.id, this.type, topic, context); await this.messageRouterClient.publish(topic, JSON.stringify(context)); } @@ -80,7 +79,6 @@ export class ComposeUIChannel implements Channel { const listener = new ComposeUIContextListener(this.messageRouterClient, handler, this.id, this.type, contextType); await listener.subscribe(); - console.log("ContextListener has been added through channel:", contextType); return listener; } } \ No newline at end of file diff --git a/src/fdc3/js/composeui-fdc3/src/infrastructure/ComposeUIContextListener.ts b/src/fdc3/js/composeui-fdc3/src/infrastructure/ComposeUIContextListener.ts index 2a1dbccd1..8e7a38c67 100644 --- a/src/fdc3/js/composeui-fdc3/src/infrastructure/ComposeUIContextListener.ts +++ b/src/fdc3/js/composeui-fdc3/src/infrastructure/ComposeUIContextListener.ts @@ -44,7 +44,6 @@ export class ComposeUIContextListener implements Listener { //TODO: integration test const context = JSON.parse(topicMessage.payload!); if (!this.contextType || this.contextType == context!.type) { - console.log("ContextListener received context to handle: ", context); this.handler!(context!); } }); diff --git a/src/fdc3/js/composeui-fdc3/src/infrastructure/ComposeUIIntentListener.ts b/src/fdc3/js/composeui-fdc3/src/infrastructure/ComposeUIIntentListener.ts index b2593dcf4..70f8df194 100644 --- a/src/fdc3/js/composeui-fdc3/src/infrastructure/ComposeUIIntentListener.ts +++ b/src/fdc3/js/composeui-fdc3/src/infrastructure/ComposeUIIntentListener.ts @@ -67,7 +67,6 @@ export class ComposeUIIntentListener implements Listener { request = new Fdc3StoreIntentResultRequest(message.messageId, this.intent, this.instanceId, message.contextMetadata.source.instanceId!, undefined, undefined, undefined, false, ResultError.IntentHandlerRejected); } - console.log("STORE INTENT RESULT REQUEST:", request); const result = await this.messageRouterClient.invoke(ComposeUITopic.sendIntentResult(), JSON.stringify(request)); if (!result) { return; 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/"