From a67db07f15e9a0e68966bf46f4b1c87e9c478d1d Mon Sep 17 00:00:00 2001 From: Nicholas Kolba Date: Thu, 16 Jan 2020 07:31:55 -0500 Subject: [PATCH 1/7] initial commit to channel api simplification --- docs/api/api-spec.md | 38 +++++++--- src/api/channel/channel.ts | 152 ------------------------------------- src/api/interface.ts | 114 +++++++++++++++++++++++++++- 3 files changed, 140 insertions(+), 164 deletions(-) delete mode 100644 src/api/channel/channel.ts diff --git a/docs/api/api-spec.md b/docs/api/api-spec.md index 4d9d588b5..e590a34e8 100644 --- a/docs/api/api-spec.md +++ b/docs/api/api-spec.md @@ -134,9 +134,9 @@ Intents functionality is dependent on resolver functionality to map the intent t ## Context channels -The context channel api allows a set of apps to share a stateful piece of data between them, and be alerted when it changes. +Context channels allows a set of apps to share a stateful piece of data between them, and be alerted when it changes. Use cases for channels include color linking between applications to automate the sharing of context and topic based pub/sub such as theme. -There are two types of channels, which are functionally identical, but have different visibility and discoverability semantics. +There are two types of channels, which are functionally identical, but have different visibility and discoverability semantics. 1. The 'system' ones, which have a well understood identity. One is called 'default'. 2. The 'app' ones, which have a transient identity and need to be revealed @@ -145,20 +145,38 @@ The 'system' channels include a 'default' channel which serves as the backwards To find a system channel, one calls - let allChannels = await channels.getSystemChannels(); - let myChannel = allChannels.find(c=>???); +```javascript + //returns an array of channels + let allChannels = await fdc3.getSystemChannels(); + let redChannel = allChannels.find(c=>{return c.id === "red";}); +``` -To broadcast one calls +To join a channel. one calls - myChannel.broadcast(context); +```javascript + fdc3.joinChannel(redChannel.id); +``` -To subscribe one calls +Calling _fdc3.broadcast_ will now route context to the joined channel. - let listener = myChannel.addBroadcastListener((c,e)=>{some code}); +To broadcast to a specific channel one calls + +```javascript + fdc3.broadcastToChannel(context, redChannel.id); +``` -App channels are created and obtained as thus: +To listen to a channel one calls - let ac = await channels.getOrCreate("a-channel-name"); +```javascript + let listener = fdc3.addChannelListener((e)=>{some code},channelId); +``` + +App channels are registered as thus: + +```javascript + let ac = await fdc3.registerChannel("a-channel-id"); +``` + ## APIs The APIs are defined in TypeScript in [src], with documentation generated in the [docs] folder. diff --git a/src/api/channel/channel.ts b/src/api/channel/channel.ts deleted file mode 100644 index e181eaa17..000000000 --- a/src/api/channel/channel.ts +++ /dev/null @@ -1,152 +0,0 @@ -type ChannelId = string; - - -/** - * Object representing a context channel. - * - * All interactions with a context channel happen through the methods on here. - */ -declare class Channel { - /** - * Constant that uniquely identifies this channel. Will be generated by the service, and guarenteed to be unique - * within the set of channels registered with the service. - * - * In the case of `system` channels (see {@link SystemChannel}), these id's _should_ persist across sessions. The - * channel list is defined by the service, but can be overridden by a desktop agent. If the desktop agent keeps - * this list static (which is recommended), then id's will also persist across sessions. - */ - public readonly id: ChannelId; - - /** - * Uniquely defines each channel type. - * - * See overrides of this class for list of allowed values. - */ - public readonly type: string; - - /** - * Broadcasts the given context on this channel. This is equivalent to joining the channel and then calling the - * top-level FDC3 `broadcast` function. - * - * Note that this function can be used without first joining the channel, allowing applications to broadcast on - * channels that they aren't a member of. - * - * This broadcast will be received by all windows that are members of this channel, *except* for the window that - * makes the broadcast. This matches the behaviour of the top-level FDC3 `broadcast` function. - */ - public broadcast(context: Context): Promise; - - /** - * Returns the last context that was broadcast on this channel. All channels initially have no context, until a - * window is added to the channel and then broadcasts. If there is not yet any context on the channel, this method - * will return `null`. The context is also reset back into it's initial context-less state whenever a channel is - * cleared of all windows. - * - * The context of a channel will be captured regardless of how the context is broadcasted on this channel - whether - * using the top-level FDC3 `broadcast` function, or using the channel-level {@link broadcast} function on this - * object. - * - * NOTE: Only non-default channels are stateful, for the default channel this method will always return `null`. - */ - public getCurrentContext(): Promise; - - /** - * Event that is fired whenever a window broadcasts on this channel. - * - * The `channel` property within the event will always be this channel instance. - */ - public addBroadcastListener(listener: (event: {channel: Channel; context: Context}) => void): DesktopAgent.Listener; -} - -/** - * A system channel will be global enough to have a presence across many apps. This gives us some hints - * to render them in a standard way. It is assumed it may have other properties too, but if it has these, - * this is their meaning. - */ -declare interface DisplayMetadata{ - /** - * A user-readable name for this channel, e.g: `"Red"` - */ - name?: string; - - /** - * The color that should be associated within this channel when displaying this channel in a UI, e.g: `0xFF0000`. - */ - color?: string; - - /** - * A URL of an image that can be used to display this channel - */ - glyph?: string; -} - -/** - * User-facing channels, to display within a colour picker or channel selector component. - * - * This list of channels should be considered fixed by applications - the service will own the list of user channels, - * making the same list of channels available to all applications, and this list will not change over the lifecycle of - * the service. - * - * We do not intend to support creation of 'user' channels at runtime, as this then adds considerable complexity when - * implementing a channel selector component (must now support events, 'create channel' UI, reflowing of channel - * list, etc). - */ -declare class SystemChannel extends Channel { - type: 'system'; - - /** - * SystemChannels may well be selectable by users. Here are the hints on how to see them. - */ - visualIdentity: DisplayMetadata; -} - - -/** - * Applications can create custom channels for specialised use-cases. Note that these channels would only be known - * about to the app that created them. They can be joined by any window, but there would be no way to discover them - * from the service's API - it would be up to applications to decide how to share the channel ID with other - * windows/applications. - */ -declare class AppChannel extends Channel { - - - // Possibly some additional fields, TBD. -} - -/** - * Channels API is namespaced under a `channels` object. - * - * ``` - * import {channels} from '???'; - * - * channels.getDesktopChannels().then((channels: Channel[]) => { - * channels[0].joinChannel(); - * }); - * ``` - * - */ -declare module channels { - /** - * Allows access to the default channel. All windows will start out in this channel, and will remain in that - * channel unless they explicitly {@link Channel.join | joining} another. - * - * Applications can leave a {@link DesktopChannel} by re-joining the default channel. - */ - const defaultChannel: Channel; - - /** - * - */ - function getSystemChannels(): Promise; - - /** - * Returns an app channel with the given identity. Either stands up a new channel or returns an existing channel. - * - * It is up to applications to manage how to share knowledge of these custom channels across windows and to manage - * channel ownership and lifecycle. - * @param channelId the identity of this channel - */ - - public static getOrCreate(channelId: ChannelId): Promise; - type: 'app'; -} diff --git a/src/api/interface.ts b/src/api/interface.ts index 4ce1411ba..72d78d320 100644 --- a/src/api/interface.ts +++ b/src/api/interface.ts @@ -34,6 +34,7 @@ interface AppIntent { apps: Array; } + /** * App metadata is Desktop Agent specific - but should support a name property. */ @@ -64,6 +65,72 @@ interface Listener { unsubscribe(); } + +/** + * Object representing a context channel. + * + * All interactions with a context channel happen through the methods on here. + */ +declare class Channel { + /** + * Constant that uniquely identifies this channel. Will be generated by the service, and guarenteed to be unique + * within the set of channels registered with the service. + * + * In the case of `system` channels (see {@link SystemChannel}), these id's _should_ persist across sessions. The + * channel list is defined by the service, but can be overridden by a desktop agent. If the desktop agent keeps + * this list static (which is recommended), then id's will also persist across sessions. + */ + public readonly id: string; + + /** + * Uniquely defines each channel type. + */ + public readonly type: string; + +} + +/** +* A system channel will be global enough to have a presence across many apps. This gives us some hints +* to render them in a standard way. It is assumed it may have other properties too, but if it has these, +* this is their meaning. +*/ +declare interface DisplayMetadata{ + /** + * A user-readable name for this channel, e.g: `"Red"` + */ + name?: string; + + /** + * The color that should be associated within this channel when displaying this channel in a UI, e.g: `0xFF0000`. + */ + color?: string; + + /** + * A URL of an image that can be used to display this channel + */ + glyph?: string; +} + +/** +* User-facing channels, to display within a colour picker or channel selector component. +* +* This list of channels should be considered fixed by applications - the service will own the list of user channels, +* making the same list of channels available to all applications, and this list will not change over the lifecycle of +* the service. +* +* We do not intend to support creation of 'user' channels at runtime, as this then adds considerable complexity when +* implementing a channel selector component (must now support events, 'create channel' UI, reflowing of channel +* list, etc). +*/ +declare class SystemChannel extends Channel { + type: 'system'; + + /** + * SystemChannels may well be selectable by users. Here are the hints on how to see them. + */ + displayMetadata: DisplayMetadata; +} + /** * A Desktop Agent is a desktop component (or aggregate of components) that serves as a * launcher and message router (broker) for applications in its domain. @@ -75,7 +142,7 @@ interface Listener { */ interface DesktopAgent { /** - * Launches/links to an app by name. + * Launches an app by name. * * If a Context object is passed in, this object will be provided to the opened application via a contextListener. * The Context argument is functionally equivalent to opening the target app with no context and broadcasting the context directly to it. @@ -179,4 +246,47 @@ interface DesktopAgent { * Adds a listener for incoming context broadcast from the Desktop Agent. */ addContextListener(handler: (context: Context) => void): Listener; -} \ No newline at end of file + + /** + * Retrieves a list of the System channels available for the app to join + */ + getSystemChannels(): Promise>; + + /** + * Joins the app to the specified channel + * An app can only be joined to one channel at a time + * rejects with error if the channel is unavailable or the join request is denied + */ + joinChannel(channel: string) : Promise; + + + + /** + * Broadcasts a context specifically to a channel + * Channel may be system or app type + * An app is not required to be a member of the channel they broadcast to, + * but the desktop agent may reject their broadcast + * rejects with error if the broadcast was denied for the channel, channel does not exist, etc + */ + broadcastToChannel(context: Context, channel: string): Promise; + + + /** + * Adds a listener specific to a channel - System or App + * rejects with error if the broadcast was denied for the channel, channel does not exist, etc + */ + addChannelListener(channel: string, handler: (context: Context) => void): Listener; + + /** + * Creates an App type channel. + * rejects with error if the channel already exists or if the app is denied creating a channel + */ + registerChannel(channel: string): Promise; + + /** + * Returns the current context for a channel + * if no channel is specified, will return current context for the joined channel for the app + */ + getCurrentContext(channel?: string): Promise; +} + From 36d66c8530bc92fd159f934675b5f4c9e0915667 Mon Sep 17 00:00:00 2001 From: Nicholas Kolba Date: Thu, 16 Jan 2020 17:21:29 -0500 Subject: [PATCH 2/7] more reworking of the API proposal, restore Channel class --- docs/api/DesktopAgent.md | 123 ++++++++++++++++++++++++++++++++++----- docs/api/api-spec.md | 31 ++++++---- src/api/interface.ts | 59 ++++--------------- 3 files changed, 141 insertions(+), 72 deletions(-) diff --git a/docs/api/DesktopAgent.md b/docs/api/DesktopAgent.md index 897b44579..ef72068c7 100644 --- a/docs/api/DesktopAgent.md +++ b/docs/api/DesktopAgent.md @@ -12,6 +12,21 @@ A Desktop Agent can be connected to one or more App Directories and will use dir ## Methods +### `broadcast` +```typescript +broadcast(context: Context): void; +``` + +Publishes context to other apps on the desktop. + +#### Examples +```javascript +fdc3.broadcast(context); +``` +#### See also +* [addContextListener](#addcontextlistener) + + ### `open` ```typescript @@ -108,19 +123,6 @@ A promise resolving to all the intents, their metadata and metadata about the ap #### See also * [`ResolveError`](Errors#resolveerror) -### `broadcast` -```typescript -broadcast(context: Context): void; -``` - -Publishes context to other apps on the desktop. - -#### Examples -```javascript -agent.broadcast(context); -``` -#### See also -* [addContextListener](#addcontextlistener) ### `raiseIntent` @@ -138,6 +140,64 @@ agent.raiseIntent("StartChat", newContext, intentR.source); #### See also * [`IntentResolution`](#intentresolution) + + + +### `getOrCreateChannel` +```typescript +getOrCreateChannel(channelId: string): Promise; +``` +Returns a Channel object for the specified channel, creating it (as an _App_ channel) - if it does not exist. + +#### Examples +```javascript + +try { + let myChannel = await fdc3.getOrCreateChannel("myChannel"); + myChannel.addContextListener(listener); +} +catch (err){ + //app could not register the channel +} + +``` +#### See also +*[`Channel`](#Channel) + + +### `getSystemChannels` +```typescript +getSystemChannels() : Promise>; +``` +Retrieves a list of the System channels available for the app to join + +#### See also +*[`Channel`](#Channel) + +### `joinChannel` +```typescript +joinChannel(channelId: string) : Promise; +``` +Joins the app to the specified channel. +If an app is joined to a channel, all _fdc3.broadcast_ calls will go to the channel, and all listeners assigned via _fdc3.addContextListener_ will listen on the channel. +An app can only be joined to one channel at a time. +Rejects with error if the channel is unavailable or the join request is denied. + +#### Examples +```javascript + //get all system channels + const channels = await fdc3.getSystemChannels(); + + //create UI to pick from the system channels + + //join the channel on selection + fdc3.joinChannel(selectedChannel.id); + +``` +#### See also +*[`getSystemChannels`](#getSystemChannels) + + ### `addIntentListener` ```typescript addIntentListener(intent: string, handler: (context: Context) => void): Listener; @@ -157,6 +217,9 @@ Adds a listener for incoming context broadcast from the Desktop Agent. * [`Listener`](#listener) * [`Context`](Context) + + + ## Return Types ### `AppIntent` @@ -234,3 +297,37 @@ The `unsubscribe` method on the listener object allows the application to cancel * [`DesktopAgent.addIntentListener`](#addintentlistener) * [`DesktopAgent.addContextListener`](#addcontextlistener) +### `Channel` +```typescript + Channel { + id: string; + type: string; + displayMetadata: DisplayMetadata; + broadcast(context: Context): Promise; + getCurrentContext(): Promise; + addBroadcastListener(listener: (event: {channel: Channel; context: Context}) => void): DesktopAgent.Listener; +} +``` +Object representing a context channel. +* __id__ uniquely identifies the channel. It is either assigned by the desktop agent (system channel) or defined by an application (app channel) +* __type__ may be _system_ or _app_ +* __dispalyMetadata__ DisplayMetaData can be used to provide display hints for channels intended to be visualized and selectable by end users. +* __broadcast__ Broadcasts a context on the channel. This function can be used without first joining the channel, allowing applications to broadcast on channels that they aren't a member of. +* __getCurrentContext__ Returns the last context that was broadcast on the channel. If no context has been set on the channel, this will return `null`. +* __addBroadcastListener__ Event that is fired whenever a window broadcasts on this channel. The `channel` property within the event will always be this channel instance. + +#### See also +[`DisplayMetadata`](#DisplayMetadata) + +### `DisplayMetadata` +```typescript +DisplayMetadata{ + name?: string; + color?: string; + glyph?: string; +} +``` +A desktop agent (typically for _system_ channels) may want to provide additional information about how a channel can be represented in a UI. A common use case is for color linking. +* __name__ The display name for the channel +* __color__ A name, hex, rgba, etc that should be associated within this channel when displaying this channel in a UI +* __glyph__ A URL of an image that can be used to display this channel diff --git a/docs/api/api-spec.md b/docs/api/api-spec.md index e590a34e8..d34ab6408 100644 --- a/docs/api/api-spec.md +++ b/docs/api/api-spec.md @@ -143,6 +143,17 @@ There are two types of channels, which are functionally identical, but have diff The 'system' channels include a 'default' channel which serves as the backwards compatible layer with the 'send/broadcast context' above. There are some reserved channel names for future use. Currently this is just 'global'. +### Joining Channels +Apps can join channels. An app can only be joined to one channel at a time. When an app joins a channel it will automatically recieve the current context for that channel, except if the channel joined is the 'default'. + +When an app is joined to a channel, calls to fdc3.broadcast and listeners added through fdc3.addContextListener will be routed to that channel. If an app is not explicitly joined to a channel, it is on the 'default' channel. It is up to the desktop agent to determine the behavior of the 'default' channel, and if context is automaticaly broadcast over it or not. + +It is possible that a call to join a channel could be rejected. If for example, the desktop agent wanted to implement controls around what data apps can access. + +### Direct Listening and Broadcast on Channels +While joining channels automates a lot of the channel behavior for an app, it has the limitation in that an app can belong to only one channel at a time. Listening and Broadcasting to channels using the _Channel.addBroadcastListener_ and the _Channel.broadcast_ APIs provides an app with fine-grained controls for specific channels. This is especially useful for working with dynamic _App Channels_. + +### Examples To find a system channel, one calls ```javascript @@ -159,24 +170,20 @@ To join a channel. one calls Calling _fdc3.broadcast_ will now route context to the joined channel. -To broadcast to a specific channel one calls +To get (or create) a channel reference, then interact with it ```javascript - fdc3.broadcastToChannel(context, redChannel.id); -``` + const appChannel = await fdc3.getOrCreateChannel("appChannel"); + //get the current context of the channel + let current = await appChannel.getCurrentContext(); + //add a listener + appChannel.addBroadcastListener((event)=>{...}); + //broadcast to the channel + appChannel.broadcast(context); -To listen to a channel one calls - -```javascript - let listener = fdc3.addChannelListener((e)=>{some code},channelId); ``` -App channels are registered as thus: -```javascript - let ac = await fdc3.registerChannel("a-channel-id"); -``` - ## APIs The APIs are defined in TypeScript in [src], with documentation generated in the [docs] folder. diff --git a/src/api/interface.ts b/src/api/interface.ts index 72d78d320..4d33ce5b4 100644 --- a/src/api/interface.ts +++ b/src/api/interface.ts @@ -87,6 +87,10 @@ declare class Channel { */ public readonly type: string; + /** + * Channels may be visualized and selectable by users. DisplayMetaData may be used to provide hints on how to see them. + */ + displayMetadata: DisplayMetadata; } /** @@ -111,25 +115,6 @@ declare interface DisplayMetadata{ glyph?: string; } -/** -* User-facing channels, to display within a colour picker or channel selector component. -* -* This list of channels should be considered fixed by applications - the service will own the list of user channels, -* making the same list of channels available to all applications, and this list will not change over the lifecycle of -* the service. -* -* We do not intend to support creation of 'user' channels at runtime, as this then adds considerable complexity when -* implementing a channel selector component (must now support events, 'create channel' UI, reflowing of channel -* list, etc). -*/ -declare class SystemChannel extends Channel { - type: 'system'; - - /** - * SystemChannels may well be selectable by users. Here are the hints on how to see them. - */ - displayMetadata: DisplayMetadata; -} /** * A Desktop Agent is a desktop component (or aggregate of components) that serves as a @@ -250,43 +235,23 @@ interface DesktopAgent { /** * Retrieves a list of the System channels available for the app to join */ - getSystemChannels(): Promise>; + getSystemChannels(): Promise>; /** * Joins the app to the specified channel * An app can only be joined to one channel at a time * rejects with error if the channel is unavailable or the join request is denied */ - joinChannel(channel: string) : Promise; - - + joinChannel(channelId: string) : Promise; /** - * Broadcasts a context specifically to a channel - * Channel may be system or app type - * An app is not required to be a member of the channel they broadcast to, - * but the desktop agent may reject their broadcast - * rejects with error if the broadcast was denied for the channel, channel does not exist, etc - */ - broadcastToChannel(context: Context, channel: string): Promise; - - - /** - * Adds a listener specific to a channel - System or App - * rejects with error if the broadcast was denied for the channel, channel does not exist, etc + * Returns a channel with the given identity. Either stands up a new channel or returns an existing channel. + * + * It is up to applications to manage how to share knowledge of these custom channels across windows and to manage + * channel ownership and lifecycle. + * @param channelId the identity of this channel */ - addChannelListener(channel: string, handler: (context: Context) => void): Listener; + getOrCreateChannel(channelId: string): Promise; - /** - * Creates an App type channel. - * rejects with error if the channel already exists or if the app is denied creating a channel - */ - registerChannel(channel: string): Promise; - /** - * Returns the current context for a channel - * if no channel is specified, will return current context for the joined channel for the app - */ - getCurrentContext(channel?: string): Promise; -} From bb17480c24df767b6c3073f55b1da7cc27c525c5 Mon Sep 17 00:00:00 2001 From: Nicholas Kolba Date: Thu, 16 Jan 2020 20:57:50 -0500 Subject: [PATCH 3/7] clean up --- src/api/interface.ts | 49 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/src/api/interface.ts b/src/api/interface.ts index 4d33ce5b4..07b11bc62 100644 --- a/src/api/interface.ts +++ b/src/api/interface.ts @@ -18,6 +18,11 @@ enum ResolveError { ResolverTimeout = "ResolverTimeout" } +enum ChannelError { + NoChannelFound = "NoChannelFound", + AccessDenied = "AccessDenied" +} + /** * Intent descriptor */ @@ -68,17 +73,13 @@ interface Listener { /** * Object representing a context channel. - * - * All interactions with a context channel happen through the methods on here. */ declare class Channel { /** * Constant that uniquely identifies this channel. Will be generated by the service, and guarenteed to be unique * within the set of channels registered with the service. * - * In the case of `system` channels (see {@link SystemChannel}), these id's _should_ persist across sessions. The - * channel list is defined by the service, but can be overridden by a desktop agent. If the desktop agent keeps - * this list static (which is recommended), then id's will also persist across sessions. + * In the case of `system` channels, these id's _should_ persist across sessions. */ public readonly id: string; @@ -91,6 +92,39 @@ declare class Channel { * Channels may be visualized and selectable by users. DisplayMetaData may be used to provide hints on how to see them. */ displayMetadata: DisplayMetadata; + + /** + * Broadcasts the given context on this channel. This is equivalent to joining the channel and then calling the + * top-level FDC3 `broadcast` function. + * + * Note that this function can be used without first joining the channel, allowing applications to broadcast on + * channels that they aren't a member of. + * + * This broadcast will be received by all windows that are members of this channel, *except* for the window that + * makes the broadcast. This matches the behaviour of the top-level FDC3 `broadcast` function. + */ + public broadcast(context: Context): Promise; + + /** + * Returns the last context that was broadcast on this channel. All channels initially have no context, until a + * window is added to the channel and then broadcasts. If there is not yet any context on the channel, this method + * will return `null`. The context is also reset back into it's initial context-less state whenever a channel is + * cleared of all windows. + * + * The context of a channel will be captured regardless of how the context is broadcasted on this channel - whether + * using the top-level FDC3 `broadcast` function, or using the channel-level {@link broadcast} function on this + * object. + * + * NOTE: Only non-default channels are stateful, for the default channel this method will always return `null`. + */ + public getCurrentContext(): Promise; + + /** + * Event that is fired whenever a window broadcasts on this channel. + * + * The `channel` property within the event will always be this channel instance. + */ + public addBroadcastListener(listener: (event: {channel: Channel; context: Context}) => void): Listener; } /** @@ -234,6 +268,7 @@ interface DesktopAgent { /** * Retrieves a list of the System channels available for the app to join + * * `Error` with a string from the `ChannelError` enumeration. */ getSystemChannels(): Promise>; @@ -241,6 +276,7 @@ interface DesktopAgent { * Joins the app to the specified channel * An app can only be joined to one channel at a time * rejects with error if the channel is unavailable or the join request is denied + * `Error` with a string from the `ChannelError` enumeration. */ joinChannel(channelId: string) : Promise; @@ -249,7 +285,8 @@ interface DesktopAgent { * * It is up to applications to manage how to share knowledge of these custom channels across windows and to manage * channel ownership and lifecycle. - * @param channelId the identity of this channel + * + * `Error` with a string from the `ChannelError` enumeration. */ getOrCreateChannel(channelId: string): Promise; From c154359559afdf374c36f46ceac93a3d335fb98b Mon Sep 17 00:00:00 2001 From: Nicholas Kolba Date: Thu, 16 Jan 2020 21:25:30 -0500 Subject: [PATCH 4/7] errors, more cleanup --- docs/api/DesktopAgent.md | 12 +++++++----- docs/api/Errors.md | 13 ++++++++++++- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/docs/api/DesktopAgent.md b/docs/api/DesktopAgent.md index ef72068c7..6cbbe3be0 100644 --- a/docs/api/DesktopAgent.md +++ b/docs/api/DesktopAgent.md @@ -148,6 +148,7 @@ agent.raiseIntent("StartChat", newContext, intentR.source); getOrCreateChannel(channelId: string): Promise; ``` Returns a Channel object for the specified channel, creating it (as an _App_ channel) - if it does not exist. + `Error` with a string from the [`ChannelError`](Errors#channelerror) enumeration if channel could not be created or access was denied. #### Examples ```javascript @@ -162,7 +163,7 @@ catch (err){ ``` #### See also -*[`Channel`](#Channel) +*[`Channel`](#channel) ### `getSystemChannels` @@ -172,7 +173,7 @@ getSystemChannels() : Promise>; Retrieves a list of the System channels available for the app to join #### See also -*[`Channel`](#Channel) +*[`Channel`](#channel) ### `joinChannel` ```typescript @@ -182,6 +183,7 @@ Joins the app to the specified channel. If an app is joined to a channel, all _fdc3.broadcast_ calls will go to the channel, and all listeners assigned via _fdc3.addContextListener_ will listen on the channel. An app can only be joined to one channel at a time. Rejects with error if the channel is unavailable or the join request is denied. + `Error` with a string from the [`ChannelError`](Errors#channelerror) enumeration. #### Examples ```javascript @@ -312,9 +314,9 @@ Object representing a context channel. * __id__ uniquely identifies the channel. It is either assigned by the desktop agent (system channel) or defined by an application (app channel) * __type__ may be _system_ or _app_ * __dispalyMetadata__ DisplayMetaData can be used to provide display hints for channels intended to be visualized and selectable by end users. -* __broadcast__ Broadcasts a context on the channel. This function can be used without first joining the channel, allowing applications to broadcast on channels that they aren't a member of. -* __getCurrentContext__ Returns the last context that was broadcast on the channel. If no context has been set on the channel, this will return `null`. -* __addBroadcastListener__ Event that is fired whenever a window broadcasts on this channel. The `channel` property within the event will always be this channel instance. +* __broadcast__ Broadcasts a context on the channel. This function can be used without first joining the channel, allowing applications to broadcast on channels that they aren't a member of. `Error` with a string from the [`ChannelError`](Errors#channelerror) enumeration. +* __getCurrentContext__ Returns the last context that was broadcast on the channel. If no context has been set on the channel, this will return `null`. `Error` with a string from the [`ChannelError`](Errors#channelerror) enumeration. +* __addBroadcastListener__ Event that is fired whenever a window broadcasts on this channel. The `channel` property within the event will always be this channel instance. `Error` with a string from the [`ChannelError`](Errors#channelerror) enumeration. #### See also [`DisplayMetadata`](#DisplayMetadata) diff --git a/docs/api/Errors.md b/docs/api/Errors.md index 06b4616aa..27b34c3b5 100644 --- a/docs/api/Errors.md +++ b/docs/api/Errors.md @@ -36,4 +36,15 @@ Contains constants representing the errors that can be encountered when calling #### See also * [`DesktopAgent.findIntent`](DesktopAgent#findintent) -* [`DesktopAgent.findIntentsByContext`](DesktopAgent#findintentsbycontext) \ No newline at end of file +* [`DesktopAgent.findIntentsByContext`](DesktopAgent#findintentsbycontext) + +## `ChannelError` + +```typescript +enum ChannelError { + NoChannelFound = "NoChannelFound", + AccessDenied = "AccessDenied", + CreationFailed = "CreationFailed" +} +``` +Contains constants representing the errors that can be encountered when calling channels using the [`joinChannel`](DesktopAgent#joinchannel) or [`getOrCreateChannel`](DesktopAgent#getorcreatechannel) methods, or the [`getCurrentContext`](DesktopAgent#channel), [`broadcast`](DesktopAgent#channel) or [`addBroadcastListener`](DesktopAgent#channel) methods on the Channel object. From dc96cc1f5d149e875ceb9668f29eef87d514aeab Mon Sep 17 00:00:00 2001 From: Nicholas Kolba Date: Fri, 17 Jan 2020 07:52:29 -0500 Subject: [PATCH 5/7] additions to channel errors enum --- src/api/interface.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/api/interface.ts b/src/api/interface.ts index 07b11bc62..67cb5735d 100644 --- a/src/api/interface.ts +++ b/src/api/interface.ts @@ -20,7 +20,8 @@ enum ResolveError { enum ChannelError { NoChannelFound = "NoChannelFound", - AccessDenied = "AccessDenied" + AccessDenied = "AccessDenied", + CreationFailed = "CreationFailed" } /** @@ -102,6 +103,7 @@ declare class Channel { * * This broadcast will be received by all windows that are members of this channel, *except* for the window that * makes the broadcast. This matches the behaviour of the top-level FDC3 `broadcast` function. + * `Error` with a string from the `ChannelError` enumeration. */ public broadcast(context: Context): Promise; @@ -116,6 +118,7 @@ declare class Channel { * object. * * NOTE: Only non-default channels are stateful, for the default channel this method will always return `null`. + * `Error` with a string from the `ChannelError` enumeration. */ public getCurrentContext(): Promise; @@ -123,6 +126,7 @@ declare class Channel { * Event that is fired whenever a window broadcasts on this channel. * * The `channel` property within the event will always be this channel instance. + * `Error` with a string from the `ChannelError` enumeration. */ public addBroadcastListener(listener: (event: {channel: Channel; context: Context}) => void): Listener; } @@ -268,7 +272,6 @@ interface DesktopAgent { /** * Retrieves a list of the System channels available for the app to join - * * `Error` with a string from the `ChannelError` enumeration. */ getSystemChannels(): Promise>; From 41794ceaa5f784aa6f8c318e02a89902db7a018b Mon Sep 17 00:00:00 2001 From: Nicholas Kolba Date: Fri, 17 Jan 2020 07:56:07 -0500 Subject: [PATCH 6/7] make DisplayMetadata optional --- docs/api/DesktopAgent.md | 2 +- src/api/interface.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/api/DesktopAgent.md b/docs/api/DesktopAgent.md index 6cbbe3be0..867390a7d 100644 --- a/docs/api/DesktopAgent.md +++ b/docs/api/DesktopAgent.md @@ -304,7 +304,7 @@ The `unsubscribe` method on the listener object allows the application to cancel Channel { id: string; type: string; - displayMetadata: DisplayMetadata; + displayMetadata?: DisplayMetadata; broadcast(context: Context): Promise; getCurrentContext(): Promise; addBroadcastListener(listener: (event: {channel: Channel; context: Context}) => void): DesktopAgent.Listener; diff --git a/src/api/interface.ts b/src/api/interface.ts index 67cb5735d..34f45433a 100644 --- a/src/api/interface.ts +++ b/src/api/interface.ts @@ -91,8 +91,9 @@ declare class Channel { /** * Channels may be visualized and selectable by users. DisplayMetaData may be used to provide hints on how to see them. + * For app channels, displayMetadata would typically not be present */ - displayMetadata: DisplayMetadata; + displayMetadata?: DisplayMetadata; /** * Broadcasts the given context on this channel. This is equivalent to joining the channel and then calling the From 69aefec1442721300b10cf31035439f92b977937 Mon Sep 17 00:00:00 2001 From: Nicholas Kolba Date: Tue, 21 Jan 2020 09:45:26 -0500 Subject: [PATCH 7/7] updates based on change requests --- docs/api/api-spec.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/api/api-spec.md b/docs/api/api-spec.md index d34ab6408..8dac3cf61 100644 --- a/docs/api/api-spec.md +++ b/docs/api/api-spec.md @@ -159,8 +159,9 @@ To find a system channel, one calls ```javascript //returns an array of channels let allChannels = await fdc3.getSystemChannels(); - let redChannel = allChannels.find(c=>{return c.id === "red";}); + let redChannel = allChannels.find(c => c.id === 'red'); ``` +#### Joining channels To join a channel. one calls @@ -170,14 +171,18 @@ To join a channel. one calls Calling _fdc3.broadcast_ will now route context to the joined channel. +#### App Channels + +App channels are topics dynamically created by applications connected via FDC3. For example, an app may create a channel to broadcast to others data or status specific to that app. + To get (or create) a channel reference, then interact with it ```javascript - const appChannel = await fdc3.getOrCreateChannel("appChannel"); + const appChannel = await fdc3.getOrCreateChannel('my_custom_channel'); //get the current context of the channel let current = await appChannel.getCurrentContext(); //add a listener - appChannel.addBroadcastListener((event)=>{...}); + appChannel.addBroadcastListener(event => {...}); //broadcast to the channel appChannel.broadcast(context);