itinance / react-native-fs

Native filesystem access for react-native
MIT License
4.89k stars 954 forks source link

Please Help: uploadFile() sending empty or corrupted files to Google Drive API #1203

Open andresmejia3 opened 7 months ago

andresmejia3 commented 7 months ago

I've been stuck on this for hours and I don't know how to proceed. I'm using Google's V3 Drive API to create a resumable request for large file creation.

When I use uploadFile(), it's creating images on my GDrive that are of 0 bytes (if binaryStreamOnly is true) or 46 bytes (if binaryStreamOnly is false). When I try to open the photo, I get "file is empty" error or a "file is corrupted" error.

The file that I'm trying to upload is the default waterfall picture that comes with the simulator's photo library. What am I doing wrong?

Google's API requires that I do an initial POST request call to generate a resumable upload link, then upload the data in a PUT request (which is what I'm using uploadFile() for.

Any help would be greatly appreciated as I've been struggling to get this to work.

Also, thanks a lot for this amazing library!

const uploadFileToDrive = async (fileDetails: FileDetails, accessToken: string): string | undefined => {
    const resumableURL = 'https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable'

    const files: UploadFileItem[] = [{
        name: path.basename(fileDetails.filePath),
        filename: path.basename(fileDetails.filePath),
        filepath: fileDetails.filePath,
        filetype: fileDetails.mimeType
    }]

    const initialResponse = await fetch(resumableURL, {
        method: 'POST',
        headers: {
            'Authorization': `Bearer ${accessToken}`,
            'X-Upload-Content-Type': fileDetails.mimeType,
            // 'Content-Length': fileDetails.size.toString(),
            'Content-Type': 'application/json; charset=UTF-8'
        },
        body: JSON.stringify({
            name: path.basename(fileDetails.filePath),
            mimeType: fileDetails.mimeType,
            parents: ['root']
        })
    })

    if (initialResponse.ok) {

        console.log('\n\tFILE SIZE:', fileDetails.size.toString())

        const location = initialResponse.headers.get('location')!
        const uploadResult = RNFS.uploadFiles({
            files,
            toUrl: location,
            method: 'PUT',
            binaryStreamOnly: true,
            headers: {
                'Content-Length': fileDetails.size.toString()
            },
            begin(res) {
                console.log('UPLOAD HAS BEGUN! JobId:', res.jobId)
            },
            progress(res) {
                console.log('PROGRESS:', res)
                const percentage = Math.floor((res.totalBytesSent/res.totalBytesExpectedToSend) * 100)
                console.log('UPLOAD IS ' + percentage + '% DONE!')
            }
        })

        return uploadResult.promise.then(response => {

            // TODO: Handle appropriate errors https://developers.google.com/drive/api/guides/manage-uploads#http---single-request
            if (response.statusCode === 200) {
                console.log('Upload - Success')

                return JSON.parse(response.body).id as string

            } else if (response.statusCode >= 500 && response.statusCode < 600) {
                console.log('Upload - Interrupted:', response)
            } else {
                console.log('Upload - Something went wrong:', response)
            }

        }).catch((err) => {
            if(err.description === 'cancelled') {// cancelled by user
            }

            console.log('UploadResult:', err)
            return undefined
        })

    } else {
        console.log('Initial Upload request failed')
    }
}