Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Backup] Experimentation of react-native-mmkv to store local backup config #1097

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,15 @@ public void onCreate() {
WebView.setWebContentsDebuggingEnabled(true);
OkHttpClientProvider.setOkHttpClientFactory(new UserAgentClientFactory());

try {
Field field = CursorWindow.class.getDeclaredField("sCursorWindowSize");
field.setAccessible(true);
field.set(null, 50 * 1024 * 1024); // 50MB
} catch (Exception e) {
if (BuildConfig.DEBUG) {
e.printStackTrace();
}
}
// try {
// Field field = CursorWindow.class.getDeclaredField("sCursorWindowSize");
// field.setAccessible(true);
// field.set(null, 50 * 1024 * 1024); // 50MB
// } catch (Exception e) {
// if (BuildConfig.DEBUG) {
// e.printStackTrace();
// }
// }
}

/**
Expand Down
14 changes: 14 additions & 0 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ PODS:
- MLImage (= 1.0.0-beta2)
- MLKitCommon (~> 5.0)
- Protobuf (~> 3.12)
- MMKV (1.3.2):
- MMKVCore (~> 1.3.2)
- MMKVCore (1.3.2)
- nanopb (2.30908.0):
- nanopb/decode (= 2.30908.0)
- nanopb/encode (= 2.30908.0)
Expand Down Expand Up @@ -423,6 +426,9 @@ PODS:
- react-native-mlkit-ocr (0.3.0):
- GoogleMLKit/TextRecognition (= 2.6.0)
- React
- react-native-mmkv (2.5.1):
- MMKV (>= 1.2.13)
- React-Core
- react-native-netinfo (9.3.7):
- React-Core
- react-native-print (0.11.0):
Expand Down Expand Up @@ -616,6 +622,7 @@ DEPENDENCIES:
- "react-native-gzip (from `../node_modules/@fengweichong/react-native-gzip`)"
- react-native-idle-timer (from `../node_modules/react-native-idle-timer`)
- react-native-mlkit-ocr (from `../node_modules/react-native-mlkit-ocr`)
- react-native-mmkv (from `../node_modules/react-native-mmkv`)
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
- react-native-print (from `../node_modules/react-native-print`)
- "react-native-receive-sharing-intent (from `../node_modules/@mythologi/react-native-receive-sharing-intent`)"
Expand Down Expand Up @@ -689,6 +696,8 @@ SPEC REPOS:
- MLKitTextRecognition
- MLKitTextRecognitionCommon
- MLKitVision
- MMKV
- MMKVCore
- nanopb
- NVHTarGzip
- OpenSSL-Universal
Expand Down Expand Up @@ -756,6 +765,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-idle-timer"
react-native-mlkit-ocr:
:path: "../node_modules/react-native-mlkit-ocr"
react-native-mmkv:
:path: "../node_modules/react-native-mmkv"
react-native-netinfo:
:path: "../node_modules/@react-native-community/netinfo"
react-native-print:
Expand Down Expand Up @@ -872,6 +883,8 @@ SPEC CHECKSUMS:
MLKitTextRecognition: 8b0e0023a4babc66ca83d8b82864e57931164445
MLKitTextRecognitionCommon: 3e84602c928fe2b775fae81376f2136324cbd763
MLKitVision: e87dc3f2e456a6ab32361ebd985e078dd2746143
MMKV: f21593c0af4b3f2a0ceb8f820f28bb639ea22bb7
MMKVCore: 31b4cb83f8266467eef20a35b6d78e409a11060d
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
NVHTarGzip: 74cc227b902e5725900d37eb6d79b57e93005a73
OpenSSL-Universal: 1aa4f6a6ee7256b83db99ec1ccdaa80d10f9af9b
Expand Down Expand Up @@ -901,6 +914,7 @@ SPEC CHECKSUMS:
react-native-gzip: 5ffb84bf191c7cd135338eca748317bc466d41a1
react-native-idle-timer: f1920a59fe776340d004ff9de13c4a6eedcc8807
react-native-mlkit-ocr: 72cdbde86f8d29cba26cf9fa0a1865fe45c8f8d6
react-native-mmkv: 69b9c003f10afdd01addf7c6ee784ce42ee2eff3
react-native-netinfo: 2517ad504b3d303e90d7a431b0fcaef76d207983
react-native-print: f704aef52d931bfce6d1d84351dbb5232d7ecb89
react-native-receive-sharing-intent: 0c21b8e80f629a73341f2566ce9b99df8124bb10
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@
"react-native-localize": "2.2.6",
"react-native-mask-input": "1.2.1",
"react-native-mlkit-ocr": "^0.3.0",
"react-native-mmkv": "2.5.1",
"react-native-mmkv-flipper-plugin": "^1.0.0",
"react-native-permissions": "^3.9.3",
"react-native-play-install-referrer": "^1.1.8",
"react-native-print": "0.11.0",
Expand Down
45 changes: 44 additions & 1 deletion src/App.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import { NavigationContainer } from '@react-navigation/native'
import { decode, encode } from 'base-64'
import React, { useEffect, useState } from 'react'
import { StatusBar, StyleSheet, View } from 'react-native'
import {
StatusBar,
StyleSheet,
View,
ActivityIndicator,
InteractionManager
} from 'react-native'
import { MMKV } from 'react-native-mmkv'

Check failure on line 11 in src/App.js

View workflow job for this annotation

GitHub Actions / Quality Checks

'MMKV' is defined but never used
import { initializeMMKVFlipper } from 'react-native-mmkv-flipper-plugin'
import { Provider } from 'react-redux'
import { PersistGate } from 'redux-persist/integration/react'
import FlipperAsyncStorage from 'rn-flipper-async-storage-advanced'
Expand Down Expand Up @@ -53,8 +61,19 @@
LauncherContextProvider
} from './screens/home/hooks/useLauncherContext'

import LauncherView from '/screens/konnectors/LauncherView'

Check warning on line 64 in src/App.js

View workflow job for this annotation

GitHub Actions / Quality Checks

There should be no empty line within import group

import {
hasMigratedFromAsyncStorage,
migrateFromAsyncStorage,
storage
} from '/libs/localStore/storage'

// add this line inside your App.tsx
if (__DEV__) {
initializeMMKVFlipper({ default: storage })
}

// Polyfill needed for cozy-client connection
if (!global.btoa) {
global.btoa = encode
Expand Down Expand Up @@ -207,6 +226,30 @@
const Wrapper = () => {
const [hasCrypto, setHasCrypto] = useState(false)

const [hasMigrated, setHasMigrated] = useState(hasMigratedFromAsyncStorage)

useEffect(() => {
if (!hasMigratedFromAsyncStorage) {
InteractionManager.runAfterInteractions(async () => {
try {
await migrateFromAsyncStorage()
setHasMigrated(true)
} catch (e) {
// TODO: fall back to AsyncStorage? Wipe storage clean and use MMKV? Crash app?
}
})
}
}, [])

if (!hasMigrated) {
// show loading indicator while app is migrating storage...
return (
<View style={{ justifyContent: 'center', alignItems: 'center' }}>
<ActivityIndicator color="black" />
</View>
)
}

return (
<>
{__DEV__ && <FlipperAsyncStorage />}
Expand Down
10 changes: 9 additions & 1 deletion src/app/domain/backup/services/manageLocalBackupConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,19 @@
export const getLocalBackupConfig = async (
client: CozyClient
): Promise<LocalBackupConfig> => {
const startTime = performance.now()

const backupConfig = await getUserPersistedData<LocalBackupConfig>(
client,
UserPersistedStorageKeys.LocalBackupConfig
)

const endTime = performance.now()

console.log(

Check failure on line 64 in src/app/domain/backup/services/manageLocalBackupConfig.ts

View workflow job for this annotation

GitHub Actions / Quality Checks

Unexpected console statement
`🟢 getLocalBackupConfig took ${endTime - startTime} milliseconds.`
)

if (backupConfig === null) {
throw new Error(t('services.backup.errors.configNotInitialized'))
}
Expand Down Expand Up @@ -142,7 +150,7 @@
uri: media.uri,
creationDate: media.creationDate,
modificationDate: media.modificationDate,
remoteId: documentCreated.id as string,
remoteId: documentCreated.id!,

Check warning on line 153 in src/app/domain/backup/services/manageLocalBackupConfig.ts

View workflow job for this annotation

GitHub Actions / Quality Checks

Forbidden non-null assertion
md5: documentCreated.attributes.md5sum
}

Expand Down
86 changes: 83 additions & 3 deletions src/libs/localStore/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@

import { logger } from '/libs/functions/logger'
const log = logger('storage.ts')
import { MMKV } from 'react-native-mmkv'

export const storage = new MMKV()
const { setItem, getItem, removeItem } = AsyncStorage
export enum StorageKeys {
AutoLockEnabled = '@cozy_AmiralApp_autoLockEnabled',
Expand Down Expand Up @@ -37,17 +39,57 @@
value: StorageItems[keyof StorageItems]
): Promise<void> => {
try {
await setItem(name, JSON.stringify(value))
const startTime = performance.now()

const res = JSON.stringify(value)

const endTime = performance.now()

console.log(`🔴 storeData parse took ${endTime - startTime} milliseconds.`)

Check failure on line 48 in src/libs/localStore/storage.ts

View workflow job for this annotation

GitHub Actions / Quality Checks

Unexpected console statement

const startTime2 = performance.now()

if (name.includes('AmiralAppLocalBackupConfig')) {
storage.set(name, res)
} else {
await setItem(name, res)
}

const endTime2 = performance.now()

console.log(

Check failure on line 60 in src/libs/localStore/storage.ts

View workflow job for this annotation

GitHub Actions / Quality Checks

Unexpected console statement
`🔴 storeData write took ${endTime2 - startTime2} milliseconds.`
)
} catch (error) {
log.error(`Failed to store key "${name}" to persistent storage`, error)
}
}

export const getData = async <T>(name: StorageKeys): Promise<T | null> => {
try {
const value = await getItem(name)
const startTime = performance.now()

let value

if (name.includes('AmiralAppLocalBackupConfig')) {
value = storage.getString(name)
} else {
value = await getItem(name)
}

const endTime = performance.now()

console.log(`🟢 getData read took ${endTime - startTime} milliseconds.`)

Check failure on line 82 in src/libs/localStore/storage.ts

View workflow job for this annotation

GitHub Actions / Quality Checks

Unexpected console statement

const startTime2 = performance.now()

return value !== null ? (JSON.parse(value) as T) : null
const res = value !== null ? (JSON.parse(value) as T) : null

const endTime2 = performance.now()

console.log(`🟢 getData parse took ${endTime2 - startTime2} milliseconds.`)

Check failure on line 90 in src/libs/localStore/storage.ts

View workflow job for this annotation

GitHub Actions / Quality Checks

Unexpected console statement

return res
} catch (error) {
log.error(`Failed to get key "${name}" from persistent storage`, error)
return null
Expand All @@ -65,3 +107,41 @@
log.error(`Failed to clear data from persistent storage`, error)
}
}

// TODO: Remove `hasMigratedFromAsyncStorage` after a while (when everyone has migrated)
export const hasMigratedFromAsyncStorage = storage.getBoolean(
'hasMigratedFromAsyncStorage'
)

// TODO: Remove `hasMigratedFromAsyncStorage` after a while (when everyone has migrated)
export async function migrateFromAsyncStorage(): Promise<void> {
console.log('Migrating from AsyncStorage -> MMKV...')

Check failure on line 118 in src/libs/localStore/storage.ts

View workflow job for this annotation

GitHub Actions / Quality Checks

Unexpected console statement
const start = global.performance.now()

const keys = await AsyncStorage.getAllKeys()

for (const key of keys) {
try {
const value = await AsyncStorage.getItem(key)

if (value != null) {
if (['true', 'false'].includes(value)) {
storage.set(key, value === 'true')
} else {
storage.set(key, value)
}
}
} catch (error) {
console.error(

Check failure on line 135 in src/libs/localStore/storage.ts

View workflow job for this annotation

GitHub Actions / Quality Checks

Unexpected console statement
`Failed to migrate key "${key}" from AsyncStorage to MMKV!`,
error
)
throw error
}
}

storage.set('hasMigratedFromAsyncStorage', true)

const end = global.performance.now()
console.log(`Migrated from AsyncStorage -> MMKV in ${end - start}ms!`)

Check failure on line 146 in src/libs/localStore/storage.ts

View workflow job for this annotation

GitHub Actions / Quality Checks

Unexpected console statement
}
10 changes: 10 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -16712,6 +16712,16 @@ react-native-mlkit-ocr@^0.3.0:
resolved "https://registry.yarnpkg.com/react-native-mlkit-ocr/-/react-native-mlkit-ocr-0.3.0.tgz#b5b65dbe1fffdca0ca2012b1cab56cca6ea1bf58"
integrity sha512-8oNJwNMGsUup41nWlKA01iW6xiNkCcXM3ANDsOKKijvsrd3eWNs7kL0Yhpt3Cq64zSyjoeqkdTdOCDiI6Pv6KA==

react-native-mmkv-flipper-plugin@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/react-native-mmkv-flipper-plugin/-/react-native-mmkv-flipper-plugin-1.0.0.tgz#f87f747d8cea51d2b12a1e711287feff5f212788"
integrity sha512-e3owMIBzXez45Wz8Ac84Vf1FmfwMXFVUpf/gCDWDLq19w7iCipVezQjlZo8ISVza8aQf1G4ggaK/r+qqtGmRlg==

[email protected]:
version "2.5.1"
resolved "https://registry.yarnpkg.com/react-native-mmkv/-/react-native-mmkv-2.5.1.tgz#29fc462077fab16a5e1b79570fbf8acaac9d87b4"
integrity sha512-5eQu25z3H6zf6w0NkJoTuFEFrbOu6luZxZ6+rK1W+XwY/rjPSFZFQPVtMaz3im90RbILFXXM/KrFGZrpaJJRoQ==

react-native-modal-datetime-picker@^14.0.0:
version "14.0.1"
resolved "https://registry.yarnpkg.com/react-native-modal-datetime-picker/-/react-native-modal-datetime-picker-14.0.1.tgz#d9c6df4ff85bf1cfbe108c756dc26dcca4cc5f2f"
Expand Down
Loading