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

Turning off context sharing via Channels API #118

Closed
vmehtafds opened this issue Aug 26, 2019 · 15 comments
Closed

Turning off context sharing via Channels API #118

vmehtafds opened this issue Aug 26, 2019 · 15 comments
Labels
api FDC3 API Working Group

Comments

@vmehtafds
Copy link

Feature Request

Description of Problem:

We have a use case that we currently support with our internal Channels where a user can turn off context sharing via the UI. We have exposed that as OFF channel in our channel selector.
image

In the FDC3 land, we have our apps which use the top level FDC3 API (broadcast and addContextListener) to send and receive context. They are unaware of Channels API and would work if they wrapped in a TitleBar that has Channels support vs a TitleBar that doesn't have channels support.
The TitleBar is what interacts with the Channels api and exposes a UI (dropdown select) to pick channel and that sets the channel for the app. The TitleBar acts as the router for the traffic.

Currently the way to have the off channel or turning off the context sharing based on some UI in the TitleBar (i.e. an OFF option in the dropdown) is by making the app aware of the TitleBar and removing the context listener when that OFF option is selected. This prevents our initial goal of app being unaware of Channels.

Potential Solutions:

There are few solutions.

  • The TitleBar could create a AppChannel with an unique id per window and use it as the "OFF" channel for that window. As it is an unique id that no other window is aware of, no one can broadcast or listen to context shared by that window. - No API changes required. This is supported with current API.
  • Similar to default channel, create a new System-level off channel.
  • Add a myChannel.turnOff() API
@1christianhall
Copy link

As discussed briefly in the call today the question is whether it is the API's job or the implementer's to provide a way to mute/filter a channel to ensure that the channel is used or not.

The gut feel from folks on the call is that the channels API assumes that if a channel is being used, it is needed...so in your example above, you'd simply "detach" your title bar in this case from the channel when the GUI indicated the widget no longer should participate on a channel.

@nkolba
Copy link
Contributor

nkolba commented Dec 6, 2019

This feels like an implementation feature.

Also, it seems that at least some of the issue is due to the ambiguity around the "default" channel. The purpose of the default is to provide backwards compatibility for the 1.0 broadcast/addContextListener apis. Maybe an approach would be to add a addChannelListener method that only listened to system channels (not default)? Another approach would be to extend addContextListener with an options arg that supported configuration of the listener. E.g.

fdc3.addContextListener(ctx =>{...}, {default:false});

@nkolba nkolba added the 1.1 label Dec 6, 2019
@vmehtafds
Copy link
Author

Any attaching/detaching of the listener requires the app code (which sets up the fdc3.addContextListener()) to know that it inside a frame that supports channels.

My understanding was app doesn't need to know if the frame around it supports channels or not.

My simple analogy is to pipe with a tap dispensing water and a bucket to collect it. To me app just decides whether to have that bucket under the pipe to collect water or not. It doesn't decide whether water is running or at what speed. The bucket just know there is a pipe dispensing water. It doesn't even know about the existence of a tap.

The tap (analogous to the frame with channels) decides what speed the water flows (speed1=red-channel, speed2=green and so on) or if the tap is completely closed (off channel). The tap doesn't control if the bucket is there or not. It just adjust the water flow. That water could go in a bucket or just dropped on the floor.

Sorry if my example confused you even more 😄
I am sure there is a better analogy out there.

@rikoe
Copy link
Contributor

rikoe commented Jan 28, 2020

@vmehtafds the latest changes should address your concerns. The frame would use fdc3.joinChannel('red') without the contained app knowing about it.

The app would only need to do fdc3.addContextListener(context => {}).

The only caveat is that there is a default channel which matches the current 1.0 use case. Therefore fdc3.joinChannel('default') will "reset" the channel, or turn broadcasting off.

So in your example you wouldn't have a distinction between "off" and "universal", you would just have "default". If you really want to turn it off completely, you could use fdc3.getOrCreateChannel('my_empty_channel') and join that one to have no messages broadcast. But if no one broadcasts on the default channel, it would effectively be the same.

@nkolba @chedzoir @nicholasdgoodman does the above match your understanding? I don't have a problem with adding an explicitly built-in off system channel, if it will help with this use case.

@vmehtafds
Copy link
Author

vmehtafds commented Jan 28, 2020

I agree with you @rikoe and I know I could just make a dummy AppChannel and use that as off (which I mentioned in my original comment)
My question was exactly the last question you raised in your comment - do we want to standardize it? Looks like at least you don't have any problem with that.

@rikoe
Copy link
Contributor

rikoe commented Jan 28, 2020

Actually now that I think about it some more @vmehtafds, I don't think an off channel is the right solution at all. It is effectively a misuse of the FDC3 API to get the behaviour you want. If we create an official channel called "off", it would just be another system channel. Nothing would prevent apps from broadcasting to that channel or subscribing to it, which would be counter-intuitive. We would have to explicitly add a section to the spec creating this "special" channel that isn't a channel and that can't deliver events, even when they are sent (or a special exception to be thrown for this case).

I think the right solution is to have a boolean flag in your frame, shared with your contained apps, which can then be used to either unsubscribe when channels are turned off, or simply ignore any events while the flag is set. This will also be much more explicit to maintainers what is going on.

I.e. the right way not to listen to channels, is not to be subscribed to them!

If you really want to "hijack" channels to offer this functionality, you still have the option of creating a custom off channel with a name no one knows about, thereby achieving your aim of not having any events, without imposing the burden of additional logic on the standard and its implementers.

