Skip to content

Commit

Permalink
Merge pull request finos#4 from finos-labs/rob-first-version
Browse files Browse the repository at this point in the history
Rob first version
  • Loading branch information
robmoffat authored Jul 1, 2023
2 parents e9e3b0a + 4a4148e commit 02180a5
Show file tree
Hide file tree
Showing 11 changed files with 99 additions and 53 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ This is a minimal proof-of-concept for FDC3 For the Web.
2. Point browser at http://localhost:5000/static/da/
3. This is your dummy desktop agent, which has two apps you can launch:
3. This is your dummy desktop agent, which has three apps you can launch:
- App1 Can Broadcast via FDC3.
- App2 Listens.
- App3 is the use case where an app has two separate APIs and uses them for intra-app comms.
4. Launch the apps, press the button, watch messages pass between them.
Expand Down
7 changes: 7 additions & 0 deletions src/demo/app3.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import './app1'
import './app2'

/**
* This demonstrates getting two separate APIs in the same app, and using them for
* intra-app comms.
*/
30 changes: 19 additions & 11 deletions src/demo/dummy-desktop-agent.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,59 @@
import { AppIdentifier } from "@finos/fdc3";
import { supply } from "../lib/webc3";
import { AppIdentifierResolver } from "../lib/types";
import { AppIdentifierResolver, DesktopAgentDetailResolver } from "../lib/types";


