Skip to content

Commit

Permalink
Merge pull request #1050 from InteropIO/tpina/find_instances_update
Browse files Browse the repository at this point in the history
findInstances correction and malformed messages clarification
  • Loading branch information
kriswest authored Sep 7, 2023
2 parents 61528b3 + a9cfb81 commit 72359bd
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 94 deletions.
7 changes: 7 additions & 0 deletions docs/agent-bridging/ref/findInstances.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ Desktop Agent bridging message exchange for a `findInstances` API call on the [`

[Message Exchange Type](../spec#individual-message-exchanges): **Request Response (collated)** or **Request Response (single)**

A Desktop Agent's [`findInstances`](../../api/ref/DesktopAgent#findinstances) API call should return an empty array for known applications and [`ResolveError.NoAppsFound`](../../api/ref/Errors#resolveerror) for unknown apps. Hence, if a findInstances request is received through bridging for a known app with no instances then a normal response should be returned with an empty array. The bridge should add the responding agent to the `sources` array in the collated response as this is a valid response. If the application is not known to the agent an error response should be used instead with the `ResolveError.NoAppsFound` message and the responding Desktop Agent should be added to the `meta.errorSources` of the bridge response.

In the event that all agents returned an error response, then the bridge will also return an error response, which is passed back to the calling application. However, if any agent returned a valid response (including with an empty array) then the application was known, but had no instances, resulting in an empty array being returned to the calling application.
E.g.

```javascript
Expand Down Expand Up @@ -95,6 +98,10 @@ which is repeated on to the target agent as:
}
```

:::note
If the `findInstancesRequest` from the requesting agent does not include a `meta.source` field then the Bridge MUST set the `meta.source.desktopAgent` field to attribute the request to the requesting agent. This is the case for all agent request messages that don't require application details.
:::

If results should be constrained to a particular Desktop Agent, then set a `desktopAgent` field in `payload.app` and a matching `destination` field in `meta`:

```json
Expand Down
6 changes: 6 additions & 0 deletions docs/agent-bridging/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -846,6 +846,12 @@ enum BridgingError {
}
```

### Handling Malformed Messages

It is the Bridge's responsibility to validate all messages that flow to and from Desktop Agents. When a request message is malformed the bridge MUST send a bridge error response message with `BridgingError.MalformedMessage` error to the sender. For 'request only' message exchanges, no specific error response schema is provided. Hence, the generic [Bridge Error Response Message schema](#all-responses-are-errors) should be used for such messages (with the type set to match the request message type).

Where responses to requests from other agents are malformed, the bridge MUST send a bridge error response message with `BridgingError.MalformedMessage` to the sender and record `BridgingError.MalformedMessage` as the error response from the responder that sent the malformed message.

### Forwarding of Messages and Collating Responses

When handling request messages, it is the responsibility of the Desktop Agent Bridge to:
Expand Down
2 changes: 1 addition & 1 deletion docs/api/ref/DesktopAgent.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ findInstances(app: AppIdentifier): Promise<Array<AppIdentifier>>;
Find all the available instances for a particular application.
If there are no instances of the specified application the returned promise should resolve to an empty array.
If the application is not known to the agent, the returned promise should be rejected with the `ResolverError.NoAppsFound` error message. However, if the application is known but there are no instances of the specified app the returned promise should resolve to an empty array.
If the request fails for another reason, the promise MUST be rejected with an `Error` Object with a `message` chosen from the [`ResolveError`](Errors#resolveerror) enumeration, or (if connected to a Desktop Agent Bridge) the [`BridgingError`](Errors#bridgingerror) enumeration.
Expand Down
3 changes: 1 addition & 2 deletions schemas/bridging/agentRequest.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@
"PrivateChannel.onAddContextListener",
"PrivateChannel.onDisconnect",
"PrivateChannel.onUnsubscribe",
"raiseIntentRequest",
"raiseIntentResultResponse"
"raiseIntentRequest"
],
"description": "Identifies the type of the message and it is typically set to the FDC3 function name that the message relates to, e.g. 'findIntent', with 'Request' appended."
},
Expand Down
9 changes: 8 additions & 1 deletion schemas/bridging/findInstancesAgentRequest.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,14 @@
"$ref": "common.schema.json#/$defs/AgentDestination"
},
"source": {
"$ref": "common.schema.json#/$defs/AppRequestSource"
"oneOf": [
{
"$ref": "../api/api.schema.json#/definitions/DesktopAgentIdentifier"
},
{
"$ref": "../api/api.schema.json#/definitions/AppIdentifier"
}
]
}
},
"unevaluatedProperties": false
Expand Down
178 changes: 88 additions & 90 deletions src/bridging/BridgingTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,6 @@ export enum RequestMessageType {
PrivateChannelOnDisconnect = 'PrivateChannel.onDisconnect',
PrivateChannelOnUnsubscribe = 'PrivateChannel.onUnsubscribe',
RaiseIntentRequest = 'raiseIntentRequest',
RaiseIntentResultResponse = 'raiseIntentResultResponse',
}

/**
Expand Down Expand Up @@ -1137,7 +1136,7 @@ export interface FindInstancesAgentRequestMeta {
* Field that represents the source application that the request was received from, or the
* source Desktop Agent if it issued the request itself.
*/
source?: SourceObject;
source?: SourceIdentifier;
timestamp: Date;
}

Expand Down Expand Up @@ -1478,10 +1477,86 @@ export interface FindInstancesBridgeRequestMeta {
* source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST
* be set by the bridge.
*/
source: MetaSource;
source: MetaSourceObject;
timestamp: Date;
}

/**
* Field that represents the source application that the request was received from, or the
* source Desktop Agent if it issued the request itself.
*
* Field that represents the source application that a request or response was received
* from, or the source Desktop Agent if it issued the request or response itself.
*
* Identifies an application, or instance of an application, and is used to target FDC3 API
* calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application
* instances.
*
* Will always include at least an `appId` field, which uniquely identifies a specific app.
*
* If the `instanceId` field is set then the `AppMetadata` object represents a specific
* instance of the application that may be addressed using that Id.
*
* Field that represents the source application that a request or response was received
* from.
*
* Identifier for the app instance that was selected (or started) to resolve the intent.
* `source.instanceId` MUST be set, indicating the specific app instance that
* received the intent.
*
* Identifies a particular Desktop Agent in Desktop Agent Bridging scenarios
* where a request needs to be directed to a Desktop Agent rather than a specific app, or a
* response message is returned by the Desktop Agent (or more specifically its resolver)
* rather than a specific app. Used as a substitute for `AppIdentifier` in cases where no
* app details are available or are appropriate.
*
* Array of DesktopAgentIdentifiers for responses that were not returned to the bridge
* before the timeout or because an error occurred. May be omitted if all sources responded
* without errors. MUST include the `desktopAgent` field when returned by the bridge.
*
* Array of DesktopAgentIdentifiers for the sources that generated responses to the request.
* Will contain a single value for individual responses and multiple values for responses
* that were collated by the bridge. May be omitted if all sources errored. MUST include the
* `desktopAgent` field when returned by the bridge.
*
* Field that represents a destination Desktop Agent that a request is to be sent to.
*
* Optional field that represents the destination that the request should be routed to. Must
* be set by the Desktop Agent for API calls that include a target app parameter and must
* include the name of the Desktop Agent hosting the target application.
*
* Represents identifiers that MUST include the Desktop Agent name and MAY identify a
* specific app or instance.
*
* Field that represents the source application that the request was received from, or the
* source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST
* be set by the bridge.
*
* Field that represents a destination App on a remote Desktop Agent that a request is to be
* sent to.
*/
export interface MetaSourceObject {
/**
* The unique application identifier located within a specific application directory
* instance. An example of an appId might be 'app@sub.root'
*/
appId?: string;
/**
* The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to
* identify the Desktop Agent to target.
*
* Used in Desktop Agent Bridging to attribute or target a message to a
* particular Desktop Agent.
*/
desktopAgent: string;
/**
* An optional instance identifier, indicating that this object represents a specific
* instance of the application described.
*/
instanceId?: string;
[property: string]: any;
}

/**
* The message payload typically contains the arguments to FDC3 API functions.
*/
Expand Down Expand Up @@ -2280,82 +2355,6 @@ export interface GetAppMetadataBridgeRequestMeta {
timestamp: Date;
}

/**
* Field that represents the source application that the request was received from, or the
* source Desktop Agent if it issued the request itself.
*
* Field that represents the source application that a request or response was received
* from, or the source Desktop Agent if it issued the request or response itself.
*
* Identifies an application, or instance of an application, and is used to target FDC3 API
* calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application
* instances.
*
* Will always include at least an `appId` field, which uniquely identifies a specific app.
*
* If the `instanceId` field is set then the `AppMetadata` object represents a specific
* instance of the application that may be addressed using that Id.
*
* Field that represents the source application that a request or response was received
* from.
*
* Identifier for the app instance that was selected (or started) to resolve the intent.
* `source.instanceId` MUST be set, indicating the specific app instance that
* received the intent.
*
* Identifies a particular Desktop Agent in Desktop Agent Bridging scenarios
* where a request needs to be directed to a Desktop Agent rather than a specific app, or a
* response message is returned by the Desktop Agent (or more specifically its resolver)
* rather than a specific app. Used as a substitute for `AppIdentifier` in cases where no
* app details are available or are appropriate.
*
* Array of DesktopAgentIdentifiers for responses that were not returned to the bridge
* before the timeout or because an error occurred. May be omitted if all sources responded
* without errors. MUST include the `desktopAgent` field when returned by the bridge.
*
* Array of DesktopAgentIdentifiers for the sources that generated responses to the request.
* Will contain a single value for individual responses and multiple values for responses
* that were collated by the bridge. May be omitted if all sources errored. MUST include the
* `desktopAgent` field when returned by the bridge.
*
* Field that represents a destination Desktop Agent that a request is to be sent to.
*
* Optional field that represents the destination that the request should be routed to. Must
* be set by the Desktop Agent for API calls that include a target app parameter and must
* include the name of the Desktop Agent hosting the target application.
*
* Represents identifiers that MUST include the Desktop Agent name and MAY identify a
* specific app or instance.
*
* Field that represents the source application that the request was received from, or the
* source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST
* be set by the bridge.
*
* Field that represents a destination App on a remote Desktop Agent that a request is to be
* sent to.
*/
export interface MetaSourceObject {
/**
* The unique application identifier located within a specific application directory
* instance. An example of an appId might be 'app@sub.root'
*/
appId?: string;
/**
* The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to
* identify the Desktop Agent to target.
*
* Used in Desktop Agent Bridging to attribute or target a message to a
* particular Desktop Agent.
*/
desktopAgent: string;
/**
* An optional instance identifier, indicating that this object represents a specific
* instance of the application described.
*/
instanceId?: string;
[property: string]: any;
}

/**
* The message payload typically contains the arguments to FDC3 API functions.
*/
Expand Down Expand Up @@ -4982,7 +4981,7 @@ const typeMap: any = {
[
{ json: 'destination', js: 'destination', typ: u(undefined, r('DestinationObject')) },
{ json: 'requestUuid', js: 'requestUuid', typ: '' },
{ json: 'source', js: 'source', typ: u(undefined, r('SourceObject')) },
{ json: 'source', js: 'source', typ: u(undefined, r('SourceIdentifier')) },
{ json: 'timestamp', js: 'timestamp', typ: Date },
],
false
Expand Down Expand Up @@ -5089,11 +5088,19 @@ const typeMap: any = {
[
{ json: 'destination', js: 'destination', typ: u(undefined, r('DestinationObject')) },
{ json: 'requestUuid', js: 'requestUuid', typ: '' },
{ json: 'source', js: 'source', typ: r('MetaSource') },
{ json: 'source', js: 'source', typ: r('MetaSourceObject') },
{ json: 'timestamp', js: 'timestamp', typ: Date },
],
false
),
MetaSourceObject: o(
[
{ json: 'appId', js: 'appId', typ: u(undefined, '') },
{ json: 'desktopAgent', js: 'desktopAgent', typ: '' },
{ json: 'instanceId', js: 'instanceId', typ: u(undefined, '') },
],
'any'
),
FindInstancesBridgeRequestPayload: o([{ json: 'app', js: 'app', typ: r('AppIdentifier') }], false),
FindInstancesBridgeResponse: o(
[
Expand Down Expand Up @@ -5464,14 +5471,6 @@ const typeMap: any = {
],
false
),
MetaSourceObject: o(
[
{ json: 'appId', js: 'appId', typ: u(undefined, '') },
{ json: 'desktopAgent', js: 'desktopAgent', typ: '' },
{ json: 'instanceId', js: 'instanceId', typ: u(undefined, '') },
],
'any'
),
GetAppMetadataBridgeRequestPayload: o([{ json: 'app', js: 'app', typ: r('AppDestinationIdentifier') }], false),
GetAppMetadataBridgeResponse: o(
[
Expand Down Expand Up @@ -6204,7 +6203,6 @@ const typeMap: any = {
'PrivateChannel.onDisconnect',
'PrivateChannel.onUnsubscribe',
'raiseIntentRequest',
'raiseIntentResultResponse',
],
ConnectionStepMessageType: ['authenticationFailed', 'connectedAgentsUpdate', 'handshake', 'hello'],
ErrorMessage: [
Expand Down

0 comments on commit 72359bd

Please sign in to comment.