Skip to content

Commit

Permalink
Fixing open tests
Browse files Browse the repository at this point in the history
  • Loading branch information
robmoffat committed May 16, 2024
1 parent 047caa0 commit fd14134
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 42 deletions.
98 changes: 56 additions & 42 deletions packages/da-server/src/handlers/OpenHandler.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AppDestinationIdentifier, AppMetadata, BroadcastAgentRequest, FindInstancesAgentRequest, FindInstancesAgentResponse, GetAppMetadataAgentErrorResponse, GetAppMetadataAgentRequest, GetAppMetadataAgentResponse, GetAppMetadataAgentResponsePayload, OpenAgentErrorResponse, OpenAgentRequest, OpenAgentResponse, OpenAgentResponseMeta, OpenErrorMessage, PrivateChannelOnAddContextListenerAgentRequest } from "@finos/fdc3/dist/bridging/BridgingTypes";
import { AppDestinationIdentifier, AppMetadata, BroadcastAgentRequest, ConnectionStep2Hello, FindInstancesAgentRequest, FindInstancesAgentResponse, GetAppMetadataAgentErrorResponse, GetAppMetadataAgentRequest, GetAppMetadataAgentResponse, GetAppMetadataAgentResponsePayload, OpenAgentErrorResponse, OpenAgentRequest, OpenAgentResponse, OpenAgentResponseMeta, OpenErrorMessage, PrivateChannelOnAddContextListenerAgentRequest } from "@finos/fdc3/dist/bridging/BridgingTypes";
import { MessageHandler } from "../BasicFDC3Server";
import { ServerContext } from "../ServerContext";
import { Directory, DirectoryApp } from "../directory/DirectoryInterface";
Expand Down Expand Up @@ -29,14 +29,16 @@ function createReplyMeta(msg: any, sc: ServerContext): BasicMeta {
}
}

