From ef893d55e0f35417c79ef5a8ecf85498859bbf28 Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Fri, 31 May 2024 11:58:30 +0200 Subject: [PATCH 1/3] feat: Forward operation in `StackLink.request()` when offline On the Flagship app we want to serve `.query()` request using the `StackLink` when the device is connected, but we want to fallback to the `PouchLink` when we detect a connection loss To allow this, we allow the consuming app to provide an `isOnline()` method to the `StackLink` When provided, the `StackLink` will check for connectivity before doing its request. When offline, instead of processing the request, it will instead forward the request to the next `Link` The code is generic so the consuming app can configure a `PouchLink` or anything else as the next `Link` --- packages/cozy-client/src/StackLink.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/cozy-client/src/StackLink.js b/packages/cozy-client/src/StackLink.js index e414c2b88b..deaa22bafb 100644 --- a/packages/cozy-client/src/StackLink.js +++ b/packages/cozy-client/src/StackLink.js @@ -58,8 +58,9 @@ export default class StackLink extends CozyLink { * @param {object} [options] - Options * @param {object} [options.stackClient] - A StackClient * @param {object} [options.client] - A StackClient (deprecated) + * @param {import('cozy-pouch-link/dist/types').LinkPlatform} [options.platform] Platform specific adapters and methods */ - constructor({ client, stackClient } = {}) { + constructor({ client, stackClient, platform } = {}) { super() if (client) { logger.warn( @@ -67,6 +68,7 @@ export default class StackLink extends CozyLink { ) } this.stackClient = stackClient || client + this.isOnline = platform?.isOnline } registerClient(client) { @@ -77,7 +79,11 @@ export default class StackLink extends CozyLink { this.stackClient = null } - request(operation, result, forward) { + async request(operation, result, forward) { + if (this.isOnline && !(await this.isOnline())) { + return forward(operation) + } + if (operation.mutationType) { return this.executeMutation(operation, result, forward) } From f035d6c38032dea7f448c0fcdeba054081bfbbb0 Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Fri, 31 May 2024 16:00:01 +0200 Subject: [PATCH 2/3] feat: Forward operation in `StackLink.request()` on Network error On the Flagship app we want to serve `.query()` request using the `StackLink` when the device is connected, but we want to fallback to the `PouchLink` when we detect a connection loss In previous commit we tried pro-actively detect for connexion loss by calling an `isOnline()` method before processing the request But we want to also catch network errors when the `isOnline()` methods fails to detect connection loss, then we also fallback to the next `Link` --- packages/cozy-client/src/StackLink.js | 14 +++++++++++--- packages/cozy-client/src/utils.js | 12 ++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/packages/cozy-client/src/StackLink.js b/packages/cozy-client/src/StackLink.js index deaa22bafb..038511a66e 100644 --- a/packages/cozy-client/src/StackLink.js +++ b/packages/cozy-client/src/StackLink.js @@ -5,6 +5,7 @@ import CozyLink from './CozyLink' import { DOCTYPE_FILES } from './const' import { BulkEditError } from './errors' import logger from './logger' +import { isReactNativeOfflineError } from './utils' /** * @@ -84,10 +85,17 @@ export default class StackLink extends CozyLink { return forward(operation) } - if (operation.mutationType) { - return this.executeMutation(operation, result, forward) + try { + if (operation.mutationType) { + return await this.executeMutation(operation, result, forward) + } + return await this.executeQuery(operation) + } catch (err) { + if (isReactNativeOfflineError(err)) { + return forward(operation) + } + throw err } - return this.executeQuery(operation) } async persistData(data, forward) { diff --git a/packages/cozy-client/src/utils.js b/packages/cozy-client/src/utils.js index 973ac5cf37..8ac4fe55b3 100644 --- a/packages/cozy-client/src/utils.js +++ b/packages/cozy-client/src/utils.js @@ -68,3 +68,15 @@ export const hasQueriesBeenLoaded = queriesResults => { hasQueryBeenLoaded(queryResult) ) } + +/** + * Check is the error is about ReactNative not having access to internet + * + * @param {Error} err - The error to check + * @returns {boolean} True if the error is a network error, otherwise false + */ +export const isReactNativeOfflineError = err => { + // This error message is specific to ReactNative + // Network errors on a browser would produce another error.message + return err.message === 'Network request failed' +} From 63ad2482865ca3f57066d58516f1f7ff6cda4e1b Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Wed, 17 Jul 2024 15:33:55 +0200 Subject: [PATCH 3/3] docs: Update types and documentation --- docs/api/cozy-client/classes/StackLink.md | 27 ++++++++++++++++------- packages/cozy-client/types/StackLink.d.ts | 5 ++++- packages/cozy-client/types/utils.d.ts | 1 + 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/docs/api/cozy-client/classes/StackLink.md b/docs/api/cozy-client/classes/StackLink.md index 28869785a3..ad99609ed5 100644 --- a/docs/api/cozy-client/classes/StackLink.md +++ b/docs/api/cozy-client/classes/StackLink.md @@ -22,6 +22,7 @@ Transfers queries and mutations to a remote stack | :------ | :------ | :------ | | `[options]` | `Object` | Options | | `[options].client` | `any` | - | +| `[options].platform` | `any` | - | | `[options].stackClient` | `any` | - | *Overrides* @@ -30,17 +31,27 @@ Transfers queries and mutations to a remote stack *Defined in* -[packages/cozy-client/src/StackLink.js:62](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/StackLink.js#L62) +[packages/cozy-client/src/StackLink.js:64](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/StackLink.js#L64) ## Properties +### isOnline + +• **isOnline**: `any` + +*Defined in* + +[packages/cozy-client/src/StackLink.js:72](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/StackLink.js#L72) + +*** + ### stackClient • **stackClient**: `any` *Defined in* -[packages/cozy-client/src/StackLink.js:69](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/StackLink.js#L69) +[packages/cozy-client/src/StackLink.js:71](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/StackLink.js#L71) ## Methods @@ -62,7 +73,7 @@ Transfers queries and mutations to a remote stack *Defined in* -[packages/cozy-client/src/StackLink.js:118](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/StackLink.js#L118) +[packages/cozy-client/src/StackLink.js:132](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/StackLink.js#L132) *** @@ -82,7 +93,7 @@ Transfers queries and mutations to a remote stack *Defined in* -[packages/cozy-client/src/StackLink.js:95](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/StackLink.js#L95) +[packages/cozy-client/src/StackLink.js:109](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/StackLink.js#L109) *** @@ -107,7 +118,7 @@ Transfers queries and mutations to a remote stack *Defined in* -[packages/cozy-client/src/StackLink.js:87](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/StackLink.js#L87) +[packages/cozy-client/src/StackLink.js:101](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/StackLink.js#L101) *** @@ -127,7 +138,7 @@ Transfers queries and mutations to a remote stack *Defined in* -[packages/cozy-client/src/StackLink.js:72](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/StackLink.js#L72) +[packages/cozy-client/src/StackLink.js:75](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/StackLink.js#L75) *** @@ -153,7 +164,7 @@ Transfers queries and mutations to a remote stack *Defined in* -[packages/cozy-client/src/StackLink.js:80](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/StackLink.js#L80) +[packages/cozy-client/src/StackLink.js:83](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/StackLink.js#L83) *** @@ -167,4 +178,4 @@ Transfers queries and mutations to a remote stack *Defined in* -[packages/cozy-client/src/StackLink.js:76](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/StackLink.js#L76) +[packages/cozy-client/src/StackLink.js:79](https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/StackLink.js#L79) diff --git a/packages/cozy-client/types/StackLink.d.ts b/packages/cozy-client/types/StackLink.d.ts index 80a4d6d97e..839117535d 100644 --- a/packages/cozy-client/types/StackLink.d.ts +++ b/packages/cozy-client/types/StackLink.d.ts @@ -9,12 +9,15 @@ export default class StackLink extends CozyLink { * @param {object} [options] - Options * @param {object} [options.stackClient] - A StackClient * @param {object} [options.client] - A StackClient (deprecated) + * @param {import('cozy-pouch-link/dist/types').LinkPlatform} [options.platform] Platform specific adapters and methods */ - constructor({ client, stackClient }?: { + constructor({ client, stackClient, platform }?: { stackClient: object; client: object; + platform: import('cozy-pouch-link/dist/types').LinkPlatform; }); stackClient: any; + isOnline: any; registerClient(client: any): void; reset(): void; /** diff --git a/packages/cozy-client/types/utils.d.ts b/packages/cozy-client/types/utils.d.ts index 031006d18c..603dfc0ac6 100644 --- a/packages/cozy-client/types/utils.d.ts +++ b/packages/cozy-client/types/utils.d.ts @@ -2,6 +2,7 @@ export function isQueryLoading(col: any): boolean; export function hasQueryBeenLoaded(col: any): any; export function isQueriesLoading(queriesResults: any): boolean; export function hasQueriesBeenLoaded(queriesResults: any): boolean; +export function isReactNativeOfflineError(err: Error): boolean; export type CancelablePromise = Promise; /** * @typedef {Promise} CancelablePromise