finos / FDC3

An open standard for the financial desktop.
https://fdc3.finos.org
Other
199 stars 131 forks source link

Question: How does a context from open(app, context) interact with broadcasting? #1350

Closed ZKRobi closed 1 month ago

ZKRobi commented 2 months ago

Question Area

Question

The specification of the open(app, context) method explains the context will be provided via a contextListener.

What is not clear from the specification is how does this interact with other parts of the standard. Can you help clarify what should happen in the following scenarios?

The opened app joins a user channel before registering a matching handler

  1. Channel.1 currently has the following context on it: { type: "fdc3.instrument", name: "Instrument 1" }.
  2. App.1 calls fdc3.open({ appId: "App.2" }, { type: "fdc3.instrument", name: "Instrument 2" })
  3. App.2 is opened, fdc3 is ready
  4. App.2 joins Channel.1
  5. App.2 calls fdc3.addContextListener("fdc3.instrument", context => { console.log(context.name) })

The opened app adds multiple matching context listeners

According to the standard this is not clear if only one, or more context listeners will get the context provided for open and if more, to what extent.

  1. App.1 calls fdc3.open({ appId: "App.2" }, { type: "fdc3.instrument", name: "Instrument 1" })
  2. App.2 is opened, fdc3 is ready. 15 seconds of timeout is allowed for registering.
  3. App.2 calls fdc3.addContextListener("fdc3.instrument", context => { console.log("handler 1: " + context.name) })
  4. App.2 calls fdc3.addContextListener("fdc3.instrument", context => { console.log("handler 2: " + context.name) })
  5. 16 seconds pass
  6. App.2 calls fdc3.addContextListener("fdc3.instrument", context => { console.log("handler 3: " + context.name) })
  7. App.2 joins Channel.1
  8. App.1 broadcasts { type: "fdc3.instrument", name: "Instrument 2" } on Channel.1
  9. App.2 calls fdc3.addContextListener("fdc3.instrument", context => { console.log("handler 4: " + context.name) })
kriswest commented 2 months ago

HI @ZKRobi, you're looking at one of my least favourite parts of the FDC3 Standard as I don't think it's well thought out and has been present since FDC3s inception before joinUserChannel existed (see http://localhost:3000/docs/1.0/api/DesktopAgent#open) and before the idea of auto-receiving context on adding a listener/joining existed. The reuse of the user channels context listener for delivering the fdc3.open context is not ideal due to the edge case you are looking at. If the app is opened with context and joins a channel before adding a context listener, what should be delivered first, the open context or the channel context? Should one be dropped? The Standard doesn't (or didn't) say.

In 2.1 we added the statement:

Context may also be received via this listener if the application was launched via a call to fdc3.open, where context was passed as an argument. In order to receive this, applications SHOULD add their context listener as quickly as possible after launch, or an error MAY be returned to the caller and the context may not be delivered. The exact timeout used is set by the Desktop Agent implementation, but MUST be at least 15 seconds.

https://fdc3.finos.org/docs/api/ref/DesktopAgent#addcontextlistener

Which, combined with the following statement on joining channels:

Joining channels in FDC3 is intended to be a behaviour initiated by the end user.

Loosely implies that you (an app) should add context listeners before joining a channel (as the user will do that themselves after you've initialized). That would mean that the context from fdc3.open can be delivered before there could be context from a channel.

In practice DA implementors often add features like auto-joining apps to channels based on what channel the app that opened them was on, or initial channels set in config etc., which affects that. In those cases, I think it best to always deliver the queued-up context from fdc3.open first and then follow it up with that from the channel as the context from open is not necessarily the same type and their combination might be important (e.g. your channel contains an instrument and you opened a position blotter filtered to a customer or timerange etc.. I would be inclined to apply this logic to all context listeners added - if the context from open matches their filter, deliver that to it first, then anything from the channel.

Where the context types differ you haven't got as much of a problem as channels can already contain different types and retain the most instance of each that has been broadcast, so its not a problem to add another context into the mix. The problem is limited to where you have the same type on the channel and sent via open - in that situation you could deliver one then the other or simply deliver the most recent (i.e. assume its meant to replace the previous context of the same type).

Finally, I don't think fdc3.open is used as much fdc3.raiseIntent to open apps with context (raiseIntent adds an action verb in the form of the intent). As raised intents and their associated contexts are delivered to a different listener the problem is reduced, and its down to apps to decide what they do if they receive conflicting context via the two different listeners.

To be clear, this is advice from my/our experience of implementing this behaviour. I do not think it is well defined in the FDC3 standard and I think we could apply some edits to clarify and standardize behaviour here. As you're thinking about this topic I'd be interested in whether you agree with what I propose above and any thoughts you have on where this would have been most helpfully clarified in the documentation.

psmulovics commented 2 months ago

thank you - this is useful, let us check whether we have more questions on this

kriswest commented 1 month ago

Closing as completed - please reopen if there are further questions or discussion to have!