mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
at verify-code 82 lines 2.5 kB view raw
1import RNFS from 'react-native-fs' 2import {BskyAgent, ComAtprotoRepoUploadBlob} from '@atproto/api' 3 4/** 5 * @param encoding Allows overriding the blob's type 6 */ 7export async function uploadBlob( 8 agent: BskyAgent, 9 input: string | Blob, 10 encoding?: string, 11): Promise<ComAtprotoRepoUploadBlob.Response> { 12 if (typeof input === 'string' && input.startsWith('file:')) { 13 const blob = await asBlob(input) 14 return agent.uploadBlob(blob, {encoding}) 15 } 16 17 if (typeof input === 'string' && input.startsWith('/')) { 18 const blob = await asBlob(`file://${input}`) 19 return agent.uploadBlob(blob, {encoding}) 20 } 21 22 if (typeof input === 'string' && input.startsWith('data:')) { 23 const blob = await fetch(input).then(r => r.blob()) 24 return agent.uploadBlob(blob, {encoding}) 25 } 26 27 if (input instanceof Blob) { 28 return agent.uploadBlob(input, {encoding}) 29 } 30 31 throw new TypeError(`Invalid uploadBlob input: ${typeof input}`) 32} 33 34async function asBlob(uri: string): Promise<Blob> { 35 return withSafeFile(uri, async safeUri => { 36 // Note 37 // Android does not support `fetch()` on `file://` URIs. for this reason, we 38 // use XMLHttpRequest instead of simply calling: 39 40 // return fetch(safeUri.replace('file:///', 'file:/')).then(r => r.blob()) 41 42 return await new Promise((resolve, reject) => { 43 const xhr = new XMLHttpRequest() 44 xhr.onload = () => resolve(xhr.response) 45 xhr.onerror = () => reject(new Error('Failed to load blob')) 46 xhr.responseType = 'blob' 47 xhr.open('GET', safeUri, true) 48 xhr.send(null) 49 }) 50 }) 51} 52 53// HACK 54// React native has a bug that inflates the size of jpegs on upload 55// we get around that by renaming the file ext to .bin 56// see https://github.com/facebook/react-native/issues/27099 57// -prf 58async function withSafeFile<T>( 59 uri: string, 60 fn: (path: string) => Promise<T>, 61): Promise<T> { 62 if (uri.endsWith('.jpeg') || uri.endsWith('.jpg')) { 63 // Since we don't "own" the file, we should avoid renaming or modifying it. 64 // Instead, let's copy it to a temporary file and use that (then remove the 65 // temporary file). 66 const newPath = uri.replace(/\.jpe?g$/, '.bin') 67 try { 68 await RNFS.copyFile(uri, newPath) 69 } catch { 70 // Failed to copy the file, just use the original 71 return await fn(uri) 72 } 73 try { 74 return await fn(newPath) 75 } finally { 76 // Remove the temporary file 77 await RNFS.unlink(newPath) 78 } 79 } else { 80 return fn(uri) 81 } 82}