A React app plus service worker app. This package uses libp2p libraries.
The gateway-client is a web app that installs a PWA
on both mobile and desktop. The PWA intercepts all network traffic from
whichever SamizdApp app is currently open and forwards it to the
networking-service
.
To run the gateway client locally, execute npm start
(alias for
npm start gateway-client
) with the following environment variables set:
NX_LOCAL = true
NX_CADDY_ROOT = "http://joshua-samizdapp.local"
You can optionally set the variables NX_BUILD_NUMBER
, NX_BUILD_COMMIT
, and
NX_BUILD_BRANCH
to test out the UI features for reporting this info.
The worker app provides dev tools via the global variable SamizdAppDevTools
:
logging
- Manage the log level of the worker:getLoggers(name:? string)
- Return loggers matching the given name (a regex string), or all loggers if no name is given.resetLevel(name?: string)
- Reset the log level of the given logger (a regex string), or all loggers if no name is given.setLevel(levelOrName: string, level?: string)
- Set the log level of the given logger (a regex string) or all loggers (if no name is given) to the given level. Any log level changes are persisted across page refreshes and worker restarts.
status
- Return the current status of the worker.localforage
- Access to the worker's persistent storage.version
- The current version of the worker.p2pClient
- The client instance used by the worker to manage the worker libp2p node. The full client API is available, some common operations are:bootstrapList.addressList
- The list of available addresses to the box.node.dial(address)
- Use libp2p to dial the given address.node.dialProtocol(address, protocol)
- Use libp2p to dial the given address and protocol.
addressBook
- The address list that libp2p has for the node (should be but isn't necessarily the same as the bootstrap address list).
The worker app uses an unusual architecture. The purpose of the worker is to
provide a connection to the box where a direct https connection wouldn't
otherwise be possible. However, a direct https connection is required to
install or update any service worker. To account for this, the worker app is
split into two parts: a root worker (worker/service-worker.ts
) and a child
app worker (worker/app.ts
).
The root worker is a standard service worker that is updated on the client with the usual restrictions for service workers. (Only when there is a direct https connection to the box). The app worker is loaded by the root worker, and is able to update itself over its own libp2p connection.
The scope of the root worker is solely focused on loading the app worker and providing its service worker context to the app worker. All of the worker app functionality is provided by the app worker, allowing the worker app to be updated at all times.
The root worker is updated according to standard service worker update logic: on a navigation event, an attempt is made to download the latest worker via a direct https connection to the box. If the successfully downloaded worker is different, it is installed and will be activated on the next worker restart.
The app worker follows similar logic, with some extra functionality. On a navigation event, an attempt is made to download the latest worker via whatever connection to the box is available. If the successfully downloaded worker is different, an update is queued and will be installed and activated on the next worker restart. If the worker is not able to download the latest worker, it will assume that there is a bug in the current worker affecting connectivity and will queue a rollback. Rollbacks act like updates, they take effect on the next worker restart. Rollbacks can be cancelled by a subsequent successful update. There is logic that prevents multiple automatic rollbacks (to account for the possibility of a bad connection) and selects a previously working version to roll back to.
The worker will report its version and update status to the gateway-client
app and is able to be manually updated or rolled back via the app as well.
Because the app worker is widely available for updates, modifying the app worker can be approached the same as any other app.
However, some users will not be able to update the root worker unless they completely uninstall and reinstall the client. It should be assumed that any modifications made to the root worker will not reach some clients for up to 6 months.
This means a lot of thought should be put into making sure any root worker modifications are:
- Necessary - The root worker update lifecycle is complicated, so updates should be made as infrequently as possible.
- Minimal - In order to maximize code quality and minimize complications from updates, the root worker codebase should be kept as lightweight as possible. This means no runtime imports (of either libraries or dependencies).
- Backwards compatible - Since not all clients will receive the update, any changes must work with older versions of the root worker.
- Safe - If a bug is introduced into the root worker, the fix for that bug will not reach all clients; any bugs introduced will remain in the wild. Extra care should be taken to ensure that no risky changes are made to the root worker.
To aid in the fulfillment of these requirements, the root worker is versioned
using a semver version number that is hardcoded into the
root worker. Any PRs that affect the worker/service-worker.ts
file must
include an appropriate version bump. A major version change (indicating a
backwards-incompatible change) will require all users to reinstall their
clients.