FDC3 icon indicating copy to clipboard operation
FDC3 copied to clipboard

Allow Desktop Agent To Join Multiple Channels

Open sgd2z opened this issue 3 years ago • 23 comments

Enhancement Request

We would like to propose allowing the desktop agent to join multiple channels.

Use Case:

image

Note the screenshot above. Here two blotters (let's say portfolio views) are sharing the same chart and news content. These portfolio views are themselves driven by different account views.

Workflow Description and Example:

  • User links one account view to one portfolio view on the green channel (so when the user switches to another account, the portfolio switches to that account)
  • User links a second account view to a second portfolio view on the red channel
  • User links charts and news on both red channel and green channel (so clicking on a symbol in either portfolio changes the chart and news to that symbol)

Additional Information

This would require the following API additions

leaveChannel(channelId: string) : Promise<void>;
getCurrentChannels() : Promise<void>;

and following API removals

leaveCurrentChannel() : Promise<void>;
getCurrentChannel() : Promise<void>;

sgd2z avatar Sep 15 '20 16:09 sgd2z

Isn't this already catered for by the current API? My recollection is hazy but I thought this is why we allow retrieving multiple channel objects and calling "join" on each... this is quite an advanced use case, and it is therefore supported by advanced API usage on individual channel objects.

Happy to discuss how we can make it more accessible of course, but I need to understand more whether this is an actual use case people have - I have always thought there is a one-to-one correspondence between a single component and a single channel.

It looks like you are rolling up the channels for multiple sub-components into one window, or am I misunderstanding?

rikoe avatar Sep 15 '20 20:09 rikoe

@rikoe - you can currently send and receive on multiple channels using the API. However, the DesktopAgent is limited to one channel. This means that other channels are meant exclusively for under the hood API communication as opposed to user driven linking of components. It also makes it a bit janky when you "join a channel" to be kicked off of other channels. While this is an advanced use case, it is not one hard to imagine on a Financial desktop.

We currently support this in Finsemble and were initially planning on removing this functionality to make it simple - one component, one channel (plus would make it easy to adopt the current FDC3 as the standard method of communication in the product) until we had a customer report an issue with multiple channels and discovered that such functionality is in use by end users.

sgd2z avatar Sep 16 '20 16:09 sgd2z

We've also be brainstorming alternatives with 'single channels' but with a direction that the end-user can specify. The developer can (sort of) do that by just not listening OR not broadcasting, but thats inflexible and defeats the point of having a user accessible channel selector. Further, setting a channel per direction (listen/broadcast) needs a more complex UI. Hence, supporting joining multiple channels actually seems the simplest (to implement/for user to understand) approach...

kriswest avatar Sep 18 '20 13:09 kriswest

I don't have a problem with this requirement, I think you've illustrated the use case well with the accompanying picture.

Some observations:

  • Ideally I don't want to get to the place where we start removing methods. Like Google Protobuf, we should see existing APIs as pretty much permanent, with interop there is a greater onus on maintaining backwards compatibility.

  • We can easily extend the current functions to take a single string or an array, without breaking backwards compatibility.

  • Calling join shouldn't kick you off of private channels, when you have used the separate Channel.addContextListener API in my opinion (which is how you should implement multiple channels with 1.1)

    It also makes it a bit janky when you "join a channel" to be kicked off of other channels.

  • You don't need to wait for FDC3 to approve and add APIs you would like to add to your desktop agent, feel free to add as many extensions/changes as you want, and front-run the current standard version (think of it like the W3C standards in this respect).

What about the following:

joinChannel(channelId: string) : Promise<void>;
leaveChannel(channelId: string): Promise<void>;
leaveCurrentChannel() : Promise<void>;
getCurrentChannel() : Promise<Channel>;
getJoinedChannels(): Promise<Channel[]>;

The only caveat is that the desktop agent will need to decide what the "current channel" is if joined to multiple - maybe the channel that most recently received a message? This is not ideal, but less bad than removing methods, imo.

rikoe avatar Sep 21 '20 14:09 rikoe

@sgd2z @rikoe @kriswest note Multiple Channel membership breaks DesktopAgent.addContextListener (there is no way in this API to indicate what channel a context came over)

The intention was to allow apps to support multiple channel membership via channel subscriptions (i.e. Channel.addContextLIstener) IMHO the UI of multiple channel membership can then be handled in AppLand - where it is better suited for handling the UX ambiguities of multiple channels.

nkolba avatar Sep 23 '20 03:09 nkolba

@nkolba - I don't see how it matters what channel it came over. That could be a future enhancement to the spec.

However, in the current state we have a hole: Channel API - Invisible to the user what Channels you are on Desktopagent API - only one channel that the user can see. joining another channel, leaves current channel. This is not so hard for end users to understand:

image

sgd2z avatar Sep 23 '20 14:09 sgd2z

joinChannel(channelId: string) : Promise<void>;
leaveChannel(channelId: string): Promise<void>;
leaveCurrentChannel() : Promise<void>;
getCurrentChannel() : Promise<Channel>;
getJoinedChannels(): Promise<Channel[]>;

The only caveat is that the desktop agent will need to decide what the "current channel" is if joined to multiple - maybe the channel that most recently received a message? This is not ideal, but less bad than removing methods, imo.

That sounds reasonable to me. Actually might just be easier to do the plurals:

joinChannels(channels: string[]) : Promise<void>;
leaveChannels(channels: string[]): Promise<void>;
leaveCurrentChannel() : Promise<void>;
getCurrentChannel() : Promise<Channel>;
getCurrentChannels(): Promise<Channel[]>;

sgd2z avatar Sep 23 '20 15:09 sgd2z

I think this is a bad UX idea, but if we decide to adopt this, then I think we will also need to add timestamps to channel contexts. Consider the case where a new window is started and allocated to the red and green channel. How does the application decide which channel to get the instrument ? I assume that the expectation would be in time order (since if the application was running before the user selected an instrument on the green channel, followed by selecting an instrument on the red channel, where the expectation would be the app would display the instrument from the red channel). Again I think this is bad UX, but of we are going to add this, then we will need to chose which context to use for each value.

lspiro-Tick42 avatar Jul 01 '21 13:07 lspiro-Tick42

I think it worth clarifying that the case you point to only applies contexts already on the channels (presumably retrieved via getCurrentContext), as it is intended that you process context from broadcasts as they arrive. Further, as the user adds components to channels one at a time (you can't click on/join two channels simultaneously without a UI that has been expressly designed to achieve that) and the proposed API only allows you to join a channel at a time, you pick up the context of the channel as you join it. Hence, time order is implicit and a timestamp would not add anything.

We've spent some time canvassing clients on this topic as we needed to decide whether to move from multi-channel to single - the general consensus was that multi-channel membership is not hard to understand, has use-cases and is easy to make optional (the user doesn't have to use it and a product flag or preference could disable it without disrupting the API).

kriswest avatar Jul 05 '21 09:07 kriswest

@kriswest say I have a window that is connected to the Red and Green channel, and that it has been reacting to updates to 'the instrument' on the red channel and yellow channel.

I then start a new window, and connect it to the Red and Green channel, so this should show the same Instrument as the first window, but there is only a 50% chance of that without the timestamp.

I am not saying that this is a huge issue, it's not like missing a trade. Things will settle down on the next update of the Instrument, but it is a 'glitch' if not a bug, and could be fixed if contexts had a time stamp (or we disallowed being on multiple channels).

Also in conclusion, as far as I know neither Refinitiv nor Bloomberg support a window joining multiple channels, and they have been using the concept of channels for a very long time.

lspiro-Tick42 avatar Jul 05 '21 10:07 lspiro-Tick42

I then start a new window, and connect it to the Red and Green channel, so this should show the same Instrument as the first window, but there is only a 50% chance of that without the timestamp.

You can't add it to the 'Red and Green channel', you can add it to the Red Channel and then the Green channel or vice versa. The ordering is up to the user. Whether the component then checks the current context and applies it or waits for a message to be transmitted on either channel is up to the component developer (as retrieving current context requires an additional step - one you can't actually implement at the moment as the component doesn't know its been added to a channel!).

My point is that there isn't a glitch as you can't join the channels simultaneously - it's more intuitive than it looks at first glance. I'm being pedantic about the UX as I've used it and seen clients use it. However, I'm not actually arguing for or against it as a UX decision - other than to say that for multi-channel to be possible the API needs to enable it, however, single channel can also be supported via that API if preferred (by Desktop Agent or the Desktop owner).

kriswest avatar Jul 05 '21 12:07 kriswest

~Added a comment to #313 based on this discussion - there's currently no way to know a user added you to a channel and that you need to go retrieve the current context (without periodically polling).~

~N.B. Were we to add either the proposed channel listener or to make channels more PubSub-like (by calling the context listener automatically when you join a channel), you'd still join channels one-at-a-time.~

kriswest avatar Jul 05 '21 12:07 kriswest

Channels joined via the DesktopAgent are PubSub like - which should be clarified in the spec and documentation: https://github.com/finos/FDC3/issues/418 Nevertheless, the API only allows you to join them one at a time ;-)

kriswest avatar Jul 05 '21 15:07 kriswest

A Standards Working Group vote is needed on this issue; should it be updated and merged into the 2.0 scope or closed?

Issue summary:

  • Allow joining multiple channels through the desktop agent
    • Existing Desktop agent functions:
      • joinChannel(channelId: string) : Promise<void>;
      • leaveCurrentChannel() : Promise<void>; - backwards compatibility, definition updated to work with channel that last received data
      • getCurrentChannel() : Promise<Channel>; - backwards compatibility, definition updated to work with channel that last received data
    • New Desktop Agent Functions:
      • leaveChannel(channelId: string): Promise<void>; - successor to leaveCurrentChannel()
      • getJoinedChannels(): Promise<Channel[]>; - successor to getCurrentChannel()
  • Channels are joined one at a time, existing on the channel is received as each channel is joined.
  • fdc3.addContextListener will receive messages from all channels joined, there is no way to differentiate which channel each message came from.
  • A desktop agent might still choose to only support single-channel membership, where joinChannel() causes you to leave any existing joined channel

Please thumbs up to vote to proceed, thumbs down to vote to close. The vote will be kept open until a few days after the next SWG meeting (Thursday 22nd July 2021).

kriswest avatar Jul 13 '21 10:07 kriswest

If we allow optional support for 'join multiple channels', then we should add a desktop capabiltiies option, so an app can query if join multiple channels is supported.

lspiro-Tick42 avatar Jul 15 '21 13:07 lspiro-Tick42

I am in favour of allowing an app to programatically join multiple channels (and needs to get list of available channels), we use this for briidge type applications. However when a user can select the channel an app is 'joined to' I propose that is restricted to a single channel

lspiro-Tick42 avatar Jul 15 '21 13:07 lspiro-Tick42

@lspiro-Tick42 The proposal is to allow the join multiple channels via the fdc3.joinChannel function (joining a channel via the desktop agent). I think what you are referring to is retrieving a channel object (via fdc3.getOrCreateChannel), adding a listener to it and broadcasting via channel.broadcast (interacting with a channel via the channel API).

If we allow optional support for 'join multiple channels', then we should add a desktop capabilities option, so an app can query if join multiple channels is supported.

As:

  • the intention is that the UI in the Desktop agent join an application to a channel
  • several participants in the recent discussion group meeting proposed that we deprecate programmatically joining channels/the joinChannel function
  • the functions for interacting the channel(s) you have been joined to do not change (broadcast/addContextListener)

there seems little utility in discovering whether join multiple channels is supported - it would make no actual difference to code you write or run to interact with the channel(s). The only time it actually matters is when you are building your own channel selector inside a component (which wouldn't be supported if joinChannel does actually get deprecated).

That said you could just check if fdc3.getJoinedChannels is implemented for capability discovery.

kriswest avatar Jul 22 '21 08:07 kriswest

@kriswest I would like to provide one real use-case that really needs multiple channels.

On our users’ desktop, there are many different apps, e.g. trade booking app, market analytics app, pricing app, risk app and reporting app. For a specific app, users can choose which apps (colors of channel) to link (join channels) for contextualization. The given app should be able to link to multiple apps according to different scenarios. In this case, it’s users who join/leave channels rather than apps, what an app does is to broadcast contexts or handle with the contexts it receives in the channels it listens to. Therefore, calling the methods (broadcast/addContextListener) on the Channel class isn't suitable for such case.

So far FDC3 doesn’t support multiple channels, so in order to satisfy this use-case, we had to create two extra APIs (publishToChannel and addChannelListener) that were not specified in FDC3 standard. addChannelListener allows users to link a specific app to multiple channels, and publishToChannel will broadcast the context to all linked channels.

Qiana-Citi avatar Aug 26 '21 12:08 Qiana-Citi

@Qiana-Citi many thanks for your input and details of your use-case.

So far FDC3 doesn’t support multiple channels, so in order to satisfy this use-case, we had to create two extra APIs (publishToChannel and addChannelListener) that were not specified in FDC3 standard. addChannelListener allows users to link a specific app to multiple channels, and publishToChannel will broadcast the context to all linked channels.

We have been able to support multiple channels without the additional functions. As 'it’s users who join/leave channels rather than apps' we only had to modify the UI they do this with and allow apps to exist in multiple channels. The interface for the app developer is unmodified (they addContextListener and broadcast which then apply to all channels they are currently joined to). We have not provided a programmatic interface to joining and leaving multiple channels (other than to ensure joinChannel adds to rather than replaces your current channel and leaveCurrentChannel removes you from all channels).

I wonder if you're two functions were proposed prior to the addition of channels in FDC3 1.1. Are you happy with the proposed additional functions (leaveChannel(channelId: string): Promise<void>; and getJoinedChannels(): Promise<Channel[]>;) which would allow for the explicit support of multiple channels or are there additional nuances to the two extra API calls that you added that we should discuss?

kriswest avatar Sep 06 '21 13:09 kriswest

@kriswest Thank you for the reply.

Yes, the proposed additional functions are exactly what we are looking for. In our previous plan, we would deprecate the two extra APIs (publishToChannel and addChannelListener) right after the multiple channels are supported (leaveChannel and getJoinedChannels are specified) by FDC3 standard.

If the two proposed additional functions won't be planned in FDC3 standard, we would consider implementing them as extensions.

Qiana-Citi avatar Sep 08 '21 13:09 Qiana-Citi

After the last SWG meeting (#459), and based on the informal votes received, it was decided to remove this issue from the FDC3 2.0 milestone - but not to close it to allow discussion to continue or a PR to be submitted for consideration.

kriswest avatar Sep 30 '21 10:09 kriswest

@timjenkel @keithbloom I was told at OSFF yesterday that there's interest at your firm's in being able to join multiple channels in FDC3. This issue hasn't moved in a long.time, but we can bring it back for a further discussion and I can post an updated proposal for (optional) additional API calls for working with it.

If you are keen to see this move forward please post something here (a note on use case would be ideal)

kriswest avatar Nov 02 '23 19:11 kriswest

@kriswest I checked with the person you talked to and I think their comment was actually related to Desktop Agent Bridging and not this issue

This does sound like a useful enhancement, but I'm not sure that we have an immediate use case that requires it

timjenkel avatar Nov 09 '23 17:11 timjenkel