Skip to content

Commit

Permalink
Both message port and iframe approaches working
Browse files Browse the repository at this point in the history
  • Loading branch information
robmoffat committed Mar 20, 2024
1 parent a8bf085 commit 1e9c3d5
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 68 deletions.
39 changes: 17 additions & 22 deletions packages/client/src/messaging/message-port.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
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 } from "fdc3-common"
import { APIResponseMessage, FDC3_PORT_TRANSFER_RESPONSE_TYPE, FDC3_PORT_TRANSFER_REQUEST_TYPE, Options, exchangeForMessagePort, APIResponseMessageParentWindow, APIResponseMessageIFrame } from "fdc3-common"
import { MessagePortMessaging } from "./MessagePortMessaging";
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, options: Options): Promise<DesktopAgent> {
export async function createDesktopAgentAPI(mp: MessagePort, data: APIResponseMessage, options: Options): Promise<DesktopAgent> {
mp.start()

const messaging = new MessagePortMessaging(mp, data.appIdentifier)
Expand All @@ -26,34 +26,29 @@ export async function messagePortInit(mp: MessagePort, data: APIResponseMessage,
}

/**
* Initialises the desktop agent by opening an iframe
* Initialises the desktop agent by opening an iframe or talking to the parent window.
* on the desktop agent host and communicating via a messsage port to it.
*
* 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 messagePortInit(event: MessageEvent, 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
if (event.ports[0]) {
return createDesktopAgentAPI(event.ports[0], event.data, options);
} else if ((event.data as APIResponseMessageIFrame).uri) {
const action = () => {
const iframeData = event.data as APIResponseMessageIFrame
return openFrame(iframeData.uri +
"?source=" + encodeURIComponent(JSON.stringify(iframeData.appIdentifier)) +
"&desktopAgentId=" + encodeURIComponent(iframeData.desktopAgentId));
}

return messagePortInit(mp, data, options);
}
const mp = await exchangeForMessagePort(window, FDC3_PORT_TRANSFER_RESPONSE_TYPE, action) as MessagePort
return createDesktopAgentAPI(mp, event.data, options);

/**
* If the desktop agent doesn't provide an opener URL, we message another iframe asking for the port.
*/
function messageParentWindow(w: Window | undefined) {
if (w) {
w.postMessage({
type: FDC3_PORT_TRANSFER_REQUEST_TYPE,
methods: 'post-message'
});
} else {
throw new Error(`Couldn't initialise message port with ${JSON.stringify(event)}`)
}
}

Expand Down
8 changes: 2 additions & 6 deletions packages/client/src/strategies/post-message.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DesktopAgent } from '@finos/fdc3'
import { APIResponseMessage, Loader, Options, FDC3_API_RESPONSE_MESSAGE_TYPE, FDC3_API_REQUEST_MESSAGE_TYPE } from 'fdc3-common'
import { messagePortIFrameInit, messagePortInit } from '../messaging/message-port';
import { messagePortInit } from '../messaging/message-port';

const loader: Loader = (options: Options) => {

Expand All @@ -9,11 +9,7 @@ const loader: Loader = (options: Options) => {
window.addEventListener("message", (event) => {
const data: APIResponseMessage = event.data;
if ((data.type == FDC3_API_RESPONSE_MESSAGE_TYPE) && (data.method == 'message-port')) {
if (event.ports.length == 1) {
return resolve(messagePortInit(event.ports[0], data, options));
} else if (data.uri) {
return resolve(messagePortIFrameInit(data, options))
}
return resolve(messagePortInit(event, options));
}

// need either a port or a uri
Expand Down
2 changes: 1 addition & 1 deletion packages/da-server/src/supply/post-message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const supply: Supplier = (
instanceId: appId.instanceId,
desktopAgent: appId.desktopAgent
}
}
} as APIResponseMessage
}

function createTransferrableArray(source: Window, appId: AppIdentifier): Transferable[] {
Expand Down
4 changes: 3 additions & 1 deletion packages/demo/src/client/da/DemoServerContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,14 @@ export class DemoServerContext implements ServerContext {
if (getApproach() == Approach.IFRAME) {
return {
apiKey,
uri: window.location.origin + "/static/embed.html",
uri: window.location.origin + "/static/da/embed.html",
desktopAgentId: this.desktopAgentUUID,
resolverUri: window.location.origin + "/static/da/intent-resolver.html"
}
} else {
return {
apiKey,
desktopAgentId: this.desktopAgentUUID,
resolverUri: window.location.origin + "/static/da/intent-resolver.html"
} as DesktopAgentDetails
}
Expand Down
35 changes: 19 additions & 16 deletions packages/demo/src/client/da/dummy-desktop-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,25 @@ import { v4 as uuid } from 'uuid'
import { DA_HELLO, FDC3_APP_EVENT } from "../../message-types";
import { DemoServerContext } from "./DemoServerContext";
import { FDC3_2_1_JSONDirectory } from "./FDC3_2_1_JSONDirectory";
import { DefaultFDC3Server } from "da-server";
import { createAppStartButton } from "./util";

import { DefaultFDC3Server, DirectoryApp, ServerContext } from "da-server";



function createAppStartButton(app: DirectoryApp, sc: ServerContext): HTMLDivElement {
const div = document.createElement("div") as HTMLDivElement
div.classList.add("app")
const h3 = document.createElement("h3")
h3.textContent = app.title
div.appendChild(h3)
const button = document.createElement("button")
button.textContent = "Start"
button.onclick = () => sc.open(app.appId)
div.appendChild(button)
const p = document.createElement("p")
p.textContent = app.description ?? ''
div.appendChild(p)
return div
}

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

Expand Down Expand Up @@ -34,19 +50,6 @@ window.addEventListener("load", () => {

// set up desktop agent handler here using FDC3 Web Loader (or whatever we call it)
supply(sc.appChecker, sc.detailsResolver, sc.portResolver)








})





})

34 changes: 33 additions & 1 deletion packages/demo/src/client/da/embed.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,53 @@
import { FDC3_PORT_TRANSFER_RESPONSE_TYPE } from "fdc3-common";
import { io } from "socket.io-client"
import { link } from "./util";
import { AppIdentifier } from "@finos/fdc3";
import { APP_HELLO } from "../../message-types";

const appWindow = window.parent;

function getQueryVariable(variable: string): string {
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split("=");
if (pair[0] == variable) {
return pair[1];
}
}

return ""
}

function getSource(): AppIdentifier {
const source = getQueryVariable("source")
const decoded = decodeURIComponent(source)
const object: AppIdentifier = JSON.parse(decoded)
return object
}

function getDeskopAgentId(): string {
const id = getQueryVariable("desktopAgentId")
return id
}


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

const socket = io()
const channel = new MessageChannel()
const source = getSource()
const desktopAgentUUID = getDeskopAgentId()

socket.on("connect", () => {

//link(socket, channel)
link(socket, channel, source)

// sned the other end of the channel to the app
appWindow.postMessage({
type: FDC3_PORT_TRANSFER_RESPONSE_TYPE,
}, "*", [channel.port1])

socket.emit(APP_HELLO, desktopAgentUUID, source)
})
})
17 changes: 0 additions & 17 deletions packages/demo/src/client/da/util.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Socket } from "socket.io-client"
import { FDC3_APP_EVENT, FDC3_DA_EVENT } from "../../message-types"
import { DirectoryApp, ServerContext } from "da-server"
import { AppMetadata } from "@finos/fdc3/dist/bridging/BridgingTypes"


