Skip to content

Commit

Permalink
Fixed compile errors in client package
Browse files Browse the repository at this point in the history
  • Loading branch information
robmoffat committed Mar 14, 2024
1 parent a21c8d1 commit ad7b304
Show file tree
Hide file tree
Showing 21 changed files with 851 additions and 214 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { AppIntent } from "@finos/fdc3";
import { IntentResolver, Messaging } from "da-proxy";
import { SingleAppIntent } from "da-proxy/src/intents/IntentResolver";

/**
* Works with the desktop agent to provide a resolution to the intent choices.
*/
export class DesktopAgentIntentResolver implements IntentResolver {

private readonly m: Messaging

constructor(m: Messaging) {
this.m = m
}

async chooseIntent(_appIntents: AppIntent[]): Promise<SingleAppIntent> {
throw new Error("Method not implemented.");
}

}
26 changes: 8 additions & 18 deletions packages/client/src/messaging/MessagePortMessaging.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
import { AppIdentifier } from "@finos/fdc3"
import { AgentRequestMessage } from "@finos/fdc3/dist/bridging/BridgingTypes"
import { Messaging } from "da-proxy"
import { AbstractMessaging } from "da-proxy"
import { RegisterableListener } from "da-proxy/src/listeners/RegisterableListener"
import { exchangePostMessage } from "fdc3-common"
import { v4 as uuidv4 } from "uuid"

type ListenerDetail = {
filter: (m: AgentRequestMessage) => boolean,
action: (m: AgentRequestMessage) => void
}

