Skip to content

Commit

Permalink
Fixed open promise with contexts
Browse files Browse the repository at this point in the history
  • Loading branch information
robmoffat committed May 16, 2024
1 parent b679db7 commit 047caa0
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 23 deletions.
6 changes: 3 additions & 3 deletions packages/da-server/src/BasicFDC3Server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ export class BasicFDC3Server implements FDC3Server {

export class DefaultFDC3Server extends BasicFDC3Server {

constructor(sc: ServerContext, directory: Directory, name: string, timeoutMs: number = 20000) {
constructor(sc: ServerContext, directory: Directory, name: string, intentTimeoutMs: number = 20000, openHandlerTimeoutMs: number = 3000) {
super([
new BroadcastHandler(name),
new IntentHandler(directory, timeoutMs),
new OpenHandler(directory)
new IntentHandler(directory, intentTimeoutMs),
new OpenHandler(directory, openHandlerTimeoutMs)
], sc)
}
}
84 changes: 65 additions & 19 deletions packages/da-server/src/handlers/OpenHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { AppDestinationIdentifier, AppMetadata, BroadcastAgentRequest, FindInsta
import { MessageHandler } from "../BasicFDC3Server";
import { ServerContext } from "../ServerContext";
import { Directory, DirectoryApp } from "../directory/DirectoryInterface";
import { ContextElement, ResolveError } from "@finos/fdc3";
import { ContextElement, OpenError, ResolveError } from "@finos/fdc3";
import { OnAddContextListenerAgentRequest } from "@kite9/fdc3-common";

function filterPublicDetails(appD: DirectoryApp, appID: AppDestinationIdentifier): GetAppMetadataAgentResponsePayload['appMetadata'] {
Expand All @@ -29,21 +29,49 @@ function createReplyMeta(msg: any, sc: ServerContext): BasicMeta {
}
}

type PendingContext = {
context: ContextElement,
source: AppMetadata
class PendingContext {

readonly context: ContextElement
readonly source: AppMetadata
private resolved: boolean = false
private onSuccess: () => void

constructor(context: ContextElement, source: AppMetadata,
onSuccess: () => void,
onError: () => void,
timeoutMs: number) {
this.context = context
this.source = source
this.onSuccess = onSuccess

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

resolve() {
this.resolved = true
this.onSuccess()
}
}

export class OpenHandler implements MessageHandler {

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

constructor(d: Directory) {
readonly timeoutMs: number

constructor(d: Directory, timeoutMs: number) {
this.directory = d
this.timeoutMs = timeoutMs
}

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)
Expand All @@ -52,6 +80,10 @@ export class OpenHandler implements MessageHandler {
}
}

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
Expand All @@ -75,6 +107,8 @@ export class OpenHandler implements MessageHandler {
context: pendingContext.context
}
}

pendingContext.resolve()
this.pendingContexts.delete(instanceId)
sc.post(message, arg0.meta.source!!)
}
Expand Down Expand Up @@ -123,32 +157,44 @@ export class OpenHandler implements MessageHandler {
}

async open(arg0: OpenAgentRequest, sc: ServerContext, from: AppMetadata): Promise<void> {
const source = arg0.payload.app
const context = arg0.payload.context

try {
const details = await sc.open(source.appId)
if (context && details.instanceId) {
this.pendingContexts.set(details.instanceId!!, { context, source })
}

const message: OpenAgentResponse = {
function createErrorMessage(e: string): OpenAgentErrorResponse {
const message: OpenAgentErrorResponse = {
meta: createReplyMeta(arg0, sc),
type: "openResponse",
payload: {
appIdentifier: details
error: e as OpenErrorMessage
}
}
return message;
}

sc.post(message, from)
} catch (e: unknown) {
const message: OpenAgentErrorResponse = {
function createSuccessMessage(details: AppMetadata): OpenAgentResponse {
const message: OpenAgentResponse = {
meta: createReplyMeta(arg0, sc),
type: "openResponse",
payload: {
error: ((e as Error).message as OpenErrorMessage)
appIdentifier: details
}
}
return message
}

const source = arg0.payload.app
const context = arg0.payload.context

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)
}
} catch (e: any) {
const message = createErrorMessage(e.message)
sc.post(message, from)
}
}
Expand Down
8 changes: 8 additions & 0 deletions packages/da-server/test/features/apps.feature
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ Feature: Opening and Requesting App Details
| openResponse | {empty} | {empty} | a1 |
| broadcastRequest | channel1 | fdc3.instrument | 0 |

Scenario: Opening An App With Context, But No Listener Added
When "libraryApp/a1" opens app "storageApp" with context data "fdc3.instrument"
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
| msg.type | msg.payload.channelId | msg.payload.context.type | to.instanceId |
| openResponse | {empty} | {empty} | a1 |

Scenario: Opening A Missing App
When "libraryApp/a1" opens app "missingApp"
Then messaging will have outgoing posts
Expand Down
2 changes: 1 addition & 1 deletion packages/da-server/test/step-definitions/generic.steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,6 @@ Given('A newly instantiated FDC3 Server', function (this: CustomWorld) {


this.sc = new TestServerContext(this)
this.server = new DefaultFDC3Server(this.sc, d, "cucumber-fdc3-server", 2000)
this.server = new DefaultFDC3Server(this.sc, d, "cucumber-fdc3-server", 2000, 2000)

});
6 changes: 6 additions & 0 deletions packages/da-server/test/step-definitions/start-app.steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,10 @@ When('{string} findsInstances of {string}', function (this: CustomWorld, appStr:
}
}
this.server.receive(message, from.source)
});

When('we wait for the listener timeout', function (this: CustomWorld) {
return new Promise<void>((resolve, _reject) => {
setTimeout(() => resolve(), 3100)
})
});

0 comments on commit 047caa0

Please sign in to comment.