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

File handling POC #102

Merged
merged 48 commits into from
Dec 14, 2021
Merged

Conversation

kidroca
Copy link
Contributor

@kidroca kidroca commented Aug 30, 2021

cc @thienlnam

Details

Add file handling capabilities to Onyx

Uses localforage for web/desktop.

Extracted a web/desktop storage provider that saves all our key/value pairs in IndexedDB through localforage
This allows saving files as part of Onyx items

FIle saving on native

When an attachment is picked the AttahcmentPicker will persist it to App/cache folder. It is then available until cache is cleared
This lets us save only the reference to the File in our key/val storage
This reference is enough to work with the file - use it in an <Image /> or in a upload request

Related Issues

$ Expensify/App#3867

Automated Tests

TBD

Linked PRs

kidroca added 26 commits August 26, 2021 01:29
Captured existing storage interface from Onyx to separate file

Storage provider mocking
When we have provider.js and provider.native.js we need
to have the mock implemented at the provider level
instead of the AsyncStorage level
this should allow us to store and retrieve Files as well as anything else
from storage for web and desktop
This is the same Provider we had up until now but the JSON
parsing and stringifying is capsulated here instead of Onyx
This is handled by Storage providers
Use FileSystem from unimodules as that's how to use expo's file system
on a bare RN project

Ad helper methods to check file items
Instead of trying to guess and handle files leave this to happen explicitly
by the library user
Add documentation and expose through Onyx
iOS would not create the folder automatically on copy
Copy link
Contributor Author

@kidroca kidroca left a comment

Choose a reason for hiding this comment

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

Add some notes on the code to help review

Copy link
Contributor Author

@kidroca kidroca left a comment

Choose a reason for hiding this comment

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

Pushing an update regarding the requested changes

It's seems this PR/POC is going to be accepted so I can add some tests tomorrow?

@@ -1,4 +1,4 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import Storage from '../../lib/storage';
Copy link
Contributor Author

Choose a reason for hiding this comment

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

When we're testing Onyx specific logic like cache eviction we can use any mock that implements the methods of the StroageProvider interface - AsyncStorage's mock is serving ok here

The cache eviction logic cleans cache and relays updates to the storage provider - what the provider does with that information is up to the provider (e.g. the logic that is performed on setItem failure is performed regardless of the provider)


should we write tests that show the providers are equivalent?

We should write tests that show the providers do what they are intended to do

For AsyncStorage all that we do is JSON.stringify and JSON.parse the values we should have tests that we're passing the correct key and stringified value to AsyncStorage and there's a few exception cases where we shouldn't stringify null for example
We don't alter how multiSet and multiMerge work internally so we don't need to test the result - we'll just be testing how AsyncStorage works (also there's nothing immediate that we can do if such a test fails, besides disabling the test)

For LocalForage we aren't stringify anything as it just works, but we implement multiGet, multiMerge, multiSet as there are no such methods
We should verify they work as expected and produce the expected result

@kidroca kidroca requested review from tgolen and marcaaron November 3, 2021 21:32
Copy link
Collaborator

@tgolen tgolen left a comment

Choose a reason for hiding this comment

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

It's looking very good to me at this stage!

@kidroca
Copy link
Contributor Author

kidroca commented Nov 4, 2021

I've prepared the App PR with videos and retested everything: Expensify/App#4908
Found one issue on mobile web ios
Otherwise everything seems ok

I'm not sure how to proceed, here are some questions

  • should I remove the Draft / Hold state and mark the PR as ready?
  • should I write tests now?
  • or try to fix the mobile web problem first?

@tgolen
Copy link
Collaborator

tgolen commented Nov 4, 2021 via email

@kidroca
Copy link
Contributor Author

kidroca commented Nov 12, 2021

@tgolen
I've found out what's causing the problem - the issues occurs because once we read the persisted requests we immediately delete them from storage, which also deletes file data
When we read a file from IndexedDB we receive only the metadata, we don't get the binary data - we receive a reference with the necessary hooks to read it if we want to. When we clear storage we lose the binary data. Here are more details: Expensify/App#4908 (comment)

I don't know why the issue occurs only on iOS Safari/Chrome, perhaps the other web platforms have some protection that doesn't delete data immediately

Any thought on how to proceed?

Since we've identified the problem I think we can continue and merge this the way it is. The offline file upload feature would work everywhere but mobile safari/chrome. Regular file upload still works there.
Or we can decide and apply an update to the offline request queue and then continue here

@tgolen
Copy link
Collaborator

tgolen commented Nov 12, 2021

I'm pretty hesitant to merge this with that big of a known bug. I'd like to see if we can fix it, or at least prevent the user from being affected (ie. disable the feature in those platforms until we fix the bug). I'm having trouble understanding the exact nature and reproduction steps of the bug though. Can you go into some more detail on why it happens and then maybe with me and @marcaaron we can try to figure something out.

the issues occurs because once we read the persisted requests we immediately delete them from storage, which also deletes file data

Does this happen because of changes in this PR, or because of localForage, or why? Can we control this at all to have it work better for us somehow? Where does this happen in the code?

@kidroca
Copy link
Contributor Author

kidroca commented Nov 12, 2021

It's not something that this PR introduced, it's how the network queue works

The details are here: Expensify/App#4908 (comment) steps, code causing the issue and some ideas on how to address it

@tgolen
Copy link
Collaborator

tgolen commented Nov 12, 2021

Ah, perfect! Just what I needed. I'll comment over there.

@kidroca kidroca marked this pull request as ready for review December 13, 2021 15:32
@kidroca kidroca requested a review from a team as a code owner December 13, 2021 15:32
@MelvinBot MelvinBot requested review from Gonals and removed request for a team December 13, 2021 15:33
@kidroca
Copy link
Contributor Author

kidroca commented Dec 14, 2021

As per this comment: Expensify/App#4908 (comment) I've removed the draft status of this PR

@thienlnam
Copy link
Contributor

@kidroca This shouldn't be on hold anymore right? Is this good to be reviewed/merged?

@kidroca
Copy link
Contributor Author

kidroca commented Dec 14, 2021

Yes,
Nothing had actually changed here since the last review - but I found a way to get this merged - attachment persistence will remain disabled (in App) until the issue (in App) with the attachment getting deleted prematurely is resolved (working on that here: Expensify/App#6556)

As a summary:
Tim approved the PR, Marc left a comment but it's not a blocker: #102 (review)
We can open a follow up PR to add a few more tests

@thienlnam thienlnam changed the title [HOLD] File handling POC File handling POC Dec 14, 2021
@thienlnam
Copy link
Contributor

Cool cool, I took a look over the PR and things look good to me.

I opened up this issue as a reminder to add tests and add some documentation regarding these changes #112

Since the PR is approved by both Tim and Marc, I will merge to push this forward

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants