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

Fdc3 for web impl get agent refactor #1466

Merged
merged 99 commits into from
Jan 14, 2025

Conversation

kriswest
Copy link
Contributor

@kriswest kriswest commented Dec 10, 2024

Describe your change

Significant refactor of the fdc3-get-agent package to align it with the Standard and a number of change fdc3-agent-proxy or fdc3-web-impl that were necessitated by the changes.

Changes:

  • Refactored Session Storage to use new format as introduced in Updating SessionStorage data format to additionally scope data #1442
  • Session Storage data is used to limit discovery options to those used previously in the session
  • The TimeoutLoader was eliminated in favour of timeouts in the individual loading strategies (as some actions in Desktop Agent Proxy interfaces can occur beyond the timeout, e.g. identity validation and UI setup)
  • AbstractWebMessaging was eliminated and separation of concerns achieved between fdc3-agent-proxy and fdc3-get-agent. The former only handles the DACP protocol (making it easier to use for other puprposes) while the latter handles all WCP messaging (including WCP6Goodbye) to set-up the message port connection in a browser.
  • GetInfo API calls are now handled by the fdc3-agent-proxy with a message exchange, rather than using cached data from identity validation step of the WCP.
  • Message exchanges use a constant 10 second timeout, rather than inheriting the discovery timeout - this timeout may need further examination - it should possibly be specified by the Desktop Agent, or just set to a long-ish value (e.g. 30 seconds). However, its worth noting that no FDC3 API calls should require a long value as any long-running tasks are handled via events (e.g. context and intent listening).
  • Renamed BasicDesktopAgent to DesktopAgentProxy to better represent its role.
  • Comms iframes must now respond to a hello message from the app, rather than simply firing off a handshake when they load - this ensures that they can handle the UI arguments provided in the hello message (and perhaps one day the FDC3 version requested)
  • Private Channel events use the updated schemas from Correcting privateChannelAddEventListenerRequest to include null as a valid listenerType #1446 for consistency (avoids unnecessary translation)
  • Corrected pagehide handling to only disconnect if persisted == false
  • Added some log messaging for getAgent and set many logs to debug level
  • Added Logging utility to prefix log messages and colourise (where supported). This could later be used to disable debug logging with an argument.
  • Typing
    • Reduces the number of any types and type overrides in many places - there are others still to address
    • Type imports from BrowserTypes are made specific (rather than importing the whole thing and taking parts of it - as this may produce a smaller module and is easier to maintain) - there are others still to address.
  • Linting
    • Pre-PR reports:
      • fdc3-agent-proxy ✖ 41 problems (41 errors, 0 warnings)
      • fdc3-web-impl ✖ 63 problems (63 errors, 0 warnings)
      • fdc3-get-agent ✖ 25 problems (25 errors, 0 warnings)
      • fdc3-for-web-reference-ui ✖ 7 problems (7 errors, 0 warnings)
      • demo 42 problems (42 errors, 0 warnings)
    • Post-PR reports:
      • fdc3-agent-proxy ✖ 3 problems (3 errors, 0 warnings)
      • fdc3-web-impl ✖ 23 problems (23 errors, 0 warnings)
      • fdc3-get-agent ✔️ 0 problems (0 errors, 0 warnings)
      • fdc3-for-web-reference-ui ✖ 4 problems (4 errors, 0 warnings)
      • demo ✖ 12 problems (12 errors, 0 warnings)
    • A step in the right direction, but more to do! Some are automatically fixable (double non-null assertions with !!) but I have left these in place as each should be reviewed to see if the assertion can be avoided through better typing or defensive programming.
  • Tests
    • Refactored fdc3-get-agent test infrastructure to better represent multiple windows, documents and iframes - previously only single window.document would represent the parent, child and iframes at times and was relying on the getAgent implementation considering its own window to be a possible parent and to set up messaging with it 0t this is now prevented
    • Introduced new tests for fdc3-getAgent covering SessionStorage use in detail, as well as a number of cases.
    • Added a variable to enable/disable debug logging for test infrastructure and created many log messages.
  • fdc3-for-web-impl and demo
    • Added support for reconnecting instances and adjusted behavior to allow connections from instances that have been forgotten (now issued a new instanceId rather than conneciton rejected)
    • Corrected a race condition on new connections from iframes