class PendingContext {
enum AppState { Opening, DeliveringContext, Done }

readonly context: ContextElement
class PendingApps {

readonly context: ContextElement | undefined
readonly source: AppMetadata
private resolved: boolean = false
state: AppState = AppState.Opening
private onSuccess: () => void

constructor(context: ContextElement, source: AppMetadata,
constructor(context: ContextElement | undefined, source: AppMetadata,
onSuccess: () => void,
onError: () => void,
timeoutMs: number) {
Expand All @@ -45,22 +47,30 @@ class PendingContext {
this.onSuccess = onSuccess

setTimeout(() => {
if (!this.resolved) {
if (this.state != AppState.Done) {
onError()
}
}, timeoutMs)
}

resolve() {
this.resolved = true
setOpened() {
if (this.context) {
this.state = AppState.DeliveringContext
} else {
this.setDone()
}
}

setDone() {
this.state = AppState.Done
this.onSuccess()
}
}

export class OpenHandler implements MessageHandler {

private readonly directory: Directory
private readonly pendingContexts: Map<string, PendingContext> = new Map()
private readonly pending: Map<string, PendingApps> = new Map()

readonly timeoutMs: number

Expand All @@ -70,47 +80,44 @@ export class OpenHandler implements MessageHandler {
}

async accept(msg: any, sc: ServerContext, from: AppMetadata): Promise<void> {
this.ensureRegisteredConnected(sc, from)

switch (msg.type as string) {
case 'openRequest': return this.open(msg as OpenAgentRequest, sc, from)
case 'findInstancesRequest': return this.findInstances(msg as FindInstancesAgentRequest, sc, from)
case 'getAppMetadataRequest': return this.getAppMetadata(msg as GetAppMetadataAgentRequest, sc, from)
case 'onAddContextListener': return this.handleOnAddContextListener(msg as OnAddContextListenerAgentRequest, sc)
case 'hello': return this.handleHello(msg as ConnectionStep2Hello, sc, from)
}
}

ensureRegisteredConnected(sc: ServerContext, from: AppMetadata) {
sc.setAppConnected(from)
}

handleOnAddContextListener(arg0: PrivateChannelOnAddContextListenerAgentRequest | OnAddContextListenerAgentRequest, sc: ServerContext) {
const instanceId = arg0.meta.source?.instanceId
const pendingContext = instanceId ? this.pendingContexts.get(instanceId) : undefined
const pendingOpen = instanceId ? this.pending.get(instanceId) : undefined

if (pendingContext && instanceId) {
if (pendingOpen && instanceId) {
const channelId = arg0.payload.channelId
const contextType = arg0.payload.contextType

if ((contextType == pendingContext.context.type) || (contextType == undefined)) {
// ok, we can deliver to this listener

const message: BroadcastAgentRequest = {
meta: {
requestUuid: sc.createUUID(),
source: pendingContext.source,
timestamp: new Date()
},
type: "broadcastRequest",
payload: {
channelId,
context: pendingContext.context
if ((pendingOpen.context) && (pendingOpen.state == AppState.DeliveringContext)) {
if ((contextType == pendingOpen.context.type) || (contextType == undefined)) {
// ok, we can deliver to this listener

const message: BroadcastAgentRequest = {
meta: {
requestUuid: sc.createUUID(),
source: pendingOpen.source,
timestamp: new Date()
},
type: "broadcastRequest",
payload: {
channelId,
context: pendingOpen.context
}
}
}

pendingContext.resolve()
this.pendingContexts.delete(instanceId)
sc.post(message, arg0.meta.source!!)
pendingOpen.setDone()
this.pending.delete(instanceId)
sc.post(message, arg0.meta.source!!)
}
}
}
}
Expand Down Expand Up @@ -185,19 +192,26 @@ export class OpenHandler implements MessageHandler {

try {
const details = await sc.open(source.appId)
if (context && details.instanceId) {
this.pendingContexts.set(details.instanceId!!, new PendingContext(context, source,
() => sc.post(createSuccessMessage(details), from),
() => sc.post(createErrorMessage(OpenError.AppTimeout), from),
this.timeoutMs))
} else {
sc.post(createSuccessMessage(details), from)
}
this.pending.set(details.instanceId!!, new PendingApps(context, source,
() => sc.post(createSuccessMessage(details), from),
() => sc.post(createErrorMessage(OpenError.AppTimeout), from),
this.timeoutMs))
} catch (e: any) {
const message = createErrorMessage(e.message)
sc.post(message, from)
}
}

handleHello(_arg0: ConnectionStep2Hello, sc: ServerContext, opening: AppMetadata): void | PromiseLike<void> {
sc.setAppConnected(opening)

const instanceId = opening.instanceId
const pendingOpen = instanceId ? this.pending.get(instanceId) : undefined

if (pendingOpen) {
if (pendingOpen.state == AppState.Opening) {
pendingOpen.setOpened()
}
}
}
}
3 changes: 3 additions & 0 deletions packages/da-server/test/features/apps.feature
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@ Feature: Opening and Requesting App Details

Scenario: Opening An App
When "libraryApp/a1" opens app "storageApp"
And "storageApp/0" sends hello
Then messaging will have outgoing posts
| msg.type | msg.payload.appIdentifier.appId | msg.payload.appIdentifier.instanceId | to.instanceId |
| openResponse | storageApp | 0 | a1 |

Scenario: Opening An App With Context
When "libraryApp/a1" opens app "storageApp" with context data "fdc3.instrument"
And "storageApp/0" sends hello
And "storageApp/0" adds a context listener on "channel1" with type "fdc3.instrument"
Then messaging will have outgoing posts
| msg.type | msg.payload.channelId | msg.payload.context.type | to.instanceId |
Expand All @@ -37,6 +39,7 @@ Feature: Opening and Requesting App Details

Scenario: Opening An App With Context, But No Listener Added
When "libraryApp/a1" opens app "storageApp" with context data "fdc3.instrument"
And "storageApp/0" sends hello
And "storageApp/0" adds a context listener on "channel1" with type "fdc3.country"
And we wait for the listener timeout
Then messaging will have outgoing posts
Expand Down

0 comments on commit fd14134

Please sign in to comment.