Skip to content

Commit

Permalink
Added proxy handshake support
Browse files Browse the repository at this point in the history
  • Loading branch information
robmoffat committed Mar 11, 2024
1 parent 75bbfe2 commit c831ff0
Show file tree
Hide file tree
Showing 30 changed files with 504 additions and 227 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,7 @@ Desktop Agent Briding needs extending with the following types:
## Troubleshooting
- Try removing tsconfig.tsbuildinfo files if you are having trouble building
## Issues To Resolve
- How does the da-server tell the da-proxy about the channel metadata?
36 changes: 23 additions & 13 deletions packages/da-proxy/src/BasicDesktopAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,34 @@ import { AppIdentifier, AppMetadata, Context, ContextHandler, DesktopAgent, Impl
import { ChannelSupport } from "./channels/ChannelSupport";
import { AppSupport } from "./apps/AppSupport";
import { IntentSupport } from "./intents/IntentSupport";
import { HandshakeSupport } from "./handshake/HandshakeSupport";
import { Connectable } from "./Connectable";

/**
* This splits out the functionality of the desktop agent into
* app, channels and intents concerns.
*/
export class BasicDesktopAgent implements DesktopAgent {
export class BasicDesktopAgent implements DesktopAgent, Connectable {

readonly handshake: HandshakeSupport
readonly channels: ChannelSupport
readonly intents: IntentSupport
readonly apps: AppSupport
readonly fdc3Version: string
readonly provider: string

constructor(channels: ChannelSupport, intents: IntentSupport, apps: AppSupport, fdc3Version: string, provider: string) {
constructor(handshake: HandshakeSupport, channels: ChannelSupport, intents: IntentSupport, apps: AppSupport, fdc3Version: string) {
this.handshake = handshake
this.intents = intents
this.channels = channels
this.apps = apps
this.fdc3Version = fdc3Version
this.provider = provider
}
}

async getInfo() : Promise<ImplementationMetadata>{
async getInfo(): Promise<ImplementationMetadata> {
const am = await this.apps.getThisAppMetadata()
return {
fdc3Version: this.fdc3Version,
provider: this.provider,
provider: this.handshake.getHandshakePayload()?.implementationMetadata.provider ?? "undefined",
appMetadata: am,
optionalFeatures: {
OriginatingAppMetadata: this.apps.hasOriginatingAppMetadata(),
Expand Down Expand Up @@ -55,7 +57,7 @@ export class BasicDesktopAgent implements DesktopAgent {
getUserChannels() {
return this.channels.getUserChannels()
}

getSystemChannels() {
return this.channels.getUserChannels()
}
Expand All @@ -71,19 +73,19 @@ export class BasicDesktopAgent implements DesktopAgent {
leaveCurrentChannel() {
return this.channels.leaveUserChannel()
}

joinUserChannel(channelId: string) {
return this.channels.joinUserChannel(channelId)
}

joinChannel(channelId: string) {
return this.channels.joinUserChannel(channelId)
}

getCurrentChannel() {
return this.channels.getUserChannel();
}

findIntent(intent: string, context: Context, resultType: string | undefined) {
return this.intents.findIntent(intent, context, resultType)
}
Expand All @@ -92,7 +94,7 @@ export class BasicDesktopAgent implements DesktopAgent {
return this.intents.findIntentsByContext(context)
}

private ensureAppId(app?: any) : AppIdentifier | undefined {
private ensureAppId(app?: any): AppIdentifier | undefined {
if (typeof app === "string") {
return {
appId: app
Expand All @@ -107,7 +109,7 @@ export class BasicDesktopAgent implements DesktopAgent {
raiseIntent(intent: string, context: Context, app?: any) {
return this.intents.raiseIntent(intent, context, this.ensureAppId(app))
}

addIntentListener(intent: string, handler: IntentHandler) {
return this.intents.addIntentListener(intent, handler)
}
Expand All @@ -128,4 +130,12 @@ export class BasicDesktopAgent implements DesktopAgent {
return this.apps.getAppMetadata(app);
}

disconnect(): Promise<void> {
return this.handshake.disconnect()
}

connect(): Promise<void> {
return this.handshake.connect()
}

}
6 changes: 6 additions & 0 deletions packages/da-proxy/src/Connectable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface Connectable {

connect(): Promise<void>

disconnect(): Promise<void>
}
20 changes: 10 additions & 10 deletions packages/da-proxy/src/Messaging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,38 +7,38 @@ export interface Messaging {
* Source for outgoing message
*/
getSource(): AppIdentifier
/**
* UUID for outgoing message
*/

/**
* UUID for outgoing message
*/
createUUID(): string;

/**
* Post an outgoing message
*/
post(message: object) : Promise<void>
post(message: object): Promise<void>

/**
* Registers a listener for incoming messages.
*/
register(l: RegisterableListener) : void
register(l: RegisterableListener): void

/**
* Unregisters a listener with the id given above
* @param id
*/
unregister(id: string) : void
unregister(id: string): void

createMeta() : object
createMeta(): object

/**
* Waits for a specific matching message
*/
waitFor<X>(filter: (m: any) => boolean) : Promise<X>
waitFor<X>(filter: (m: any) => boolean): Promise<X>

/**
*
* @param message Performs a request / response message pass
*/
exchange<X>(message: object, expectedTypeName: string) : Promise<X>
exchange<X>(message: object, expectedTypeName: string): Promise<X>
}
17 changes: 10 additions & 7 deletions packages/da-proxy/src/channels/ChannelSupport.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import { Channel, ContextHandler, Listener, PrivateChannel } from "@finos/fdc3"
import { ContextElement } from "@finos/fdc3/dist/bridging/BridgingTypes"

export interface ChannelSupport {

hasUserChannelMembershipAPIs(): boolean

getUserChannel() : Promise<Channel | null>
getUserChannel(): Promise<Channel | null>

getUserChannels() : Promise<Channel[]>
getUserChannels(): Promise<Channel[]>

getOrCreate(id: string) : Promise<Channel>
getOrCreate(id: string): Promise<Channel>

createPrivateChannel() : Promise<PrivateChannel>
createPrivateChannel(): Promise<PrivateChannel>

leaveUserChannel() : Promise<void>
leaveUserChannel(): Promise<void>

joinUserChannel(id: string) : Promise<void>
joinUserChannel(id: string): Promise<void>

addContextListener(handler: ContextHandler, type: string | null) : Promise<Listener>
addContextListener(handler: ContextHandler, type: string | null): Promise<Listener>

mergeChannelState(newState: { [key: string]: ContextElement[] }): void

}
34 changes: 24 additions & 10 deletions packages/da-proxy/src/channels/DefaultChannelSupport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { DefaultPrivateChannel } from "./DefaultPrivateChannel";
import { DefaultChannel } from "./DefaultChannel";
import { StatefulChannel } from "./StatefulChannel";
import { DefaultContextListener } from "../listeners/DefaultContextListener";
import { ContextElement } from "@finos/fdc3/dist/bridging/BridgingTypes";

export class DefaultChannelSupport implements ChannelSupport {

Expand All @@ -19,35 +20,48 @@ export class DefaultChannelSupport implements ChannelSupport {
this.userChannel = userChannelState.find(c => c.id == initialChannelId) ?? null;
}

mergeChannelState(newState: { [key: string]: ContextElement[]; }): void {
this.userChannel = null
this.userChannelState.forEach(uc => {
const incoming = newState[uc.id] ?? []
incoming.forEach((context) => {
const existing = uc.getState()
if (!existing.get(context.type)) {
existing.set(context.type, context)
}
});
})
}

hasUserChannelMembershipAPIs(): boolean {
return true
}
getUserChannel() : Promise<Channel | null> {

getUserChannel(): Promise<Channel | null> {
return Promise.resolve(this.userChannel);
}

getUserChannels() : Promise<Channel[]> {
getUserChannels(): Promise<Channel[]> {
return Promise.resolve(this.userChannelState);
}

getDisplayMetadata(_id: string) : DisplayMetadata {
getDisplayMetadata(_id: string): DisplayMetadata {
return {

}
}

getOrCreate(id: string) : Promise<Channel> {
getOrCreate(id: string): Promise<Channel> {
const out = new DefaultChannel(this.messaging, id, "app", this.getDisplayMetadata(id))
return Promise.resolve(out)
}

createPrivateChannel() : Promise<PrivateChannel> {
createPrivateChannel(): Promise<PrivateChannel> {
const out = new DefaultPrivateChannel(this.messaging, this.messaging.createUUID())
return Promise.resolve(out);
}

leaveUserChannel() : Promise<void> {
leaveUserChannel(): Promise<void> {
this.userChannel = null;
this.userChannelListeners.forEach(
l => l.updateUnderlyingChannel(null, new Map())
Expand All @@ -57,7 +71,7 @@ export class DefaultChannelSupport implements ChannelSupport {

joinUserChannel(id: string) {
if (this.userChannel?.id != id) {
const newUserChannel = this.userChannelState.find(c => c.id == id)
const newUserChannel = this.userChannelState.find(c => c.id == id)
if (newUserChannel) {
this.userChannel = newUserChannel;
this.userChannelListeners.forEach(
Expand All @@ -80,5 +94,5 @@ export class DefaultChannelSupport implements ChannelSupport {
return Promise.resolve(listener);
}


}
48 changes: 48 additions & 0 deletions packages/da-proxy/src/handshake/DefaultHandshakeSupport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { ConnectionStep2Hello, ConnectionStep3Handshake, ConnectionStep3HandshakePayload } from "@finos/fdc3/dist/bridging/BridgingTypes";
import { Messaging } from "../Messaging";
import { ChannelSupport } from "../channels/ChannelSupport";
import { HandshakeSupport } from "./HandshakeSupport";

/**
* This will eventually need extending to allow for auth handshaking.
*/
export class DefaultHandshakeSupport implements HandshakeSupport {

readonly messaging: Messaging
readonly acceptableFDC3Versions: string[]
readonly channels: ChannelSupport
private handshakePayload: ConnectionStep3HandshakePayload | null = null

constructor(messaging: Messaging, acceptableFDC3Versions: string[], cs: ChannelSupport) {
this.messaging = messaging
this.acceptableFDC3Versions = acceptableFDC3Versions
this.channels = cs
}

async connect(): Promise<void> {
const hello: ConnectionStep2Hello = {
type: "hello",
payload: {
desktopAgentBridgeVersion: "1.0",
supportedFDC3Versions: this.acceptableFDC3Versions,
authRequired: false,
},
meta: {
timestamp: new Date()
}
}

const handshake = await this.messaging.exchange<ConnectionStep3Handshake>(hello, "handshake")
this.channels.mergeChannelState(handshake.payload.channelsState)
this.handshakePayload = handshake.payload
return Promise.resolve()
}

disconnect(): Promise<void> {
throw new Error("Method not implemented.");
}

getHandshakePayload(): ConnectionStep3HandshakePayload | null {
return this.handshakePayload
}
}
12 changes: 12 additions & 0 deletions packages/da-proxy/src/handshake/HandshakeSupport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { ConnectionStep3HandshakePayload } from "@finos/fdc3/dist/bridging/BridgingTypes"
import { Connectable } from "../Connectable"

/**
* Handles messaging around connection and disconnection of the proxy
* to the server.
*/
export interface HandshakeSupport extends Connectable {

getHandshakePayload(): ConnectionStep3HandshakePayload | null

}
7 changes: 6 additions & 1 deletion packages/da-proxy/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import { DefaultChannelSupport } from "./channels/DefaultChannelSupport";
import { DefaultAppSupport } from "./apps/DefaultAppSupport";
import { AppSupport } from "./apps/AppSupport";

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

export {
type Messaging,
BasicDesktopAgent,
Expand All @@ -23,5 +26,7 @@ export {
DefaultAppSupport,
DefaultChannelSupport,
DefaultIntentSupport,
type DesktopAgentProvider
type DesktopAgentProvider,
type HandshakeSupport,
DefaultHandshakeSupport
}
14 changes: 7 additions & 7 deletions packages/da-proxy/src/listeners/DefaultIntentListener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,20 @@ export class DefaultIntentListener extends AbstractListener<IntentHandler> {
readonly intent: string

constructor(messaging: Messaging, intent: string, action: IntentHandler) {
super(messaging,
{ intent },
action,
"subscribeIntentListener",
super(messaging,
{ intent },
action,
"subscribeIntentListener", /** TODO : https://github.com/finos/FDC3/issues/1171 */
"unsubscribeIntentListener")

this.intent = intent
}

filter(m: any): boolean {
return (m.type == 'raiseIntentRequest') && (m.payload.intent == this.intent)
}
action(m: any) : void {

action(m: any): void {
this.handler(m.payload.context, {
source: m.meta.source
})
Expand Down
Loading

0 comments on commit c831ff0

Please sign in to comment.