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

fix: Import Onyx state on iOS #53370

Merged
Merged
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
38 changes: 10 additions & 28 deletions src/components/ImportOnyxState/index.native.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, {useState} from 'react';
import RNFS from 'react-native-fs';
import ReactNativeBlobUtil from 'react-native-blob-util';
import Onyx from 'react-native-onyx';
import type {FileObject} from '@components/AttachmentModal';
import {KEYS_TO_PRESERVE, setIsUsingImportedState} from '@libs/actions/App';
Expand All @@ -13,33 +13,15 @@ import {cleanAndTransformState} from './utils';

const CHUNK_SIZE = 100;

function readFileInChunks(fileUri: string, chunkSize = 1024 * 1024) {
function readOnyxFile(fileUri: string) {
const filePath = decodeURIComponent(fileUri.replace('file://', ''));

return RNFS.exists(filePath)
.then((exists) => {
if (!exists) {
throw new Error('File does not exist');
}
return RNFS.stat(filePath);
})
.then((fileStats) => {
const fileSize = fileStats.size;
let fileContent = '';
const promises = [];

// Chunk the file into smaller parts to avoid memory issues
for (let i = 0; i < fileSize; i += chunkSize) {
promises.push(RNFS.read(filePath, chunkSize, i, 'utf8').then((chunk) => chunk));
}

// After all chunks have been read, join them together
return Promise.all(promises).then((chunks) => {
fileContent = chunks.join('');

return fileContent;
});
});
return ReactNativeBlobUtil.fs.exists(filePath).then((exists) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TMisiukiewicz, have you considered using readStream instead of readFile?
According to the docs:

if the file is large, you should consider use readStream instead.

And since log files could realistically be large, we might hit a limit

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this was my initial idea. However, when using it, the app was crashing immediately without any JS error. I found out during debugging with Xcode that this is the error that makes it crash:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[0]'

I couldn't find any information how to fix it. I found out that this was reported in the library repository here: RonRadtke/react-native-blob-util#392 but thought the fastest way to unblock me from doing other fixes related to Import is using readFile. Works for me with ~15mb files. Maybe it's a good idea to go with this solution first and eventually adjust it once we hit any issues?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it's a good idea to go with this solution first and eventually adjust it once we hit any issues?

Can confirm, this works for large files on my end too. Agree, let's proceed with the current solution, we can follow-up in case any problems arise

if (!exists) {
throw new Error('File does not exist');
}
return ReactNativeBlobUtil.fs.readFile(filePath, 'utf8');
});
}

function chunkArray<T>(array: T[], size: number): T[][] {
Expand Down Expand Up @@ -72,8 +54,8 @@ export default function ImportOnyxState({setIsLoading, isLoading}: ImportOnyxSta
}

setIsLoading(true);
readFileInChunks(file.uri)
.then((fileContent) => {
readOnyxFile(file.uri)
.then((fileContent: string) => {
const transformedState = cleanAndTransformState<OnyxValues>(fileContent);
setShouldForceOffline(true);
Onyx.clear(KEYS_TO_PRESERVE).then(() => {
Expand Down
Loading