export class MessagePortMessaging implements Messaging {
export class MessagePortMessaging extends AbstractMessaging {

private readonly appId: AppIdentifier
private readonly mp: MessagePort
private readonly listeners : Map<string, ListenerDetail> = new Map()
private readonly listeners: Map<string, RegisterableListener> = new Map()

constructor(mp: MessagePort, appId: AppIdentifier) {
super()
this.appId = appId
this.mp = mp;

this.mp.onmessage = (m) => {
this.listeners.forEach((v, _k) => {
if (v.filter(m.data)) {
v.action(m.data)
}
}
})
}
}
Expand All @@ -40,14 +36,8 @@ export class MessagePortMessaging implements Messaging {
return Promise.resolve();
}

register(filter: (m: any) => boolean, action: (m: any) => void): string {
const id = this.createUUID();
this.listeners.set(id,{
filter,
action
})

return id;
register(l: RegisterableListener): void {
this.listeners.set(l.id, l)
}

unregister(id: string): void {
Expand Down
53 changes: 19 additions & 34 deletions packages/client/src/messaging/message-port.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
import { Context, DesktopAgent } from "@finos/fdc3";
import { BasicDesktopAgent, DefaultChannelSupport, DefaultAppSupport, DefaultIntentSupport, DefaultChannel } from "da";
import { DesktopAgent } from "@finos/fdc3";
import { BasicDesktopAgent, DefaultChannelSupport, DefaultAppSupport, DefaultIntentSupport, DefaultChannel, DefaultHandshakeSupport } from "da-proxy";
import { APIResponseMessage, FDC3_PORT_TRANSFER_RESPONSE_TYPE, FDC3_PORT_TRANSFER_REQUEST_TYPE, Options, exchangeForMessagePort, exchange } from "fdc3-common"
import { MessagePortMessaging } from "./MessagePortMessaging";
import { ConnectionStep2Hello, ConnectionStep3Handshake } from "@finos/fdc3/dist/bridging/BridgingTypes";
import { DesktopAgentIntentResolver } from "../intent-resolution/DesktopAgentIntentResolver";

/**
* Given a message port, constructs a desktop agent to communicate via that.
*/
export async function messagePortInit(mp: MessagePort, data: APIResponseMessage) : Promise<DesktopAgent> {
export async function messagePortInit(mp: MessagePort, data: APIResponseMessage): Promise<DesktopAgent> {
mp.start()

const handshakeData = (await exchange(mp, "handshake", () => sendHello(mp, data))).data as ConnectionStep3Handshake
const messaging = new MessagePortMessaging(mp, data.appIdentifier)
const channelState = handshakeData.payload.channelsState
const userChannelState = buildUserChannelState(messaging, channelState)
const userChannelState = buildUserChannelState(messaging)

return new BasicDesktopAgent(
new DefaultChannelSupport(messaging, userChannelState, null),
new DefaultIntentSupport(),
new DefaultAppSupport(messaging, data.appIdentifier),
data.fdc3Version,
data.provider);
const version = "2.0"
const cs = new DefaultChannelSupport(messaging, userChannelState, null)
const hs = new DefaultHandshakeSupport(messaging, [version], cs)
const is = new DefaultIntentSupport(messaging, new DesktopAgentIntentResolver(messaging))
const as = new DefaultAppSupport(messaging, data.appIdentifier, "WebFDC3")
const da = new BasicDesktopAgent(hs, cs, is, as, version)
return da
}

/**
Expand All @@ -30,16 +29,16 @@ export async function messagePortInit(mp: MessagePort, data: APIResponseMessage)
* It is up to the desktop agent to arrange communucation between other
* windows.
*/
export async function messagePortIFrameInit(data: APIResponseMessage, options: Options) : Promise<DesktopAgent> {
export async function messagePortIFrameInit(data: APIResponseMessage, options: Options): Promise<DesktopAgent> {

const action = data.uri ? () => {
return openFrame(data.uri!!);
} : () => {
return messageParentWindow(options.frame)
}

const mp = await exchangeForMessagePort(window, FDC3_PORT_TRANSFER_RESPONSE_TYPE, action) as MessagePort

return messagePortInit(mp, data);
}

Expand All @@ -58,7 +57,7 @@ function messageParentWindow(w: Window | undefined) {
/**
* The desktop agent requests that the client opens a URL in order to provide a message port.
*/
function openFrame(url: string) : Window {
function openFrame(url: string): Window {
var ifrm = document.createElement("iframe")
ifrm.setAttribute("src", url)
ifrm.setAttribute("name", "FDC3 Communications")
Expand All @@ -68,23 +67,9 @@ function openFrame(url: string) : Window {
return ifrm.contentWindow!!
}

function sendHello(mp: MessagePort, data: APIResponseMessage) {
const hello : ConnectionStep2Hello = {
type: "hello",
payload: {
desktopAgentBridgeVersion: data.desktopAgentBridgeVersion,
supportedFDC3Versions: data.supportedFDC3Versions,
authRequired: data.authRequired,
authToken: data.authToken
},
meta: {
timestamp: new Date()
}
}
mp.postMessage(hello);
}

function buildUserChannelState(messaging: MessagePortMessaging, _channelState: Record<string, Context[]>) {
function buildUserChannelState(messaging: MessagePortMessaging) {
// TODO: Figure out how to set initial user channels.
// Should probably be in the message from the server.
return [
new DefaultChannel(messaging, "one", "user", {
color: "red",
Expand Down
12 changes: 9 additions & 3 deletions packages/da-proxy/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,34 @@
import { BasicDesktopAgent } from "./BasicDesktopAgent";
import { Messaging } from "./Messaging";
import { AbstractMessaging } from "./messaging/AbstractMessaging";

import { DefaultChannel } from "./channels/DefaultChannel";
import { IntentSupport } from "./intents/IntentSupport";
import { ChannelSupport } from "./channels/ChannelSupport";

import { StatefulChannel } from "./channels/StatefulChannel";
import { DesktopAgentProvider } from "./DesktopAgentProvider";

import { DefaultIntentSupport } from "./intents/DefaultIntentSupport";
import { DefaultChannelSupport } from "./channels/DefaultChannelSupport";
import { IntentSupport } from "./intents/IntentSupport";
import { IntentResolver } from "./intents/IntentResolver";

import { DefaultAppSupport } from "./apps/DefaultAppSupport";
import { AppSupport } from "./apps/AppSupport";

import { HandshakeSupport } from "./handshake/HandshakeSupport";
import { DefaultHandshakeSupport } from "./handshake/DefaultHandshakeSupport";

import { DesktopAgentProvider } from "./DesktopAgentProvider";

export {
type Messaging,
AbstractMessaging,
BasicDesktopAgent,
DefaultChannel,
type StatefulChannel,
type AppSupport,
type IntentSupport,
type ChannelSupport,
type IntentResolver,
DefaultAppSupport,
DefaultChannelSupport,
DefaultIntentSupport,
Expand Down
2 changes: 1 addition & 1 deletion packages/da-proxy/src/intents/IntentResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export interface SingleAppIntent {

export interface IntentResolver {

chooseIntent(appIntents: AppIntent[]) : SingleAppIntent
chooseIntent(appIntents: AppIntent[]): Promise<SingleAppIntent>

}

2 changes: 1 addition & 1 deletion packages/da-proxy/test/step-definitions/generic.steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class SimpleIntentResolver implements IntentResolver {

cw: CustomWorld

chooseIntent(appIntents: AppIntent[]): SingleAppIntent {
async chooseIntent(appIntents: AppIntent[]): Promise<SingleAppIntent> {
const out = {
intent: appIntents[0].intent,
chosenApp: appIntents[0].apps[0]
Expand Down
10 changes: 0 additions & 10 deletions packages/da-server/src/directory/fdc3-2.1-json-directory.ts

This file was deleted.

9 changes: 7 additions & 2 deletions packages/da-server/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
{
"extends": "../../tsconfig.root.json",
"compilerOptions": {
"rootDirs": [ "src", "test", "generated" ],
"rootDirs": [
"src",
"test",
"generated"
],
"outDir": "dist",
},
"include": [
"src", "generated"
"src",
"generated",
],
"references": [
{
Expand Down
17 changes: 9 additions & 8 deletions packages/demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<title>Desktop Agent</title>
<meta charset="UTF-8" />
<script type="module" src="src/dummy-desktop-agent.ts"></script>
<!--<script type="module" src="src/dummy-desktop-agent.ts"></script> -->
</head>

<body>
Expand All @@ -22,24 +22,25 @@

<ul>
<li>
<a type="button" href="#" id="app1" >Open App 1 on MAIN HOST</a>
<a type="button" href="#" id="app1">Open App 1 on MAIN HOST</a>

<p><em>App will connect to the desktop agent and broadcast on the red channel when you hit the button</em></p>
<p><em>App will connect to the desktop agent and broadcast on the red channel when you hit the button</em>
</p>
</li>
<li>
<a type="button" href="#" id="app2" >Open App 2 on MAIN HOST</a>
<a type="button" href="#" id="app2">Open App 2 on MAIN HOST</a>

<p><em>App will connect to the desktop agent on startup and listen to messages on the red channel</em></p>

</li>
<li>
<a type="button" href="#" id="app3" >Open App 2 on SECOND HOST</a>
<a type="button" href="#" id="app3">Open App 2 on SECOND HOST</a>

<p><em>App will connect to the desktop agent on startup and listen to messages on the red channel</em></p>

</li>
<li>
<a type="button" href="#" id="app4" >Open App 3</a>
<a type="button" href="#" id="app4">Open App 3</a>

<p><em>App creates two APIs to the desktop agent, broadcasts in one and listens in the other.</em></p>
</li>
Expand Down
7 changes: 6 additions & 1 deletion packages/demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,16 @@
},
"dependencies": {
"@finos/fdc3": "^2.1.0-beta.4",
"@types/node": "^20.11.27",
"@types/uuid": "^9.0.7",
"@types/ws": "^8.5.10",
"client": "workspace:*",
"da-proxy": "workspace:*",
"da-server": "workspace:*",
"fdc3-common": "workspace:*",
"uuid": "^9.0.1"
"uuid": "^9.0.1",
"vite-plugin-mix": "^0.4.0",
"ws": "^8.16.0"
},
"references": [
{
Expand Down
13 changes: 13 additions & 0 deletions packages/demo/src/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { WebSocketServer } from 'ws';

const wss = new WebSocketServer();

wss.on('connection', function connection(ws) {
ws.on('error', console.error);

ws.on('message', function message(data) {
console.log('received: %s', data);
});

ws.send('something');
});
36 changes: 36 additions & 0 deletions packages/demo/src/server/FDC3_2_1_JSONDirectory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { BasicDirectory } from "da-server/src/directory/BasicDirectory";
import { DirectoryApp } from "da-server/src/directory/DirectoryInterface";
import { readFile } from 'fs/promises';

function loadRemotely(u: string) {
return fetch(u).then((response) => response.json());
}

function loadLocally(u: string) {
return readFile(u)
.then((buf) => buf.toString('utf8'))
.then((data) => JSON.parse(data));
}

async function load(url: string): Promise<DirectoryApp[]> {
if (url.startsWith('http')) {
return await loadRemotely(url).then(convertToDirectoryList);
} else {
return await loadLocally(url).then(convertToDirectoryList);
}
}
const convertToDirectoryList = (data: any) => {
return data.applications as DirectoryApp[];
}

export class FDC3_2_1_JSONDirectory extends BasicDirectory {

constructor() {
super([])
}

async load(url: string) {
this.allApps = await load(url);
}

}
Loading

0 comments on commit ad7b304

Please sign in to comment.