Related Issue

Addresses a number of issues in addition to working to improve the implementation generally:

resolves #1429
resolves #1430
resolves #1433
resolves #1445
resolves #1468

Contributor License Agreement

  • I acknowledge that a contributor license agreement is required and that I have one in place or will seek to put one in place ASAP.

Review Checklist

  • Issue: If a change was made to the FDC3 Standard, was an issue linked above?
  • N/A (working on unreleased implementation) CHANGELOG: Is a CHANGELOG.md entry included?
  • API changes: Does this PR include changes to any of the FDC3 APIs (DesktopAgent, Channel, PrivateChannel, Listener, Bridging)?
    • Docs & Sources: If yes, were both documentation (/docs) and sources updated?

      JSDoc comments on interfaces and types should be matched to the main documentation in /docs
    • Conformance tests: If yes, are conformance test definitions (/toolbox/fdc3-conformance) still correct and complete?

      Conformance test definitions should cover all required aspects of an FDC3 Desktop Agent implementation, which are usually marked with a MUST keyword, and optional features (SHOULD or MAY) where the format of those features is defined
    • Schemas: If yes, were changes applied to the Bridging and FDC3 for Web protocol schemas?

      The Web Connection protocol and Desktop Agent Communication Protocol schemas must be able to support all necessary aspects of the Desktop Agent API, while Bridging must support those aspects necessary for Desktop Agents to communicate with each other
      • If yes, was code generation (npm run build) run and the results checked in?

        Generated code will be found at /src/api/BrowserTypes.ts and/or /src/bridging/BridgingTypes.ts
  • Context types: Were new Context type schemas created or modified in this PR?
    • Were the field type conventions adhered to?
    • Was the BaseContext schema applied via allOf (as it is in existing types)?
    • Was a title and description provided for all properties defined in the schema?
    • Was at least one example provided?
    • Was code generation (npm run build) run and the results checked in?

      Generated code will be found at /src/context/ContextTypes.ts
  • Intents: Were new Intents created in this PR?

kriswest and others added 30 commits November 19, 2024 21:18
Individual timeouts allow for steps that our outside the timeout (identity validation)
ImplementationMetadata is now passed into AbstractMessaging's constructor and getting close to eliminating AbstractWebMessaging. Correcting typing and generics on a number of functions (replacing any and unqualified generics)
- Eliminate AbstractWebMessaging
- Messaging is no longer a Connectable (as the connection is provided to it - was previously a no-op)
- Handling getInfo via a message exchange rather than passing down through connection flow
- Messaging implementations no longer handle implementationMetadata, instead holding the AppIdentifier directly
- Renamed HandshakeSupport HeartbeatSupport as its no longer involved in holding implementaiton metadata.
- Improving typing and error handling (defensive coding) in get-agent-proxy
Copy link

494 passed

@kriswest kriswest requested a review from robmoffat January 10, 2025 17:13
@robmoffat
Copy link
Member

awesome, I'll try and get to it first thing on Monday

Copy link
Member

@robmoffat robmoffat left a comment

Choose a reason for hiding this comment

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

Couple of minor issues. The only one stopping me hitting approve is the license for pico colours really. Perhaps you can just add the ANSI codes directly into your logger and remove the dependency entirely?

I'm going to do some testing now.

From picocolors (imported due to issues building in both ESM and CommonJS)
https://github.com/alexeyraspopov/picocolors

ISC License
Copy link
Member

Choose a reason for hiding this comment

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

I'm a bit worried about this license. A lot of FDC3's users have automated tools for license scanning and approvals. If FDC3 suddenly ends up being mixed-license (Apache + ISC) then it may get flagged.

According to opensource.org https://opensource.org/license/isc-license-txt. this license is currently not categorised as open source. Is there an alternative with an Apache license we can use?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I intend to remove it and replace with a custom implementation - this was a result of my frustration at not finding a lib for this that would build under both es6 and commonjs. I was going to do that in the debug logs PR...

