Skip to content

Commit 4e067f3

Browse files
committed
feat: Configure CozyClient to use CozyPouchLink
We want the Flagship app to work when offline To make this possible we configure cozy-client with CozyPouchLink which role will be to synchronize necessary doctypes into a local PouchDB and serve them from it instead of from the cozy-stack when the device is offline For now the list of synchronized doctypes is hardcoded but in the future we expect to implement a dynamic list based on cozy-apps' manifests Related PR: cozy/cozy-client#1507
1 parent c2387d4 commit 4e067f3

10 files changed

+167
-3
lines changed

src/libs/client.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export {
3030
} from '/libs/clientHelpers/initClient'
3131
export { call2FAInitClient } from '/libs/clientHelpers/twoFactorAuthentication'
3232
import { CozyPersistedStorageKeys, getData } from '/libs/localStore/storage'
33+
import { getLinks } from '/pouchdb/getLinks'
3334

3435
const log = Minilog('LoginScreen')
3536

@@ -44,14 +45,16 @@ export const getClient = async () => {
4445
return false
4546
}
4647
const { uri, oauthOptions, token } = oauthData
48+
const links = getLinks()
4749
const client = new CozyClient({
4850
uri,
4951
oauth: { token },
5052
oauthOptions,
5153
appMetadata: {
5254
slug: 'flagship',
5355
version: packageJSON.version
54-
}
56+
},
57+
links
5558
})
5659
listenTokenRefresh(client)
5760
client.getStackClient().setOAuthOptions(oauthOptions)

src/libs/client.spec.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ describe('client', () => {
6262
appMetadata: {
6363
slug: 'flagship',
6464
version: packageJSON.version
65-
}
65+
},
66+
links: expect.anything()
6667
})
6768
})
6869

src/libs/clientHelpers/createClient.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import googleServicesJson from '/../android/app/src/prod/google-services.json'
1313
import packageJSON from '../../../package.json'
1414

1515
import { startListening } from '/app/domain/authentication/services/AuthService'
16+
import { getLinks } from '/pouchdb/getLinks'
1617

