ethersphere / bee-js

Javascript client library for connecting to Bee decentralised storage
https://bee-js.ethswarm.org/
BSD 3-Clause "New" or "Revised" License
60 stars 27 forks source link

Uploading binary data doesn't work correctly in React Native (iOS + Android) #757

Closed IgorShadurin closed 1 year ago

IgorShadurin commented 2 years ago

In bee-js, for some reason, binary data is converted to a sequence of numbers separated by commas instead of binary data. This only happens in React Native. In web and node everything works fine. Example:

function stringToBytes(data) {
  return new TextEncoder().encode(data);
}

const beeUrl = 'http://localhost:1633/';
const beeStamp = 'STAMP_HERE';
const dataString = 'Hello world!'
const dataBytes = stringToBytes(dataString)

const bee = new Bee(beeUrl);
const uploadResult = await bee.uploadData(beeStamp, dataBytes);

uploadResult.reference will be equal 1d15dc38ebe908e9dd6425d4b1de2181b0c3138a501d525f679d2e8ed846d892 in React Native. By downloading http://localhost:1633/bytes/1d15dc38ebe908e9dd6425d4b1de2181b0c3138a501d525f679d2e8ed846d892 I receiving text 72,101,108,108,111,32,119,111,114,108,100,33 instead of Hello world!

In web and node uploadResult.reference will be b1249e359cdf85a5684ba0b7fc83017589779ebdb18826222ba2f718eec069d9 and content Hello world!.

I'm attaching an example code in React Native to the issue. To run it, necessary to run

npm i

npm install --global expo-cli

expo start

And open Expo app on your mobile phone to launch the project.

bee-js-react-native.zip

This issue is a blocker for running fdp-storage on mobile devices.

https://github.com/fairDataSociety/fdp-storage/issues/110

crtahlin commented 2 years ago

@Cafe137 is there a plan to tackle this issue, what is the estimated time to solve it?

Cafe137 commented 2 years ago

I reproduced the issue. bee-js has a data.browser.js with a prepareData function that wraps Uint8Array in Blob. I suspect that is where the issue is, due to RN's implementation.

When Uint8Array is wrapped via the only constructor, its byteLength goes from 12 to 44.

I tried a few polyfills for Blob, but all errored out in Expo Go. This may still be worth to research a bit.


I also tried to create new File and pass that to uploadFile, but that has a different error due to ArrayView not being fully available in RN.


From bee-js perspective I would wait for the ky update that is in progress, and in the meantime suggest to upload manually with axios or fetch and see if Uint8Array is handled correctly there.

Cafe137 commented 2 years ago

@agazso suggested an approach leveraging the possibility that in bee-js the underlying fetch-like function can be user-specified via the Bee constructor:

const bee = new Bee('http://192.168.0.225:1633', { fetch: ReactNativeBlobUtil.fetch })

While I haven't had much luck yet with these fetch/Blob polyfills and alternatives, the idea is good and could be explored further.

Cafe137 commented 2 years ago

Another idea - pass Readable. Requires polyfill for stream and events packages but should be possible as well.

This does not work yet in Expo Go but can be used as starting point:

    function prepareData(data: string): Readable {
        const textEncoder = new TextEncoder()
        return new ReadableStream({
            start(controller) {
                controller.enqueue(textEncoder.encode(data))
                controller.close()
            }
        })
    }
molekilla commented 2 years ago

@Cafe137 can you try using this https://github.com/tradle/rn-nodeify

crtahlin commented 2 years ago

@Cafe137 is there a planned resolution for this issue?