Copy link
Contributor Author

@kriswest kriswest Jan 13, 2025

Choose a reason for hiding this comment

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

Actually, it is an OpenSource license, approved by the Open Source Initiative - the categorizations they display are within the set of Open Source licenses and are:
image
Its also the default license on NPM packages created with npm init (I'm told).

Regardless I intend to replace this with a custom implementation.

Copy link
Member

Choose a reason for hiding this comment

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

ok great. Yes, I misunderstood that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

picocolors removed / replaced

@@ -161,6 +161,10 @@ export function setupGenericSteps() {
expect(handleResolve(field, this)['message']).toBe(errorType);
});

Then('{string} is an error', function (this: PropsWorld, field: string) {
expect(handleResolve(field, this)).toBeInstanceOf(Error);
Copy link
Member

Choose a reason for hiding this comment

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

Why not use the existing 'error with message' and assert that the error matches "Invalid arguments passed to addContextListener!"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because the error message is non-standardized. There doesn't seem any point in enforcing the arbitrary message. Instead I'd rather pursue this in 2.3 and then do it properly:

Copy link
Contributor Author

Choose a reason for hiding this comment

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

WIll add a comment to the test and code regarding that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

*/
goodbye(instanceId: string): void;
setFDC3Server(server: FDC3Server): void;
Copy link
Member

Choose a reason for hiding this comment

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

rather than introduce the FDC3Server here, it might be better to have cleanup involve just the ServerContext and MessageHandler classes. setAppState() on the ServerContext can then chain cleanup on the MessageHandlers if it wants to.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The problem is that the ServerContext doesn't have a reference to the handlers, nor do the handlers to each other and both can handle/cause disconnections that they need to notify each other about. The Server is only thing with references to both. As I said earlier I don't understand the design decision in separating the ServerContext from the handlers as both have to hold state for applications and clean it up when appropriate.

If you don't want the ServerContext linked back to the server, then it will need to be linked to all the handlers so it can notify them to clean up their state (which is all that link is for) - that may be worse... This is a second attempt at solving the same state problem, if you want me to make a third then I need you to identify an architectural change that you'll accept AND that solves the state problem.

Copy link
Member

Choose a reason for hiding this comment

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

yes, I agree about the problem. This is as a result of cleanup needing to work across all the handlers. The ServerContext is separated out from the handler as it's expected that an implementation of the Desktop agent Server (in this case, demo), will want to implement that in it's own way. Whereas the behaviour of opening / resolving intents etc. will be reused.

If you don't want the ServerContext linked back to the server, then it will need to be linked to all the handlers so it can notify them to clean up their state (which is all that link is for) - that may be worse...

I think it would be less bad to have two classes referencing each other than three. But if you don't think this would be an improvement then just leave it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well... it wouldn't be 3 classes so much as 1 <-> 4 (each handler would need to reference the context and vice-versa and custom implementations would have to implement the link.

What I mean on the architecture is that the ServerContext could hold the references to the handlers instead of the server... And if we do that we might as well merge the concepts of the FDC3Server and ServerContext as theres not a lot of code in the server... Are we deriving a benefit from keeping them separate? I count something like 5 lines of code we get from the BasicFDC3Server...

@@ -128,7 +128,7 @@ const openChannelIframe = (e: MouseEvent) => {
const channel = new MessageChannel();

// STEP 2B: Receive confirmation over port from iframe
channel.port1.onmessage = ({ data }) => {
channel.port1.addEventListener('message', ({ data }) => {
Copy link
Member

Choose a reason for hiding this comment

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

Have you tested this code? I can't get it to run. If you can't either I suggest we take it out and the index.html file - people will be able to test the channel selector and intent resolver much better through the demo.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It looked well out of date to me and out of sync with the UI implementations, I fixed a few things but not tested - it definitely needs work to run.

@julianna-ciq

@robmoffat

This comment was marked as outdated.

@robmoffat
Copy link
Member

robmoffat commented Jan 13, 2025

Ok, one more UI thing, the default channel appears to be white now, instead of black. But that makes it hard to see against the workbench:

Screenshot 2025-01-13 at 10 50 12

blue channel looking fine

Screenshot 2025-01-13 at 10 49 59

no channel is invisible

Obviously, if workbench was running in dark mode, the reverse would be true! We might want to consider adding a white background to the channel icon?

@kriswest

This comment was marked as outdated.

@kriswest

This comment was marked as outdated.

@robmoffat
Copy link
Member

Conformance tests all passing for me. 🥳

Copy link

494 passed

1 similar comment
Copy link

494 passed

@kriswest
Copy link
Contributor Author

@robmoffat regarding the channel selector UI, there aren't white of black channels... The demo implementation is working fine for me. However, if I select the 'Default Web FDC3' UI in the demo I don't see the selector at all. Likely something needs fixing there - no idea why its even halfway working for you. Did you rebuild everything?

Oh you have to start the server for the reference UI separately... Still no white or black channels however. Also neither UI seems to allow deselecting the channel, which seems a flaw.

@robmoffat
Copy link
Member

robmoffat commented Jan 13, 2025

Oh you have to start the server for the reference UI separately...

No, it's supposed to start:

    "dev": "concurrently \"cd toolbox/fdc3-workbench && npm run dev\" \"cd toolbox/fdc3-for-web/reference-ui && npm run dev\" \"cd toolbox/fdc3-for-web/demo && npm run dev\"",

That part worked for me. The bit that didn't work so well that I drew attention to in my review is the index.html page in this ui-reference project, which doesn't really do anything, and the main.ts file that it uses.

Still no white or black channels however.

Also neither UI seems to allow deselecting the channel, which seems a flaw.

Agreed

@kriswest
Copy link
Contributor Author

That part worked for me. The bit that didn't work so well that I drew attention to in my review is the index.html page in this ui-reference project, which doesn't really do anything, and the main.ts file that it uses.

I believe the purpose was testing outside of the DA, not sure when it fell behind.

Still no white or black channels however.

Ah you mean when no channel is selected! I'll work on making it possible to deselect the channel first then have a think, we probably need styling that will work on either black or white... perhpas a white stroke on the cube + a drop shadow?

@robmoffat
Copy link
Member

robmoffat commented Jan 13, 2025

Ah you mean when no channel is selected! I'll work on making it possible to deselect the channel first then have a think, we probably need styling that will work on either black or white... perhpas a white stroke on the cube + a drop shadow?

Yes, sorry. It's clear in the demo's own implementation but not visible in the reference-ui version. I'll leave you to exercise your design skills 😁

@kriswest
Copy link
Contributor Author

It wasn't possible to deselect the channel in either implementation, I've fixed that as well as text contrast on each item:

Demo:
image

Default:
image

And have tried to bodge the logo styles on the default implementation to be visible on any backdrop:

image
image
image

Although it may be better to use the color contrast function I added for the text colours to flip the stroke color to black when white doesn't contrast with the colour... That'll need a little tuning of the SVG to look right.

Copy link

494 passed

@kriswest
Copy link
Contributor Author

@robmoffat should be ready for another look. I've not touched the index.html in reference-ui, but am otherwise done I think.

Copy link

494 passed

Copy link
Member

@robmoffat robmoffat left a comment

Choose a reason for hiding this comment

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

Thumbs up from me.. although there's one issue you can look at

name: 'Channel 1',
color: 'red',
glyph: '1',
glyphColor: 'white',
Copy link
Member

Choose a reason for hiding this comment

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

I'm getting a compile error here, which I can fix by changing to this:

export type ChannelState = {
  id: string;
  type: ChannelType;
  context: Context[];
  displayMetadata: DisplayMetadata & { glyphColor: string };
};

in BroadcastHandler

but is that just me?

Copy link
Member

Choose a reason for hiding this comment

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

... but actually I don't think you're even using glyphColor!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Gah, you're right. That was an abortive attempt to fix color contrast on channels - before I went and did it properly with a luminance based contrast calculation. Removed it. Getting no build errors this end.

Copy link

494 passed

@robmoffat
Copy link
Member

do you want to merge this?

@robmoffat robmoffat merged commit a5eeddd into fdc3-for-web-impl Jan 14, 2025
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment