1. 24 Jan, 2022 6 commits
  2. 21 Jan, 2022 1 commit
    • Eduardo Sanz García's avatar
      Make PortProvider#listen a private method · c5e02b31
      Eduardo Sanz García authored
      I can't see any negative consequence of starting to listen to
      postMessage discovery message immediately after `PortProvider` is
      instantiated. (In fact, this is what it was currently happening). These
      messages won't be lost, and the `PortRPC`s won't create the
      communication channels before the RPC methods are registered.
      
      On the other hand, it simplifies the use of `PortProvider` and
      eliminates the potential problem of `PortProvider#listen` been called
      more than once.
      c5e02b31
  3. 20 Jan, 2022 5 commits
  4. 19 Jan, 2022 3 commits
    • Robert Knight's avatar
      Make some internal method names more concise · 5838a84b
      Robert Knight authored
      Remove an uninformative suffix from two method names.
      5838a84b
    • Robert Knight's avatar
      Push document metadata from guest to sidebar · d7568d7c
      Robert Knight authored
      Change the way document metadata and URIs for guest frames gets from the
      guest to the sidebar, so that the guest _pushes_ the information instead
      of the sidebar requesting it. This achieves two things:
      
       1. It enables the sidebar to get the initial document URI faster, as
          the guest can fetch the information and send it to the sidebar over
          the message channel while the sidebar is still loading. This in turn
          allows the initial annotation search request to be made sooner and
          for annotations to appear quicker.
      
          This fixes https://github.com/hypothesis/client/issues/4094.
      
          In practice this doesn't improve the best case metadata fetch time
          significantly (only 5-10ms or so) but does seem to reduce the variance in
          fetch times.
      
       2. It will in future enable the guest to inform the sidebar of
          URI/metadata changes after the initial load. This can happen if a
          client-side navigation happens in an HTML document for example or if
          the currently loaded PDF is changed in PDF.js.
      d7568d7c
    • Eduardo Sanz García's avatar
      Use an RPC call instead of direct call to `Guest#selectAnnotations` · d4046e03
      Eduardo Sanz García authored
      We want the `BucketBar` to be able to communicate with `Guest`s that are
      in other iframes, like in the Ebook scenario. Currently, the `BucketBar`
      has an instance of the `Guest`, associated with `host` frame, and
      assumes to be the main `Guest`, for communication purposes.
      
      I have replaced the reliance of the direct invocation of
      `Guest#selectAnnotations` by a new `selectAnnotations` RPC event in the
      `guest-host` communication channel. This has the advantage of making no
      assumptions about which iframe contains the annotations.
      
      I have made some minor modification in the types and functionality of
      `range-util`.
      d4046e03
  5. 18 Jan, 2022 11 commits
    • Robert Knight's avatar
      Buffer RPC calls made before port is connected · 53f06183
      Robert Knight authored
      Fix a race condition where inter-frame RPC calls would silently fail if made
      before the MessagePort discovery process had completed. Fix the issue by queuing
      calls in PortRPC and then dispatching them once a port is connected. This is
      similar to how MessagePort buffers messages until they are consumed by calling
      `start`.
      53f06183
    • Robert Knight's avatar
      Simplify method name · 9ace9a71
      Robert Knight authored
      The "frame" part is redundant. Guests are always other frames in this
      context. Also this is consistent with `_connectGuest` in the `Sidebar`
      class.
      9ace9a71
    • Robert Knight's avatar
      6bfb7075
    • Robert Knight's avatar
      Use Maps instead of objects for records · 31688be1
      Robert Knight authored
      This avoids hazards with conflicts between map keys and built-in object
      property names.
      31688be1
    • Robert Knight's avatar
      Add test for calling `on` after `connect` · 3a354558
      Robert Knight authored
      3a354558
    • Robert Knight's avatar
      Combine Bridge and PortRPC classes · bb510f43
      Robert Knight authored
      Reduce the number of layers involved in inter-frame communication by combining
      the Bridge and PortRPC classes. PortRPC still only supports sending requests to
      a single port, but now has an API that is more like the Bridge class, where
      construction of the class, registering of RPC method handlers and connecting to
      a MessagePort are separate steps. This separation is convenient because it
      allows the RPC client to be set up before the MessagePort retrieval process,
      which is async in non-host frames, has completed.
      
      Existing uses of Bridge have been replaced either with a single PortRPC
      instance, for 1:1 connections between frames, or an array of PortRPC
      instances for 1:N connections between the sidebar/host and guest frames.
      Migrating to an array for 1:N connections paves the way to sending certain
      requests only to specific guests, whereas they are currently sent to _all_
      guests.
      
      Bridge's `call` method had logic for gathering results from multiple guests,
      timing out and disconnecting clients in the event of an error.  This logic was
      inappropriate in various ways and has not been re-implemented in PortRPC.
      
       - The timeout value was hardcoded at 1000ms for all calls. This may be too
         short depending on what the call does or what code is executing in the
         destination frame.
       - Disconnecting clients in the event of _any_ error, whether with the
         connection or an error on the client end in handling the call, doesn't make sense.
       - The `call` method returned a single Promise, so an error from any client
         would replace successful results from other clients. Also the client would
         have to wait until the results from all callers was available before sending
         a response.
       - The `call` method always passed a callback function to `PortRPC.call`,
         resulting in PortRPC always sending a response message back over the message
         channel, even when the code calling `bridge.call` did not use the response.
         Currently _no_ calls to `bridge.call` used the response, so this was just
         wasted traffic.
      
      The changes in detail are:
      
       1. Change the PortRPC API to be more like Bridge, where an instance is
          constructed, RPC handlers are added via `on` and the client is then
          connected to a port via `connect`.
      
       2. Replace use of Bridge with either a single PortRPC or array of PortRPCs in
          the `Guest`, `Sidebar` and `FrameSyncService` classes.
      
          This required changes in various tests to simulate a guest frame connecting
          before testing that a particular event resulted in an RPC call being made to
          a guest frame.
      
       3. Rename `bridge-events.d.ts` => `port-rpc-events.d.ts` to match (2)
      
       4. Remove the `Bridge` class, its tests and the PortRPC-Bridge integration
          tests, as they are now unused.
      
      Two existing issues were identified in this work but are not yet resolved:
      
       1. `FrameSyncService` does not tear down the PortRPC client for a guest when
           the guest frame disconnects.
       2. If a cross-frame RPC call is attempted before the async port discovery has
          completed, nothing happens. It will probably make sense to queue calls
          similar to how MessagePort queues messages.
      bb510f43
    • Eduardo's avatar
      Apply suggestions from code review · f709339f
      Eduardo authored
      Co-authored-by: 's avatarRobert Knight <robertknight@gmail.com>
      f709339f
    • Eduardo Sanz García's avatar
      Move scroll and resize listeners to their own service · 2ae809c9
      Eduardo Sanz García authored
      This is a step towards making the bucket bar works for a `guest` frame
      that is not in the `host` frame. When that's the case the observation of
      scrolling and resize can't happen in the `host` frame.
      
      A new service has been created, `BucketService`. The service is
      instantiated only in the `guest` frame that contains the main
      annotatable content. The service observes changes in the elements that
      could impact the relative position of the anchors relative to the
      viewport. If these changes are detected, as well as addition or deletion
      of anchors, it sends the `anchorsChanged` RPC event to the `host` frame
      so that the positions can be recalculated. As a result of the new
      service the `BucketBar` has been simplified.
      2ae809c9
    • dependabot[bot]'s avatar
      Bump eslint from 8.6.0 to 8.7.0 · 96f25627
      dependabot[bot] authored
      Bumps [eslint](https://github.com/eslint/eslint) from 8.6.0 to 8.7.0.
      - [Release notes](https://github.com/eslint/eslint/releases)
      - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
      - [Commits](https://github.com/eslint/eslint/compare/v8.6.0...v8.7.0)
      
      ---
      updated-dependencies:
      - dependency-name: eslint
        dependency-type: direct:development
        update-type: version-update:semver-minor
      ...
      Signed-off-by: 's avatardependabot[bot] <support@github.com>
      96f25627
    • Robert Knight's avatar
      e8318a82
    • Robert Knight's avatar
      Remove `onConnect` method from Bridge · c72257a9
      Robert Knight authored
      Simplify the Bridge class by removing the `onConnect` API and replacing
      current calls with alternative approaches.
      
      The `onConnect` method was a way to register a callback that would be invoked
      after a test RPC call over a newly-connected channel succeeded.
      
      The purpose of this method was not that clear however and its existence
      suggested that it is necessary to wait for the callback to be invoked before
      making RPC requests on the new channel. This is not the case, as the underlying
      transport buffers messages until the receiver is ready to consume them. Therefore
      RPC requests can be made as soon as `createChannel` returns.
      
      The current uses of `onConnect` were replaced as follows:
      
       1. The host frame used it to be notified when the sidebar application has
          loaded. This has been replaced with an explicit `ready` RPC call.
      
       2. The sidebar waited for this callback before querying metadata for a
          newly-connected guest. It now sends a metadata query to the guest
          immediately when it receives the guest port from the host frame. This saves
          an unnecessary round-trip between the host and guest. In future we can
          optimize metadata querying more by having the guest _push_ metadata to
          the sidebar rather than waiting for the sidebar to query it.
      c72257a9
  6. 17 Jan, 2022 10 commits
  7. 10 Jan, 2022 4 commits