@nkolba @chedzoir @nicholasdgoodman @pjbroadbent any thoughts?

@vmehtafds
Copy link
Author

@rikoe - I was trying to figure out an appetite for off functionality in the standard (as we have something like that in FactSet Workstation and is useful). If no one else needs the off functionality then it doesnt make sense to add it to standard.
I agree off channel seems counter-intuitive. The other approach would be to add a new API to Channel for stopping/resuming (channel.stop() and channel.resume()). I dont want to complicate the standard/API if no one else sees a need for the "off" functionality.

@rikoe
Copy link
Contributor

rikoe commented Jan 30, 2020

@vmehtafds I was actually thinking similar thoughts. I don't mind a channel suspension feature, I think, I would just wonder about giving one application power to stop interaction for all others.

Also, based on your image above we would need such a feature for all channels, or am I understanding wrong?

Otherwise you would have to go fdc3.getSystemChannels().find(c => c.id === 'default').stop()?

@vmehtafds
Copy link
Author

@rikoe - I would imagine that the suspension would be only for the app calling it and not for every app.

The more I am also thinking about it now, I feel I want fdc3.leaveCurrentChannel() or something i.e. I should be able to say I am not in any channel and thus don't route any traffic to me.

Currently only way to leave a channel is to join another channel so there is no way to be not in any channel.

@rikoe
Copy link
Contributor

rikoe commented Jan 31, 2020

You can! listener.unsubscribe() 😉

@vmehtafds
Copy link
Author

@rikoe - Not really sure I understand. Is there a way for the frame to get the current listener?
The app which does fdc3.addContextListener() would have access to the listener(as the return argument). But not sure how the frame would get that listener object easily. I might be missing something obvious.

@nkolba
Copy link
Contributor

nkolba commented Feb 5, 2020

@vmehtafds TLDR: lengthy explanation is below, overall I'd recommend either implementing an "off" channel at the system level or changing the behavior of the "default" channel to not broadcast. Depending on how your titlebar is implemented, you may be able to polyfill this behavior from the titlebar without requiring the app to be aware of the plumbing.

...

The 1.0 spec is intentionally vague about the behavior of context routing in the broadcast API. The spec states the following:

On the financial desktop, applications often want to broadcast context to any number of applications. Context sharing needs to support concepts of different groupings of applications as well as data privacy concerns. Each Desktop Agent will have its own rules for supporting these features.
(https://fdc3.finos.org/docs/1.0/api/api-spec#send-broadcast-context)

And that broadcast Publishes context to other apps on the desktop. (https://fdc3.finos.org/docs/1.0/api/DesktopAgent#broadcast)

And that addContextListener Adds a listener for incoming context broadcast from the Desktop Agent. (https://fdc3.finos.org/docs/1.0/api/DesktopAgent#addcontextlistener)

The intention was to give desktop agents wide latitude in implementing business logic around how context is routed between apps. In 1.0 there is no contract guaranteeing delivery of a broadcast.

The addition of the channels APIs in 1.1 formalizes the implementation - so that there is now a contract for channels. From the 1.1 spec:

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[sic] broadcast over it or not.
(https://fdc3.finos.org/docs/next/api/api-spec#joining-channels)

Note that this contract quite explicitly is not binding for the default channel.

The expectation here is that if you are using SystemChannels to link app context sharing, the end user is only going to want apps sharing context if they have explicitly linked them through a color scheme or some other grouping like a workspace. However, this effectively means that the “default” channel becomes for all intents and purposes an “off’ channel for apps relying on fdc3.broadcast and fdc3.addContextListener. For these apps, the transition to the channels approach would constitute a breaking change. Note that if we instead had a “leaveChannel” api, we’d have the exact same problem with backwards compatibility/ Desktop agents would have to choose whether not being in a channel meant broadcast is a no-op (and potentially break 1.0 expectations) or if broadcast just routed globally if you weren’t in a channel (once again, requiring a “really off” state).

The expectation of the above part of the spec is that desktop agents making that transition are best positioned to make the rules about the default channel that make the most sense for them - especially since desktop agents are free to create what system channels they want and what rules they want around them. So, the desktop agent could have the default channel always broadcast and add its own “off” system channel.

To sum up:

  • The “default” channel is the state of an app when it is not joined to channel
  • Desktop Agents are required to route broadcast context on joined channels and to provide the current context when an app joins a channel for all channels except the “default"
  • It is up to the desktop agent to decide what the behavior of the “default” is an manage backwards compatibility with the pre-channels world of 1.0
  • Allowing an end user to remove an app from receiving broadcasts is a feature of a desktop agent - this could be the behavior of the “default” channel, or the desktop agent could expose a different “off” channel that would not route broadcasts

@nkolba
Copy link
Contributor

nkolba commented Feb 7, 2020

@vmehtafds - after some more discussions with @rikoe , I've made a proposed update to the spec, which you can see in #168.

The proposed behavior for the 'default' would have it effectively behave as an 'off' channel, those apps could opt-in to explicitly listen to its context if they wanted to. Your feedback on the PR would be very helpful!

@nkolba
Copy link
Contributor

nkolba commented Feb 8, 2020

@vmehtafds @rikoe Reference implementation @ https://github.com/nkolba/desktop-agent is now updated to work this way, if you want to see it in action.

@nkolba
Copy link
Contributor

nkolba commented Feb 27, 2020

Addressed with PR #171

@nkolba nkolba closed this as completed Feb 27, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api FDC3 API Working Group
Projects
None yet
Development

No branches or pull requests

4 participants