window.addEventListener("load", () => {

let currentInstance = 0;
let currentApiInstance = 0;

type AppIdentifierAndWindow = AppIdentifier & { window: Window, url: string }

const instances : { [key: string] : AppIdentifierAndWindow } = {}
const instances : AppIdentifierAndWindow[] = []

function launch(url: string, appId: string) {
const w : Window = window.open(url, "_blank")!!;
const instance = currentInstance++;
w.name = "App"+instance;
instances[w.name] = {
instances.push({
appId,
instanceId: ""+instance,
window: w,
url: w.location.href
}
})
}

// for a given window, allows us to determine which app it is (if any)
const appIdentifierResolver : AppIdentifierResolver = o => instances[o.name];
const appIdentifierResolver : AppIdentifierResolver = o => instances.find(i => i.window ==o);
const daDetailResolver : DesktopAgentDetailResolver = () => {
return {
apiId : currentApiInstance++,
key: "Abc"
}
}

// set up desktop agent handler here using FDC3 Web Loader (or whatever we call it)
supply("/src/demo/implementation.js", appIdentifierResolver);
supply("/src/demo/implementation.js", appIdentifierResolver, daDetailResolver);

// hook up the buttons
document.getElementById("app1")?.addEventListener("click", () => launch("/static/app1/index.html", "1"));
document.getElementById("app2")?.addEventListener("click", () => launch("/static/app2/index.html", "2"));
document.getElementById("app3")?.addEventListener("click", () => launch("/static/app3/index.html", "3"));


// allow apps opened by this desktop agent to broadcast to each other
// implementation of broadcast, desktop-agent side
window.addEventListener(
"message",
(event) => {
const data = event.data;
if (data.type == "Broadcast") {
const origin = event.origin;
const source = event.source as Window
console.log(`Broadcast Origin: ${origin} Source: ${source} `);
console.log(`Broadcast Origin: ${origin} Source: ${source} From ${JSON.stringify(data.from)}`);
const appIdentifier = appIdentifierResolver(source);
if (appIdentifier != null) {
Object.values(instances)
.filter(i => i.window != source)
if (appIdentifier != undefined) {
instances
.forEach(i => {
i.window.postMessage(data, "*")
})
Expand Down
13 changes: 9 additions & 4 deletions src/demo/implementation.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@

/**
* This dummy desktop agent just implements broadcast and addContextListener for the
* purposes of the demo. Communication is also via post-message.
*/
class DummyDesktopAgent {

constructor(id, details) {
this.id = id;
this.details = details;
}

broadcast(context) {
console.log("Broadcasting: "+JSON.stringify(context))
window.opener.postMessage({
type: "Broadcast",
context: context
context: context,
from: this.id
}, "*") // in a real desktop agent, don't use *
}

Expand All @@ -31,6 +36,6 @@ class DummyDesktopAgent {
}
}

export default (id) => {
return new DummyDesktopAgent();
export default (id, details) => {
return new DummyDesktopAgent(id, details);
}
8 changes: 4 additions & 4 deletions src/lib/loaders/load-with-import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { APIResponseMessage, FDC3Initialiser } from "../types";
/**
* This loads the script using an import
*/
export function load(resolve: (da: DesktopAgent) => void, data: APIResponseMessage) {
import(data.url).then(ns => {
export function load(data: APIResponseMessage) : Promise<DesktopAgent> {
return import(/* @vite-ignore */ data.url).then(ns => {
const init = ns.default as FDC3Initialiser;
const da = init(data.appIdentifier);
resolve(da);
const da = init(data.appIdentifier, data.daDetails);
return da;
})
}
16 changes: 0 additions & 16 deletions src/lib/loaders/load-with-script.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AppIdentifier, DesktopAgent} from '@finos/fdc3'
import { APIResponseMessage, AppIdentifierResolver, Strategy } from '../types'
import { APIResponseMessage, AppIdentifierResolver, DesktopAgentDetailResolver, Options, Strategy } from '../types'
import { load } from '../loaders/load-with-import';

const FDC3_API_REQUEST_MESSAGE_TYPE = 'FDC3-API-Request';
Expand All @@ -8,15 +8,16 @@ const FDC3_API_RESPONSE_MESSAGE_TYPE = 'FDC3-API-Response';

export const strategy : Strategy = {

supply : (url: string, resolver: AppIdentifierResolver) => {
supply : (url: string, resolver: AppIdentifierResolver, detailsResolver: DesktopAgentDetailResolver) => {
function createResponseMessage(appIdentifier: AppIdentifier) : APIResponseMessage {
return {
type: FDC3_API_RESPONSE_MESSAGE_TYPE,
url,
appIdentifier : {
appId: appIdentifier.appId,
instanceId: appIdentifier.instanceId
}
},
daDetails: detailsResolver(appIdentifier)
}
}
window.addEventListener(
Expand All @@ -36,14 +37,20 @@ export const strategy : Strategy = {
});
},

load : (options: any) => {
load : (options: Options) => {

function handleOptions(da: DesktopAgent) {
return da;
}

const out = new Promise<DesktopAgent>((resolve, reject) => {
// setup listener for message and retrieve JS URL from it
window.addEventListener("message", (event) => {
const data : APIResponseMessage = event.data ;
if (data.type == FDC3_API_RESPONSE_MESSAGE_TYPE) {
load(resolve, data);
load(data)
.then(da => handleOptions(da))
.then(da => resolve(da))
} else {
reject("Incorrect API Response Message");
}
Expand Down
18 changes: 13 additions & 5 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,33 @@ export const DEFAULT_OPTIONS : Options = {
setWindowGlobal: false
}

export type AppIdentifierResolver = (o: Window) => AppIdentifier;

export type AppIdentifierResolver = (o: Window) => AppIdentifier | undefined;

export type Strategy = {
supply: (url: string, resolver: AppIdentifierResolver) => void
supply: (url: string, idResolver: AppIdentifierResolver, detailsResolver: DesktopAgentDetailResolver) => void
load: (options: Options) => Promise<DesktopAgent>
}

/**
* These are details such as login information sent from the desktop back to the
* app in order to initialise the api.
*/
export type DesktopAgentDetails = { [key: string] : string | number | boolean }

export type DesktopAgentDetailResolver = (a: AppIdentifier) => DesktopAgentDetails

/**
* When writing an FDC3 implementation, this is the shape of the function
* that should be returned by the DesktopAgent's supply url.
*/
export type FDC3Initialiser = (id: AppIdentifier) => DesktopAgent
export type FDC3Initialiser = (id: AppIdentifier, daDetails: DesktopAgentDetails) => DesktopAgent

/**
* This is the object that the desktop agent must get back to the App.
*/
export type APIResponseMessage = {
type: string,
url: string,
appIdentifier: AppIdentifier
appIdentifier: AppIdentifier,
daDetails: DesktopAgentDetails
}
22 changes: 17 additions & 5 deletions src/lib/webc3.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
import { DesktopAgent} from '@finos/fdc3'
import { strategy } from './strategies/post-message'
import { AppIdentifierResolver, DEFAULT_OPTIONS, Options } from './types';
import { strategy } from './strategies/post-message-load-js'
import { AppIdentifierResolver, DEFAULT_OPTIONS, DesktopAgentDetailResolver, Options } from './types';

/**
* This configures the postMessage listener to respond to requests for desktop agent APIs.
* Called by the desktop agent
*/
export function supply(url: string, resolver: AppIdentifierResolver) {
strategy.supply(url, resolver);
export function supply(url: string, appIdResolver: AppIdentifierResolver, detailsResolver: DesktopAgentDetailResolver) {
strategy.supply(url, appIdResolver, detailsResolver);
}


/**
* This return an FDC3 API. Called by Apps.
*/
export function load(options: Options = DEFAULT_OPTIONS) : Promise<DesktopAgent> {
return strategy.load(options);

function handleGenericOptions(da: DesktopAgent) {
if ((options.setWindowGlobal) && (window.fdc3 == null)) {
window.fdc3 = da;
}

return da;
}

return strategy
.load(options)
.then(da => handleGenericOptions(da))
}
15 changes: 15 additions & 0 deletions static/app3/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<html lang="en">

<head>
<title>App 3</title>
<meta charset="UTF-8" />
<script type="module" src="/src/demo/app3.ts"></script>
</head>

<body>
<p>FDC3 For the Web App3</p>
<button id="broadcast">Press Me To Broadcast</button>
<div id="log"></div>
</body>

</html>
3 changes: 1 addition & 2 deletions static/da/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@

<a type="button" href="#" id="app2" >Open App 2</a>

<div id="log"></div>

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

</body>

Expand Down

0 comments on commit 02180a5

Please sign in to comment.