From 069bc1b14abab8aef1c29de62f4f65747587edd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noe=CC=81=20Malzieu?= Date: Mon, 24 Jun 2024 17:56:39 +0200 Subject: [PATCH 1/2] Start working on killing db connection when backgrounded --- utils/xmtpRN/client.ts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/utils/xmtpRN/client.ts b/utils/xmtpRN/client.ts index 27f8703d4..d00bd910d 100644 --- a/utils/xmtpRN/client.ts +++ b/utils/xmtpRN/client.ts @@ -62,3 +62,27 @@ export const isOnXmtp = async (address: string) => export const xmtpClientByAccount: { [account: string]: ConverseXmtpClientType; } = {}; + +// On iOS, it's important to stop writing to SQLite database +// when the app is going from BACKGROUNDED to SUSPENDED +// (see https://github.com/xmtp/xmtp-ios/issues/336) + +// There are currently 2 SQLite databases: +// 1st one managed by Converse, created to store v2 XMTP data +// 2nd one managed by LibXMTP, created to store v3 XMTP data + +// Let's just stop writing to both of them as soon as the app is BACKGROUNDED + +export const dropXmtpClientsDbConnections = async () => { + await Promise.all( + Object.values(xmtpClientByAccount).map((c) => + c.dropLocalDatabaseConnection() + ) + ); +}; + +export const reconnectXmtpClientsDbConnections = async () => { + await Promise.all( + Object.values(xmtpClientByAccount).map((c) => c.reconnectLocalDatabase()) + ); +}; From 667428fe09f2710ad0f4791da96de5575f3b5d35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noe=CC=81=20Malzieu?= Date: Tue, 25 Jun 2024 12:09:54 +0200 Subject: [PATCH 2/2] Postpone writing to Converse SQLite when app is backgrounded --- components/XmtpEngine.tsx | 15 ++++++++++++++- data/db/index.ts | 10 ++++++++-- utils/xmtpRN/client.web.ts | 4 ++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/components/XmtpEngine.tsx b/components/XmtpEngine.tsx index 3f5f0480e..cf9fed309 100644 --- a/components/XmtpEngine.tsx +++ b/components/XmtpEngine.tsx @@ -11,6 +11,10 @@ import { useAppStore } from "../data/store/appStore"; import { useSelect } from "../data/store/storeHelpers"; import { getTopicsData } from "../utils/api"; import { loadSavedNotificationMessagesToContext } from "../utils/notifications"; +import { + dropXmtpClientsDbConnections, + reconnectXmtpClientsDbConnections, +} from "../utils/xmtpRN/client"; import { createPendingConversations } from "../utils/xmtpRN/conversations"; import { sendPendingMessages } from "../utils/xmtpRN/send"; import { syncXmtpClient } from "../utils/xmtpRN/sync"; @@ -72,10 +76,16 @@ export default function XmtpEngine() { appState.current.match(/inactive|background/) && hydrationDone ) { + await reconnectXmtpClientsDbConnections(); loadSavedNotificationMessagesToContext(); if (isInternetReachableRef.current) { syncAccounts(accounts); } + } else if ( + nextAppState.match(/inactive|background/) && + appState.current === "active" + ) { + await dropXmtpClientsDbConnections(); } appState.current = nextAppState; } @@ -105,7 +115,10 @@ export default function XmtpEngine() { const runningCron = useRef(false); const xmtpCron = useCallback(async () => { - if (!useAppStore.getState().splashScreenHidden) { + if ( + !useAppStore.getState().splashScreenHidden || + AppState.currentState.match(/inactive|background/) + ) { return; } runningCron.current = true; diff --git a/data/db/index.ts b/data/db/index.ts index 0d6246874..41737f757 100644 --- a/data/db/index.ts +++ b/data/db/index.ts @@ -1,4 +1,4 @@ -import { Platform } from "react-native"; +import { AppState, Platform } from "react-native"; import RNFS from "react-native-fs"; import { Repository } from "typeorm/browser"; @@ -38,7 +38,13 @@ export const getRepository = async ( // init. This means methods that try to interact with the database too // early will not fail but just take longer to execute! - while (!repositories[account]?.[entity]) { + // We also use the same mechanism to postpone writing to + // database if the app is in background + + while ( + !repositories[account]?.[entity] || + AppState.currentState.match(/inactive|background/) + ) { console.log(`Database for ${account} not yet initialized`); await new Promise((r) => setTimeout(r, 100)); } diff --git a/utils/xmtpRN/client.web.ts b/utils/xmtpRN/client.web.ts index ec45f8150..0e8d69102 100644 --- a/utils/xmtpRN/client.web.ts +++ b/utils/xmtpRN/client.web.ts @@ -37,3 +37,7 @@ export const isOnXmtp = async (address: string) => Client.canMessage(getCleanAddress(address), { env, }); + +export const dropXmtpClientsDbConnections = async () => {}; + +export const reconnectXmtpClientsDbConnections = async () => {};