From 4798ba0a42bf77d9f2c34b29c806811a0098aae1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20=22rysiek=22=20Wo=C5=BAniak?= Date: Tue, 2 Nov 2021 00:27:43 +0000 Subject: [PATCH] Updated docs/ARCHITECTURE.md to reflect the current code --- config.js.example | 2 +- docs/ARCHITECTURE.md | 75 ++++++++++++++++++++++++++++---------------- 2 files changed, 49 insertions(+), 28 deletions(-) diff --git a/config.js.example b/config.js.example index e1905c7..e3fb6ad 100644 --- a/config.js.example +++ b/config.js.example @@ -13,7 +13,7 @@ self.LibResilientConfig.plugins = [{ name: 'cache' },{ name: 'any-of', - plugins: [{ + uses: [{ name: 'alt-fetch', // configuring the alternate endpoints plugin to use IPNS gateways // diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index b2551df..57ff299 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -7,7 +7,7 @@ Eventually this will document the architecture of LibResilient. There are three kinds of plugins: - **Transport plugins** - Plugins that *retrieve* website content, e.g. by using regular HTTPS [`fetch()`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API), or by going through [IPFS](https://js.ipfs.io/). They *should* also offer a way to *publish* content by website admins (if relevant credentials or encryption keys are provided, depending on the method). + Plugins that *retrieve* website content, for example by using regular HTTPS [`fetch()`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API), or by going through [IPFS](https://js.ipfs.io/). They *should* also offer a way to *publish* content by website admins (if relevant credentials or encryption keys are provided, depending on the method). Methods these plugins implement: - `fetch` - fetch content from an external source (e.g., from IPFS) - `publish` - publish the content to the external source (e.g., to IPFS) @@ -23,25 +23,19 @@ Methods these plugins implement: Plugins that *compose* other plugins, for example by running them simultaneously to retrieve content from whichever succeeds first. Methods these plugins implement depend on which plugins they compose. Additionally, plugins being composed the `uses` key, providing the configuration for them the same way configuration is provided for plugins in the `plugins` key of `LibResilientConfig`. -Any plugin needs to add itself to the LibResilientPlugins global variable, using a data structure as follows: +Every plugin needs to be implemented as a constructor function that is added to the `LibResilientPluginConstructors` [Map()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) object for later instantiation. + +The constructor function should return a structure as follows (fields depending on the plugin type): ```javascript -self.LibResilientPlugins.push({ +{ name: 'plugin-name', description: 'Plugin description. Just a few words, ideally.', version: 'any relevant plugin version information', fetch: functionImplementingFetch, publish|stash|unstash: functionsImplementingRelevantFunctionality, - uses: { - composed-plugin-1: { - configKey1: "whatever-data-here" - }, - composed-plugin-2: { - configKey2: "whatever-data-here" - }, - {...} - } -}) + uses: [] +} ``` ### Transport plugins @@ -60,29 +54,56 @@ Stashing plugins *must* stash the request along with the `X-LibResilient-Method` ### Composing plugins -Composing plugins work by composing other plugins, for example to run them simultaneously and retrieve content from the first one that succeeds. A composing plugin needs to set the `uses` key in it's `LibResilientPlugins`. The key should contain mappings from plugin names to configuration: +Composing plugins work by composing other plugins, for example to: run them simultaneously and retrieve content from the first one that succeeds; or to run them in a particular order. A composing plugin needs to set the `uses` key in the object returned by it's constructor. The key should contain mappings from plugin names to configuration: ```javascript -uses: { - composed-plugin-1: { - configKey1: "whatever-data-here" - }, - composed-plugin-2: { - configKey2: "whatever-data-here" - }, - {...} -} +uses: [{ + name: "composed-plugin-1", + configKey1: "whatever-data-here" + },{ + name: "composed-plugin-2", + configKey2: "whatever-data-here" + }, + {...} +}] +``` + +If these mappings are to be configured via the global configuration file, the `uses` key should instead point to `config.uses`: + +```javascript +uses: config.uses ``` ## Fetching a resource via LibResilient -Whenever a resource is being fetched on a LibResilient-enabled site, the `service-worker.js` script dispatches plugins in the set order. Currently this order is hard-coded in `service-worker.js`, and is: +Whenever a resource is being fetched on a LibResilient-enabled site, the `service-worker.js` script dispatches plugins in the set order. This order is configured via the `plugins` key of the `LibResilientConfig` variable, usually set in `config.js` config file. + +A minimal default configuration is hard-coded in case no site-specific configuration is provided. This default configuration runs these plugins: 1. `fetch`, to use the upstream site directly if it is available, -1. `cache`, to display the site immediately from the cache in case regular `fetch` fails, -1. `gun-ipfs`, in the background if `cache` call succeeded, otherwise as the active fetch handler. +1. `cache`, to display the site immediately from the cache in case regular `fetch` fails (if content is already cached from previous visit). -If a background plugin `fetch()` succeeds, the result is added to the cache and will be immediately available on page reload. +A more robust configuration could look like this: + +```javascript +self.LibResilientConfig.plugins = [{ + name: 'fetch' + },{ + name: 'cache' + },{ + name: 'alt-fetch', + endpoints: [ + 'https://fallback-endpoint.example.com' + ]} + }] +``` + +For each resource, such a config would: + +1. Perform a regular `fetch()` to the main site domain first; if that succeeds, content is added to cache and displayed to the user. +1. If the `fetch()` failed, the cache would be checked. + 1. If the resource was cached, it would be displayed; at the same time, a background request for that resource would be made to `fallback-endpoint.example.com` instead of the (failing) main domain; if that succeeded, the new version of the resource would be cached. + 1. If the resource was not cached, a request for that resource would be made to `fallback-endpoint.example.com`; if that succeded, the resource would be displayed and cached. ## Stashed versions invalidation