[web] Introduce useWebLock
Summary:
ENG-6667 : Implement "primary" tab lock
We want to only have a singular tunnelbroker connection across all tabs on web. One way to achieve this is to use the WebLockAPI. The useWebLock hook exposes a nicer interface to it. It returns lock status and releaseLock function. When the status is equal to 'should-release' the caller is expected to run cleanup (e.g. disconnecting from the tunnelbroker) and call releaseLock.
Only the foreground tabs will try and acquire a lock. After a tab is backgrounded it should release the lock if it has one.
Some information about the web lock api:
- It allows to request a lock with a specific name
- The lock can be held only "in one place"/"one call to the request method" across all tabs of the same origin
- If we make sure to only call it once in the app, we can get the required locking behaviour between tabs
- (this is assuming the exclusive mode, which is the default)
- If the lock is already taken, the request call goes into a queue, and will wait until the lock is released
- Request in queue can be aborted with an AbortSignall
- Call to request returns a promise and expects an async callback as an argument. When it acquired the lock it calls the provided callback. The promise returned by the request call resolves when the the promise returned from the callback resolves.
- Locks are released automatically after the tab is closed
Additionally our version of flow doesn't type the LockManager (this was also the case for e.g. service worker and shared worker types) so I had to do it myself.
Test Plan:
Add this code:
const { lockStatus, releaseLock } = useWebLock('lock'); React.useEffect(() => { document.title = lockStatus; if(lockStatus === 'should-release') { // Add some delay to simulate closing the tunnelbroker socket setTimeout(releaseLock, 1000); } }, [lockStatus]);
Try switching between different tabs quickly, try displaying two tabs at the same time. Check that at all times the only tab holding the lock is one of the tabs in the foreground (except for the 1s delay before call to releaseLock). Check that if no tab is selected the lock is released.
Reviewers: kamil, inka, bartek
Reviewed By: kamil
Subscribers: ashoat, tomek
Differential Revision: https://phab.comm.dev/D11113