Expand All @@ -15,19 +14,3 @@ export function link(socket: Socket, channel: MessageChannel, app: AppMetadata)
socket.emit(FDC3_APP_EVENT, event.data, app)
}
}

export function createAppStartButton(app: DirectoryApp, sc: ServerContext): HTMLDivElement {
const div = document.createElement("div") as HTMLDivElement
div.classList.add("app")
const h3 = document.createElement("h3")
h3.textContent = app.title
div.appendChild(h3)
const button = document.createElement("button")
button.textContent = "Start"
button.onclick = () => sc.open(app.appId)
div.appendChild(button)
const p = document.createElement("p")
p.textContent = app.description ?? ''
div.appendChild(p)
return div
}
2 changes: 1 addition & 1 deletion packages/demo/src/server/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ io.on('connection', (socket: Socket) => {
// message from app to da
console.log(JSON.stringify(data))

if (myInstance == null) {
if ((myInstance == null) && (data.type == 'intentResolutionChoice')) {
// message from app's intent resolver
myInstance = Array.from(instances.values()).find(cw => cw.apps.get(from.instanceId))
}
Expand Down
14 changes: 11 additions & 3 deletions packages/fdc3-common/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ export type DesktopAgentPortResolver = (o: Window, a: AppIdentifier) => MessageP
* agent is via the "message-port" approach. This may change in the future.
*/
export type APIResponseMessage = {
type: string,
type: "FDC3-API-Response",
method: "message-port",
uri?: string, /* Supplied when an embedded iframe should be loaded */
appIdentifier: AppIdentifier,
resolverUri: string
resolverUri: string,
desktopAgentId: string
// fdc3Version: string,
// supportedFDC3Versions: string[],
// desktopAgentBridgeVersion: string,
Expand All @@ -60,6 +60,14 @@ export type APIResponseMessage = {
// authToken?: string,
}

export type APIResponseMessageIFrame = APIResponseMessage & {
uri?: string, /* Supplied when an embedded iframe should be loaded */
}

export type APIResponseMessageParentWindow = APIResponseMessage & {
// tbd
}

export type APIRequestMessage = {
type: string,
methods: string[]
Expand Down

0 comments on commit 1e9c3d5

Please sign in to comment.