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

tus-js-client doesn't upload file larger than 100Mb for Android #508

Open
Xotonori opened this issue Nov 21, 2022 · 10 comments
Open

tus-js-client doesn't upload file larger than 100Mb for Android #508

Xotonori opened this issue Nov 21, 2022 · 10 comments
Labels
bug react-native Issues with tus-js-client in React Native

Comments

@Xotonori
Copy link

Xotonori commented Nov 21, 2022

tus-js-client doesn't upload file larger than 100Mb for Android. I've got next error - "Failed to upload because: Error: tus: cannot fetch file.uri as Blob, make sure the uri is correct and accessible. [object Object]"

I get video file data by "react-native-document-picker" library.

Than i get data like:

const assets = [{
"fileCopyUri": "file:///data/user/0/...projectName...development/files/9467e842-4db4-4bf7-849d-f3c400120665/fileName.mp4", 
"name": "basketball2k168MB.mp4", 
"size": 155686888, 
"type": "video/mp4", 
"uri":"content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2FfileName.mp4"
}];

Than i push assets to tus upload component and get presight params:

const uploadFile = (file: any, idx: number) => {
  const fileSize = file?.size || 0;

  dispatch(GameVimeoPresignUrl(idx, fileSize)).then(
    (data: VimeoPresignUrl) => {

      const {uploadLink, chunkSize, uri} = data;
      
      const uploader = new tus.Upload(file, {
        uploadUrl: uploadLink,
        endpoint: uploadLink,
        retryDelays: [0, 3000, 5000, 10000, 20000],
        chunkSize,
        metadata: {
          filename: `video.${file.name}`,
          filetype: file.type,
        },

        onError: onUploadError,
        onProgress: (bytesUploaded, bytesTotal) => {
          const percent = bytesUploaded / bytesTotal;
          onProgress(percent, idx);
        },
        onSuccess: () => {
          console.log('Successfully uploaded to:', uri);
          onUploadSuccess(uri);
        },
      });
      uploader.start();
    },
  );
};

And when uploading started, I get this error - "Failed to upload because: Error: tus: cannot fetch file.uri as Blob, make sure the uri is correct and accessible. [object Object]"

Files lower than 100Mb uploading very well, but larger don't( This problem only for an Android, IOS is ok.

@Xotonori Xotonori added the bug label Nov 21, 2022
@Valere3162
Copy link

Did you found any solution for this? I am also facing the exact same issue.

@Xotonori
Copy link
Author

Xotonori commented Feb 6, 2023

Unfortunatly no =(

@nh2
Copy link
Contributor

nh2 commented Mar 24, 2023

I cannot confirm this issue.
I can successfully upload a 500 MB video file with tus-js-client 3.0.1 to my own TUS server implementation, with both Firefox and Chrome on Android 11 (LineageOS on a Google Pixel 1).


Separate: In your code:

      const uploader = new tus.Upload(file, {
//...
        chunkSize,

It looks like here you're passing the large file's full size as chunkSize.

According to chunkSize docs this will pull the whole file into RAM:

A large chunk size (more than a GB) is problematic when a reader/readable stream is used as the input file. In these cases, tus-js-client will create an in-memory buffer with the size of chunkSize

On Android devices you usually don't have a lot of RAM, so this might be problematic.

@H4mxa
Copy link

H4mxa commented Oct 3, 2023

When attempting to upload a large file on iOS, the app's memory usage rapidly increases to 2GB and subsequently causes the app to crash.

@Acconut
Copy link
Member

Acconut commented Oct 17, 2023

@H4mxa Are you using React Native on iOS? Or are you using it in the browser? Because the original question was using React Native.

@Acconut Acconut added the react-native Issues with tus-js-client in React Native label Oct 18, 2023
@Tanush-J
Copy link

I am also facing the same issue with React-Native and I am using expo-image-picker to select a video.

 LOG  {"assetId": "33737", "base64": null, "duration": 180032, "exif": null, "fileName": "77541d9f-259a-4fde-8e3b-a5d98d940223.mp4", "filesize": 451514586, "height": 1080, "mimeType": "video/mp4", "rotation": 90, "type": "video", "uri": "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252FnativeChunking-94c8fbbb-5bd2-4a23-be0e-a8c6ef78365f/ImagePicker/4c885de7-a3c5-4759-8156-b8ade72214e7.mp4", "width": 1920}
 LOG  Failed because: Error: tus: cannot fetch `file.uri` as Blob, make sure the uri is correrrrect and accessible. [object Object]

I am getting this error when file size is around 400MB

@Acconut
Copy link
Member

Acconut commented Jun 1, 2024

My first thought is that this could be an memory issue. When a file URI in React Native is passed to tus-js-client, we attempt to load the entire file into a blob in memory:

export default function uriToBlob(uri) {

It is quite possible that this operation is not possible for larger file sizes as it would exhaust the available memory. We should investigate whether it is possible to only load parts of the file into memory and then tus-js-client can use its chunking logic to divide the file into multiple, smaller chunks.

@wfern
Copy link

wfern commented Jun 11, 2024

I think @Acconut is right. I saw in some place about a fetch() limitation on Android but I didn't find it to link.

Maybe a custom FileReader using expo-file-system and react-native-quick-base64 can solve the issue. Something like:

export default class TusFileReader {
  async openFile(input, chunkSize): {
    const fileInfo = await FileSystem.getInfoAsync(input.uri);
    if (fileInfo.exists) {
      return new FileSource(input, fileInfo.size);
    }
  }
}
class FileSource {
  private _file;
  private _size;

  get size(): number {
    return this._size;
  }

  constructor(file, size) {
    this._file = file;
    this._size = size;
  }

  async slice(start, end) {
    if (start >= this._size) {
      return { value: new Uint8Array(0), done: true };
    }

    end = Math.min(end, this._size);
    const length = end - start;

    const data = await FileSystem.readAsStringAsync(this._file.uri, {
      encoding: FileSystem.EncodingType.Base64,
      length: length,
      position: start,
    });
    
    const value = toByteArray(data);

    return { value, done: false };
  }
}

@Acconut
Copy link
Member

Acconut commented Jun 12, 2024

@wfern Thank you for the suggestion. Something like you suggested will likely help here. Do you have an opinion on what is the best way to access files that works well with React Native and Expo? You mentioned expo-file-system, but react-native-fs also has method for reading files at offsets: https://github.com/itinance/react-native-fs?tab=readme-ov-file#readfilepath-string-length--0-position--0-encodingoroptions-any-promisestring. I am no React Native developer and thus I am wondering that the preferred approach for file access currently is.

@wfern
Copy link

wfern commented Jun 12, 2024

@Acconut This is debatable because there is no preferred way. Most people should use expo nowadays but there are still many cases of people not using it and not liking using expo libraries because of the extra setup (even though it is minimal).

A good option would be to leave it as it is because:

  • It already works and I think it meets most cases.
  • The user does not need to add any libraries.

Document the possible limitation and add a snippet with that code on how to create FileReader for RN and mention that it is also possible to do it with "react-native-fs".

This would work for me because first I would test it the way it is today (no extra setup or libraries, just works™) and if it didn't work I would add FileReader based on this documentation snippet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug react-native Issues with tus-js-client in React Native
Projects
None yet
Development

No branches or pull requests

7 participants