1718
/**
1819
* Create a CozyClient for the given Cozy instance and register it
@@ -21,6 +22,8 @@ import { startListening } from '/app/domain/authentication/services/AuthService'
2122
* @returns {CozyClient} - The created and registered CozyClient
2223
*/
2324
export const createClient = async (instance: string): Promise<CozyClient> => {
25+
const links = getLinks()
26+
2427
const options = {
2528
scope: ['*'],
2629
oauth: {
@@ -37,7 +40,8 @@ export const createClient = async (instance: string): Promise<CozyClient> => {
3740
appMetadata: {
3841
slug: 'flagship',
3942
version: packageJSON.version
40-
}
43+
},
44+
links
4145
}
4246

4347
const client = new CozyClient(options)

src/pouchdb/getLinks.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { platformReactNative } from '/pouchdb/platformReactNative'
2+
3+
import { default as PouchLink } from 'cozy-pouch-link'
4+
5+
export const offlineDoctypes = [
6+
// cozy-home
7+
'io.cozy.accounts',
8+
'io.cozy.apps',
9+
'io.cozy.contacts',
10+
'io.cozy.files',
11+
'io.cozy.files.shortcuts',
12+
'io.cozy.home.settings',
13+
'io.cozy.jobs',
14+
'io.cozy.konnectors',
15+
'io.cozy.settings',
16+
'io.cozy.apps.suggestions',
17+
'io.cozy.triggers',
18+
'io.cozy.apps_registry',
19+
20+
// mespapiers
21+
'io.cozy.bills',
22+
'io.cozy.sharings',
23+
'io.cozy.mespapiers.settings',
24+
'io.cozy.permissions'
25+
]
26+
27+
export const getLinks = () => {
28+
const pouchLinkOptions = {
29+
doctypes: offlineDoctypes,
30+
initialSync: true,
31+
platform: platformReactNative
32+
}
33+
34+
const pouchLink = new PouchLink({
35+
...pouchLinkOptions
36+
})
37+
38+
return [pouchLink]
39+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import EventEmitter from 'events'
2+
3+
import { AppState, AppStateStatus, NativeEventSubscription } from 'react-native'
4+
5+
import Minilog from 'cozy-minilog'
6+
7+
const log = Minilog('🛋️ PlatormReactNative.appState')
8+
9+
let appState = AppState.currentState
10+
let appStateHandler: NativeEventSubscription | undefined = undefined
11+
12+
export const listenAppState = (eventEmitter: EventEmitter): void => {
13+
appStateHandler = AppState.addEventListener('change', nextAppState => {
14+
log.debug('🛋️ AppState event', nextAppState)
15+
if (isGoingToSleep(nextAppState)) {
16+
eventEmitter.emit('resume')
17+
}
18+
if (isGoingToWakeUp(nextAppState)) {
19+
eventEmitter.emit('pause')
20+
}
21+
22+
appState = nextAppState
23+
})
24+
}
25+
26+
export const stopListeningAppState = (): void => {
27+
appStateHandler?.remove()
28+
}
29+
30+
const isGoingToSleep = (nextAppState: AppStateStatus): boolean =>
31+
Boolean(appState.match(/active/) && nextAppState === 'background')
32+
33+
const isGoingToWakeUp = (nextAppState: AppStateStatus): boolean =>
34+
Boolean(appState.match(/background/) && nextAppState === 'active')
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { EventEmitter } from 'events'
2+
3+
import { listenAppState } from '/pouchdb/platformReactNative.appState'
4+
import { listenNetInfo } from '/pouchdb/platformReactNative.netInfo'
5+
6+
export const pouchDbEmitter = new EventEmitter()
7+
8+
const listenPouchEvents = (): void => {
9+
listenAppState(pouchDbEmitter)
10+
listenNetInfo(pouchDbEmitter)
11+
}
12+
13+
listenPouchEvents()
14+
15+
export const events = {
16+
addEventListener: (
17+
eventName: string,
18+
handler: (...args: unknown[]) => void
19+
): void => {
20+
pouchDbEmitter.addListener(eventName, handler)
21+
},
22+
removeEventListener: (
23+
eventName: string,
24+
handler: (...args: unknown[]) => void
25+
): void => {
26+
pouchDbEmitter.removeListener(eventName, handler)
27+
}
28+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { NetService } from '/libs/services/NetService'
2+
3+
export const isOnline = async (): Promise<boolean> => {
4+
return (await NetService.isConnected()) ?? true
5+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import EventEmitter from 'events'
2+
3+
import NetInfo, { NetInfoSubscription } from '@react-native-community/netinfo'
4+
5+
import Minilog from 'cozy-minilog'
6+
7+
const log = Minilog('🛋️ PlatormReactNative.netInfo')
8+
9+
let netInfoHandler: NetInfoSubscription | undefined = undefined
10+
11+
export const listenNetInfo = (eventEmitter: EventEmitter): void => {
12+
netInfoHandler = NetInfo.addEventListener(state => {
13+
log.debug('🛋️ NetInfo event', state.isConnected)
14+
if (state.isConnected) {
15+
eventEmitter.emit('online')
16+
} else {
17+
eventEmitter.emit('offline')
18+
}
19+
})
20+
}
21+
22+
export const stopListeningNetInfo = (): void => {
23+
netInfoHandler?.()
24+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import AsyncStorage from '@react-native-async-storage/async-storage'
2+
3+
export const storage = {
4+
getItem: async (key: string): Promise<string | null> => {
5+
return AsyncStorage.getItem(key)
6+
},
7+
setItem: async (key: string, value: string | undefined): Promise<void> => {
8+
if (value === undefined) return
9+
return AsyncStorage.setItem(key, value)
10+
},
11+
removeItem: async (key: string): Promise<void> => {
12+
return AsyncStorage.removeItem(key)
13+
}
14+
}

src/pouchdb/platformReactNative.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { events } from '/pouchdb/platformReactNative.events'
2+
import { isOnline } from '/pouchdb/platformReactNative.isOnline'
3+
import { storage } from '/pouchdb/platformReactNative.storage'
4+
import PouchDB from '/pouchdb/pouchdb'
5+
6+
export const platformReactNative = {
7+
storage,
8+
events,
9+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
10+
pouchAdapter: PouchDB,
11+
isOnline
12+
}

0 commit comments

Comments
 (0)