Skip to content

Commit

Permalink
Merge pull request #516 from ChartIQ/362-DesktopAgent-and-Channel-API…
Browse files Browse the repository at this point in the history
…s-should-be-async

362 All DesktopAgent and Channel APIs are async
  • Loading branch information
rikoe authored Dec 21, 2021
2 parents c1b0acb + 48071af commit 0ece665
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 69 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
* Updated copyright notices ([#467](https://github.com/finos/FDC3/pull/467))
* Adjusted wording in API spec and documentation to acknowledge the possibility of methods of intent resolution other than a resolver UI ([#461](https://github.com/finos/FDC3/pull/461))
* Moved the Icon type definition into the Types documentation page for consistency with other types. ([#493](https://github.com/finos/FDC3/pull/493)
* All DesktopAgent and Channel API functions are now async for consistency, changing the return type of the `broadcast`, `addIntentListener`, `addContextListener` and `getInfo` functions ([#516](https://github.com/finos/FDC3/pull/516))

### Deprecated
### Fixed
Expand Down
2 changes: 1 addition & 1 deletion docs/api/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ import { fdc3Ready, addIntentListener } from '@finos/fdc3'

await fdc3Ready();

const listener = addIntentListener('ViewAnalysis', instrument => {
const listener = await addIntentListener('ViewAnalysis', instrument => {
// handle intent
})
```
Expand Down
18 changes: 9 additions & 9 deletions docs/api/ref/Channel.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ interface Channel {
displayMetadata?: DisplayMetadata;

// methods
broadcast(context: Context): void;
broadcast(context: Context): Promise<void>;
getCurrentContext(contextType?: string): Promise<Context|null>;
addContextListener(contextType: string | null, handler: ContextHandler): Listener;
addContextListener(contextType: string | null, handler: ContextHandler): Promise<Listener>;
/**
* @deprecated Use `addContextListener(null, handler)` instead of `addContextListener(handler)`
*/
addContextListener(handler: ContextHandler): Listener;
addContextListener(handler: ContextHandler): Promise<Listener>;
}
```

Expand Down Expand Up @@ -72,15 +72,15 @@ DisplayMetadata can be used to provide display hints for channels intended to be

### `addContextListener`
```ts
public addContextListener(contextType: string | null, handler: ContextHandler): Listener;
public addContextListener(contextType: string | null, handler: ContextHandler): Promise<Listener>;
```
Adds a listener for incoming contexts of the specified _context type_ whenever a broadcast happens on this channel.

```ts
/**
* @deprecated Use `addContextListener(null, handler)` instead of `addContextListener(handler)`
*/
public addContextListener(handler: ContextHandler): Listener;
public addContextListener(handler: ContextHandler): Promise<Listener>;
```
Adds a listener for incoming contexts whenever a broadcast happens on the channel.

Expand All @@ -90,7 +90,7 @@ Adds a listener for incoming contexts whenever a broadcast happens on the channe
Add a listener for any context that is broadcast on the channel:

```ts
const listener = channel.addContextListener(null, context => {
const listener = await channel.addContextListener(null, context => {
if (context.type === 'fdc3.contact') {
// handle the contact
} else if (context.type === 'fdc3.instrument') => {
Expand All @@ -105,11 +105,11 @@ listener.unsubscribe();
Adding listeners for specific types of context that is broadcast on the channel:

```ts
const contactListener = channel.addContextListener('fdc3.contact', contact => {
const contactListener = await channel.addContextListener('fdc3.contact', contact => {
// handle the contact
});

const instrumentListener = channel.addContextListener('fdc3.instrument', instrument => {
const instrumentListener = await channel.addContextListener('fdc3.instrument', instrument => {
// handle the instrument
});

Expand All @@ -127,7 +127,7 @@ instrumentListener.unsubscribe();
### `broadcast`

```typescript
public broadcast(context: Context): void;
public broadcast(context: Context): Promise<void>;
```

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.
Expand Down
28 changes: 14 additions & 14 deletions docs/api/ref/DesktopAgent.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,19 @@ interface DesktopAgent {
open(app: TargetApp, context?: Context): Promise<void>;

// context
broadcast(context: Context): void;
addContextListener(contextType: string | null, handler: ContextHandler): Listener;
broadcast(context: Context): Promise<void>;
addContextListener(contextType: string | null, handler: ContextHandler): Promise<Listener>;
/**
* @deprecated 'Use `addContextListener(null, handler)` instead of `addContextListener(handler)`
*/
addContextListener(handler: ContextHandler): Listener;
addContextListener(handler: ContextHandler): Promise<Listener>;

// intents
findIntent(intent: string, context?: Context): Promise<AppIntent>;
findIntentsByContext(context: Context): Promise<Array<AppIntent>>;
raiseIntent(intent: string, context: Context, app?: TargetApp): Promise<IntentResolution>;
raiseIntentForContext(context: Context, app?: TargetApp): Promise<IntentResolution>;
addIntentListener(intent: string, handler: ContextHandler): Listener;
addIntentListener(intent: string, handler: ContextHandler): Promise<Listener>;

// channels
getOrCreateChannel(channelId: string): Promise<Channel>;
Expand All @@ -40,7 +40,7 @@ interface DesktopAgent {
leaveCurrentChannel() : Promise<void>;

//implementation info
getInfo(): ImplementationMetadata;
getInfo(): Promise<ImplementationMetadata>;
}
```

Expand All @@ -49,11 +49,11 @@ interface DesktopAgent {
### `addContextListener`

```ts
addContextListener(contextType: string | null, handler: ContextHandler): Listener;
addContextListener(contextType: string | null, handler: ContextHandler): Promise<Listener>;
/**
* @deprecated 'Use `addContextListener(null, handler)` instead of `addContextListener(handler)`
*/
addContextListener(handler: ContextHandler): Listener;
addContextListener(handler: ContextHandler): Promise<Listener>;
```
Adds a listener for incoming context broadcasts from the Desktop Agent. If the consumer is only interested in a context of a particular type, they can specify that type. If the consumer is able to receive context of any type or will inspect types received, then they can pass `null` as the `contextType` parameter to receive all context types.

Expand All @@ -62,10 +62,10 @@ Context broadcasts are only received from apps that are joined to the same chann
#### Examples
```js
// any context
const listener = fdc3.addContextListener(null, context => { ... });
const listener = await fdc3.addContextListener(null, context => { ... });

// listener for a specific type
const contactListener = fdc3.addContextListener('fdc3.contact', contact => { ... });
const contactListener = await fdc3.addContextListener('fdc3.contact', contact => { ... });
```

#### See also
Expand All @@ -77,14 +77,14 @@ const contactListener = fdc3.addContextListener('fdc3.contact', contact => { ...
### `addIntentListener`

```ts
addIntentListener(intent: string, handler: ContextHandler): Listener;
addIntentListener(intent: string, handler: ContextHandler): Promise<Listener>;
```
Adds a listener for incoming Intents from the Agent.

#### Examples

```js
const listener = fdc3.addIntentListener('StartChat', context => {
const listener = await fdc3.addIntentListener('StartChat', context => {
// start chat has been requested by another application
});
```
Expand All @@ -98,7 +98,7 @@ const listener = fdc3.addIntentListener('StartChat', context => {
### `broadcast`

```ts
broadcast(context: Context): void;
broadcast(context: Context): Promise<void>;
```

Publishes context to other apps on the desktop. Calling `broadcast` at the `DesktopAgent` scope will push the context to whatever `Channel` the app is joined to. If the app is not currently joined to a channel, calling `fdc3.broadcast` will have no effect. Apps can still directly broadcast and listen to context on any channel via the methods on the `Channel` class.
Expand Down Expand Up @@ -219,7 +219,7 @@ let current = await fdc3.getCurrentChannel();
### `getInfo`

```ts
getInfo(): ImplementationMetadata;
getInfo(): Promise<ImplementationMetadata>;
```

Retrieves information about the FDC3 Desktop Agent implementation, such as the implemented version of the FDC3 specification and the name of the implementation provider.
Expand All @@ -231,7 +231,7 @@ Returns an [`ImplementationMetadata`](Metadata#implementationmetadata) object.
```js
import {compareVersionNumbers, versionIsAtLeast} from '@finos/fdc3';

if (fdc3.getInfo && versionIsAtLeast(fdc3.getInfo(), "1.2")) {
if (fdc3.getInfo && versionIsAtLeast(await fdc3.getInfo(), "1.2")) {
await fdc3.raiseIntentForContext(context);
} else {
await fdc3.raiseIntent("ViewChart", context);
Expand Down
6 changes: 3 additions & 3 deletions docs/api/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ From version 1.2 of the FDC3 specification, Desktop Agent implementations MUST p
```js
import {compareVersionNumbers, versionIsAtLeast} from '@finos/fdc3';

if (fdc3.getInfo && versionIsAtLeast(fdc3.getInfo(), '1.2')) {
if (fdc3.getInfo && versionIsAtLeast(await fdc3.getInfo(), '1.2')) {
await fdc3.raiseIntentForContext(context);
} else {
await fdc3.raiseIntent('ViewChart', context);
Expand Down Expand Up @@ -321,9 +321,9 @@ const appChannel = await fdc3.getOrCreateChannel('my_custom_channel');
// get the current context of the channel
const current = await appChannel.getCurrentContext();
// add a listener
appChannel.addContextListener(null, context => {...});
await appChannel.addContextListener(null, context => {...});
// broadcast to the channel
appChannel.broadcast(context);
await appChannel.broadcast(context);

```

Expand Down
6 changes: 3 additions & 3 deletions src/api/Channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export interface Channel {
*
* `Error` with a string from the `ChannelError` enumeration.
*/
broadcast(context: Context): void;
broadcast(context: Context): Promise<void>;

/**
* Returns the last context that was broadcast on this channel. All channels initially have no context, until a
Expand All @@ -63,10 +63,10 @@ export interface Channel {
* Adds a listener for incoming contexts whenever a broadcast happens on this channel.
* @deprecated use `addContextListener(null, handler)` instead of `addContextListener(handler)`.
*/
addContextListener(handler: ContextHandler): Listener;
addContextListener(handler: ContextHandler): Promise<Listener>;

/**
* Adds a listener for incoming contexts of the specified context type whenever a broadcast happens on this channel.
*/
addContextListener(contextType: string | null, handler: ContextHandler): Listener;
addContextListener(contextType: string | null, handler: ContextHandler): Promise<Listener>;
}
10 changes: 5 additions & 5 deletions src/api/DesktopAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ export interface DesktopAgent {
* fdc3.broadcast(context);
* ```
*/
broadcast(context: Context): void;
broadcast(context: Context): Promise<void>;

/**
* Raises a specific intent for resolution against apps registered with the desktop agent.
Expand Down Expand Up @@ -169,13 +169,13 @@ export interface DesktopAgent {
/**
* Adds a listener for incoming Intents from the Agent.
*/
addIntentListener(intent: string, handler: ContextHandler): Listener;
addIntentListener(intent: string, handler: ContextHandler): Promise<Listener>;

/**
* Adds a listener for incoming context broadcast from the Desktop Agent.
* @deprecated use `addContextListener(null, handler)` instead of `addContextListener(handler)`.
*/
addContextListener(handler: ContextHandler): Listener;
addContextListener(handler: ContextHandler): Promise<Listener>;

/**
* Adds a listener for incoming context broadcasts from the Desktop Agent. If the consumer is only interested in a context of a particular type, they can they can specify that type. If the consumer is able to receive context of any type or will inspect types received, then they can pass `null` as the `contextType` parameter to receive all context types.
Expand All @@ -187,7 +187,7 @@ export interface DesktopAgent {
* const contactListener = fdc3.addContextListener('fdc3.contact', contact => { ... });
* ```
*/
addContextListener(contextType: string | null, handler: ContextHandler): Listener;
addContextListener(contextType: string | null, handler: ContextHandler): Promise<Listener>;

/**
* Retrieves a list of the System channels available for the app to join
Expand Down Expand Up @@ -243,5 +243,5 @@ export interface DesktopAgent {
* the implemented version of the FDC3 specification and the name of the implementation
* provider.
*/
getInfo(): ImplementationMetadata;
getInfo(): Promise<ImplementationMetadata>;
}
40 changes: 24 additions & 16 deletions src/api/Methods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,21 @@ function rejectIfNoGlobal(f: () => Promise<any>) {
return window.fdc3 ? f() : Promise.reject(UnavailableError);
}

function throwIfNoGlobal(f: () => any) {
if (!window.fdc3) {
throw UnavailableError;
}
return f();
}

/**
* Utility function that returns a promise that will resolve immeadiately
* if the desktop agent API is found at `window.fdc3`. If the API is found,
* the promise will resolve when the `fdc3Ready` event is received or if it
* is found at the end of the specified timeout. If the API is not found, it
* will reject with an error.
*
* ```javascript
* await fdc3Ready();
* const intentListener = await addIntentListener("ViewChart", intentHandlerFn);
* ```
*
* @param waitForMs The number of milliseconds to wait for the FDC3 API to be
* ready. Defaults to 5 seconds.
*/
export const fdc3Ready = async (waitForMs = DEFAULT_TIMEOUT): Promise<void> => {
return new Promise((resolve, reject) => {
// if the global is already available resolve immediately
Expand Down Expand Up @@ -51,8 +59,8 @@ export function findIntentsByContext(context: Context): Promise<AppIntent[]> {
return rejectIfNoGlobal(() => window.fdc3.findIntentsByContext(context));
}

export function broadcast(context: Context): void {
throwIfNoGlobal(() => window.fdc3.broadcast(context));
export function broadcast(context: Context): Promise<void> {
return rejectIfNoGlobal(() => window.fdc3.broadcast(context));
}

export function raiseIntent(intent: string, context: Context, app?: TargetApp): Promise<IntentResolution> {
Expand All @@ -63,19 +71,19 @@ export function raiseIntentForContext(context: Context, app?: TargetApp): Promis
return rejectIfNoGlobal(() => window.fdc3.raiseIntentForContext(context, app));
}

export function addIntentListener(intent: string, handler: ContextHandler): Listener {
return throwIfNoGlobal(() => window.fdc3.addIntentListener(intent, handler));
export function addIntentListener(intent: string, handler: ContextHandler): Promise<Listener> {
return rejectIfNoGlobal(() => window.fdc3.addIntentListener(intent, handler));
}

export function addContextListener(
contextTypeOrHandler: string | null | ContextHandler,
handler?: ContextHandler
): Listener {
): Promise<Listener> {
//Handle (deprecated) function signature that allowed contextType argument to be omitted
if (typeof contextTypeOrHandler !== 'function') {
return throwIfNoGlobal(() => window.fdc3.addContextListener(contextTypeOrHandler, handler as ContextHandler));
return rejectIfNoGlobal(() => window.fdc3.addContextListener(contextTypeOrHandler, handler as ContextHandler));
} else {
return throwIfNoGlobal(() => window.fdc3.addContextListener(null, contextTypeOrHandler as ContextHandler));
return rejectIfNoGlobal(() => window.fdc3.addContextListener(null, contextTypeOrHandler as ContextHandler));
}
}

Expand All @@ -99,8 +107,8 @@ export function leaveCurrentChannel(): Promise<void> {
return rejectIfNoGlobal(() => window.fdc3.leaveCurrentChannel());
}

export function getInfo(): ImplementationMetadata {
return throwIfNoGlobal(() => window.fdc3.getInfo());
export function getInfo(): Promise<ImplementationMetadata> {
return rejectIfNoGlobal(() => window.fdc3.getInfo());
}

/**
Expand Down
Loading

0 comments on commit 0ece665

Please sign in to comment.