Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Context Clearing #1379

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions docs/api/ref/Channel.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ interface Channel {
broadcast(context: Context): Promise<void>;
getCurrentContext(contextType?: string): Promise<Context|null>;
addContextListener(contextType: string | null, handler: ContextHandler): Promise<Listener>;
clearContext(contextType?: string): Promise<void>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we should require an explicit null argument (contextType: string | null) to clear all types - which would match addContectListener or stick with this (matching getCurrentContext). Either works of course.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me it makes sense to keep it closer to getCurrentContext, because they seem most related to me, but happy to hear any thoughts/suggestions.

Copy link
Contributor

@kriswest kriswest Oct 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a historical reason for addContextListener having an explicit null argument, the contextType argument was originally optional so the handler argument could be either first or second (when a type was specified). This was NOT good in practice so we moved to an explicit null argument and deprecated the single argument override:
https://fdc3.finos.org/docs/2.0/api/ref/DesktopAgent#addcontextlistener-deprecated

We don't have that problem here, so I agree its fine as is (matching getCurrentContext).


//deprecated functions
/**
Expand All @@ -57,6 +58,7 @@ interface IChannel: IIntentResult
Task Broadcast(IContext context);
Task<IContext?> GetCurrentContext(string? contextType);
Task<IListener> AddContextListener<T>(string? contextType, ContextHandler<T> handler) where T : IContext;
Task ClearContext(string? contextType);
bingenito marked this conversation as resolved.
Show resolved Hide resolved
}
```

Expand Down Expand Up @@ -431,6 +433,99 @@ catch (Exception ex)
- [`broadcast`](#broadcast)
- [`addContextListener`](#addcontextlistener)

### `clearContext`

<Tabs groupId="lang">
<TabItem value="ts" label="TypeScript/JavaScript">

```ts
public clearContext(contextType?: string): Promise<void>;
```

</TabItem>
<TabItem value="dotnet" label=".NET">

```csharp
Task ClearContext(string? contextType);
```

</TabItem>
</Tabs>

Used to clear the specified context type if provided, otherwise, clear all contexts. Desktop Agent MUST update internal context. Any future calls to [`getCurrentContext`](#getcurrentcontext) and any new joiners on that channel (through [`joinUserChannel`](DesktopAgent#joinUserChannel) or [`addContextListener`](DesktopAgent#addContextListener)) will not receive anything for specified context type or all contexts accordingly.
kemerava marked this conversation as resolved.
Show resolved Hide resolved
Desktop Agent MUST update all channel listeners subscribed to the [`fdc3.nothing`](../../context/ref/Nothing.md/#nothing) type. If `contextType` is provided, then `subType` will be specified, otherwise, it is ommitted.
kemerava marked this conversation as resolved.
Show resolved Hide resolved


**Examples:**

Without specifying a context type:

<Tabs groupId="lang">
<TabItem value="ts" label="TypeScript/JavaScript">

```ts
try {
const context = await channel.clearContext();
} catch (err: ChannelError) {
// handle error
}
```

</TabItem>
<TabItem value="dotnet" label=".NET">

```csharp
try
{
var context = await channel.ClearContext();
}
catch (Exception ex)
{
// handle error
}
```

</TabItem>
</Tabs>

Specifying a context type:

<Tabs groupId="lang">
<TabItem value="ts" label="TypeScript/JavaScript">

```ts
try {
const contact = await channel.clearContext('fdc3.contact');
} catch (err: ChannelError) {
// handler error
}
```

</TabItem>
<TabItem value="dotnet" label=".NET">

```csharp
try
{
var context = await channel.ClearContext("fdc3.contact");
}
catch (Exception ex)
{
// handle error
}
```

</TabItem>
</Tabs>


**See also:**

- [`getCurrentContext`](#getcurrentcontext)
- [`addContextListener`](DesktopAgent#addContextListener)
- [`joinUserChannel`](DesktopAgent#joinUserChannel)
- [`fdc3.nothing`](../../context/ref/Nothing.md/#nothing)

## Deprecated Functions

### `addContextListener` (deprecated)
Expand Down
7 changes: 5 additions & 2 deletions docs/api/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ When raising an intent a specific context is provided as input. The type of the

A context type may also be associated with multiple intents. For example, an `fdc3.instrument` could be associated with `ViewChart`, `ViewNews`, `ViewAnalysis` or other intents.

To raise an intent without a context, use the [`fdc3.nothing`](../context/ref/Nothing) context type. This type exists so that applications can explicitly declare that they support raising an intent without a context (when registering an `IntentHandler` or in an App Directory).
To raise an intent without a context, use the [`fdc3.nothing`](../context/ref/Nothing) context type. This type exists so that applications can explicitly declare that they support raising an intent without a context (when registering an `IntentHandler` or in an App Directory). This type is also used when the context is cleared for the channel. If the optional context type is provided when performing [`clearContext`](ref/Channel.md#clearcontext), that type will be recorded in the field `subType` of [`fdc3.nothing`](../context/ref/Nothing) context type.

As an alternative to raising a specific intent, you may also raise an unspecified intent with a known context allowing the Desktop Agent or the user (if the intent is ambiguous) to select the appropriate intent and then to raise it with the specified context for resolution.

Expand Down Expand Up @@ -585,7 +585,7 @@ Apps can join *User channels*. An app can only be joined to one User channel at

When an app is joined to a User channel, calls to [`fdc3.broadcast`](ref/DesktopAgent#broadcast) will be routed to that channel and listeners added through [`fdc3.addContextListener`](ref/DesktopAgent#addcontextlistener) will receive context broadcasts from other apps also joined to that channel. If an app is not joined to a User channel [`fdc3.broadcast`](ref/DesktopAgent#broadcast) will be a no-op and handler functions added with [`fdc3.addContextListener`](ref/DesktopAgent#addcontextlistener) will not receive any broadcasts. However, apps can still choose to listen and broadcast to specific channels (both User and App channels) via the methods on the [`Channel`](ref/Channel) class.

When an app joins a User channel, or adds a context listener when already joined to a channel, it will automatically receive the current context for that channel.
When an app joins a User channel, or adds a context listener when already joined to a channel, it will automatically receive the current context for that channel, unless the context was cleared through [`clearContext`](ref/Channel.md#clearcontext).

It is possible that a call to join a User channel could be rejected. If for example, the desktop agent wanted to implement controls around what data apps can access.

Expand Down Expand Up @@ -830,6 +830,9 @@ The [Context specification](../context/spec#assumptions) recommends that complex

To facilitate context linking in such situations it is recommended that applications `broadcast` each context type that other apps (listening on a User Channel or App Channel) may wish to process, starting with the simpler types, followed by the complex type. Doing so allows applications to filter the context types they receive by adding listeners for specific context types - but requires that the application broadcasting context make multiple broadcast calls in quick succession when sharing its context.

### Context clearning on channels
Channel interface provides the ability to [`clearContext`](ref/Channel.md#clearcontext) on the channel, either for the specific context type, if provided, or for all contexts on that channel. If provided, the specified type will be recorded in the `subType` field of the [`fdc3.nothing`](../context/ref/Nothing) context type. Once cleared, any subsequent new joiners on the channel, new context listeners on the context or calls to [`getCurrentContext`](ref/Channel.md#getcurrentcontext) will not return anything to the caller.
kemerava marked this conversation as resolved.
Show resolved Hide resolved

### Originating App Metadata

Optional metadata about each context message received, including the app that originated the message, SHOULD be provided by the desktop agent implementation to registered context handlers on all types of channel. As this metadata is optional, apps making use of it MUST handle cases where it is not provided.
7 changes: 6 additions & 1 deletion schemas/context/nothing.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,19 @@
"properties": {
"type": {
"const": "fdc3.nothing"
},
"subtype": {
"type": "string",
"description": "A subtype of the context type. This can be used to provide a specific context which should be cleared, if ommitted, all contexts will be cleared"
kemerava marked this conversation as resolved.
Show resolved Hide resolved
}
}
},
{ "$ref": "context.schema.json#/definitions/BaseContext" }
],
"examples": [
{
"type": "fdc3.nothing"
"type": "fdc3.nothing",
"subtype": "fdc3.timeRange"
kemerava marked this conversation as resolved.
Show resolved Hide resolved
}
]
}
9 changes: 9 additions & 0 deletions src/api/Channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,15 @@ export interface Channel {
*/
addContextListener(contextType: string | null, handler: ContextHandler): Promise<Listener>;

/**
* Provides the ability to clear context from the channel. Subsequent connection to this channel or calls to get current context will not return anything (accounting for contextType if specified).
kemerava marked this conversation as resolved.
Show resolved Hide resolved
*
* If a `contextType` is provided, only contexts of that type will be cleared.
kemerava marked this conversation as resolved.
Show resolved Hide resolved
*
* If no `contextType` is provided, all contexts will be cleared.
kemerava marked this conversation as resolved.
Show resolved Hide resolved
*/
clearContext(contextType?: string): Promise<void>;

/**
* @deprecated use `addContextListener(null, handler)` instead of `addContextListener(handler)`.
*/
Expand Down