Skip to content

Commit

Permalink
Merge pull request finos#94 from tim-dinsdale/feature/color-channel-3
Browse files Browse the repository at this point in the history
Proposed API changes
  • Loading branch information
Nicholas Kolba authored Aug 9, 2019
2 parents 09537c8 + 5229f62 commit 9c2c7b5
Show file tree
Hide file tree
Showing 2 changed files with 181 additions and 1 deletion.
30 changes: 29 additions & 1 deletion docs/api/api-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,36 @@ On the financial desktop, applications often want to broadcast context to any nu
## Resolvers
Intents functionality is dependent on resolver functionality to map the intent to a specific App. This will often require end-user input. Resolution can either be performed by the Desktop Agent (raising UI to pick the desired App for the intent) or by the app launching the intent - in which case the calling App will handle the resolution itself (using the findIntents API below) and then invoke an explicit Intent object.

## 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.

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

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'.

To find a system channel, one calls

let allChannels = await channels.getSystemChannels();
let myChannel = allChannels.find(c=>???);

To broadcast one calls

myChannel.broadcast(context);

To subscribe one calls

let listener = myChannel.addBroadcastListener((c,e)=>{some code});

App channels are created and obtained as thus:

let ac = await channels.getOrCreate("a-channel-name");

## APIs
The APIs are defined in TypeScript in [src], with documentation generated in the [docs] folder.

[src]: https://github.com/FDC3/FDC3/tree/master/src/api
[docs]: https://github.com/FDC3/FDC3/tree/master/docs/api
[docs]: https://github.com/FDC3/FDC3/tree/master/docs/api
152 changes: 152 additions & 0 deletions src/api/channel/channel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
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<void>;

/**
* 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<Context|null>;

/**
* 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<SystemChannel[]>;

/**
* 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<AppChannel>;
type: 'app';
}

0 comments on commit 9c2c7b5

Please sign in to comment.