Skip to content

Commit

Permalink
fix: offline data to fs for JSI OOM
Browse files Browse the repository at this point in the history
  • Loading branch information
CodyJasonBennett committed Sep 1, 2023
1 parent 8620d22 commit 3c91eac
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 105 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"eslint-plugin-react": "^7.29.4",
"eslint-plugin-react-hooks": "^4.4.0",
"expo-asset": "^8.4.6",
"expo-file-system": "^15.4.3",
"expo-gl": "^11.1.2",
"husky": "^7.0.4",
"jest": "^29.3.1",
Expand Down
4 changes: 4 additions & 0 deletions packages/fiber/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"expo": ">=43.0",
"expo-asset": ">=8.4",
"expo-gl": ">=11.0",
"expo-file-system": ">=11.0",
"react": ">=18.0",
"react-dom": ">=18.0",
"react-native": ">=0.64",
Expand All @@ -73,6 +74,9 @@
"expo-asset": {
"optional": true
},
"expo-file-system": {
"optional": true
},
"expo-gl": {
"optional": true
}
Expand Down
208 changes: 104 additions & 104 deletions packages/fiber/src/native/polyfills.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as THREE from 'three'
import { Platform, NativeModules, Image } from 'react-native'
import type { Asset } from 'expo-asset'
import { Asset } from 'expo-asset'
import * as fs from 'expo-file-system'

if (Platform.OS !== 'web') {
const BlobManager = require('react-native/Libraries/Blob/BlobManager.js')
Expand Down Expand Up @@ -73,20 +74,21 @@ if (Platform.OS !== 'web') {
return `${BLOB_URL_PREFIX}${blob.data.blobId}?offset=${blob.data.offset}&size=${blob.size}`
}

// Check if expo-asset is installed (available with expo modules)
let expAsset: typeof Asset | undefined
try {
expAsset = require('expo-asset')?.Asset
} catch (_) {}

/**
* Generates an asset based on input type.
*/
async function getAsset(input: string | number): Promise<Asset> {
switch (typeof input) {
case 'string':
if (input.startsWith('data:')) return { localUri: input } as Asset
if (input.startsWith('blob:')) {
if (input.startsWith('data:')) {
const [header, data] = input.split(',')
const [, type] = header.split('/')

const localUri = fs.cacheDirectory + uuidv4() + `.${type}`
await fs.writeAsStringAsync(localUri, data, { encoding: fs.EncodingType.Base64 })

return { localUri } as Asset
} else if (input.startsWith('blob:')) {
const blob = await new Promise<Blob>((res, rej) => {
const xhr = new XMLHttpRequest()
xhr.open('GET', input)
Expand All @@ -107,123 +109,121 @@ if (Platform.OS !== 'web') {

return getAsset(localUri)
}
return expAsset!.fromURI(input).downloadAsync()
return Asset.fromURI(input).downloadAsync()
case 'number':
return expAsset!.fromModule(input).downloadAsync()
return Asset.fromModule(input).downloadAsync()
default:
throw new Error('R3F: Invalid asset! Must be a URI or module.')
}
}

if (expAsset) {
// Don't pre-process urls, let expo-asset generate an absolute URL
const extractUrlBase = THREE.LoaderUtils.extractUrlBase.bind(THREE.LoaderUtils)
THREE.LoaderUtils.extractUrlBase = (url: string) => (typeof url === 'string' ? extractUrlBase(url) : './')

// There's no Image in native, so create a data texture instead
THREE.TextureLoader.prototype.load = function load(url, onLoad, onProgress, onError) {
const texture = new THREE.Texture()

getAsset(url)
.then(async (asset: Asset) => {
if (!asset.width || !asset.height) {
const { width, height } = await new Promise<{ width: number; height: number }>((res, rej) =>
Image.getSize(asset.localUri!, (width, height) => res({ width, height }), rej),
)
asset.width = width
asset.height = height
}

texture.image = {
data: { localUri: asset.localUri },
width: asset.width,
height: asset.height,
}
texture.flipY = true
// texture.unpackAlignment = 1
texture.needsUpdate = true

// @ts-ignore
texture.isDataTexture = true

onLoad?.(texture)
})
.catch(onError)

return texture
}
// Don't pre-process urls, let expo-asset generate an absolute URL
const extractUrlBase = THREE.LoaderUtils.extractUrlBase.bind(THREE.LoaderUtils)
THREE.LoaderUtils.extractUrlBase = (url: string) => (typeof url === 'string' ? extractUrlBase(url) : './')

// Fetches assets via XMLHttpRequest
THREE.FileLoader.prototype.load = function load(url, onLoad, onProgress, onError) {
if (this.path) url = this.path + url
// There's no Image in native, so create a data texture instead
THREE.TextureLoader.prototype.load = function load(url, onLoad, onProgress, onError) {
const texture = new THREE.Texture()

const request = new XMLHttpRequest()
getAsset(url)
.then(async (asset: Asset) => {
if (!asset.width || !asset.height) {
const { width, height } = await new Promise<{ width: number; height: number }>((res, rej) =>
Image.getSize(asset.localUri!, (width, height) => res({ width, height }), rej),
)
asset.width = width
asset.height = height
}

getAsset(url)
.then((asset) => {
request.open('GET', asset.uri, true)
texture.image = {
data: { localUri: asset.localUri },
width: asset.width,
height: asset.height,
}
texture.flipY = true
// texture.unpackAlignment = 1
texture.needsUpdate = true

request.addEventListener(
'load',
(event) => {
if (request.status === 200) {
onLoad?.(request.response)
// @ts-ignore
texture.isDataTexture = true

this.manager.itemEnd(url)
} else {
onError?.(event as unknown as ErrorEvent)
onLoad?.(texture)
})
.catch(onError)

this.manager.itemError(url)
this.manager.itemEnd(url)
}
},
false,
)
return texture
}

request.addEventListener(
'progress',
(event) => {
onProgress?.(event)
},
false,
)
// Fetches assets via XMLHttpRequest
THREE.FileLoader.prototype.load = function load(url, onLoad, onProgress, onError) {
if (this.path) url = this.path + url

request.addEventListener(
'error',
(event) => {
onError?.(event as unknown as ErrorEvent)
const request = new XMLHttpRequest()

this.manager.itemError(url)
this.manager.itemEnd(url)
},
false,
)
getAsset(url)
.then((asset) => {
request.open('GET', asset.uri, true)

request.addEventListener(
'abort',
(event) => {
request.addEventListener(
'load',
(event) => {
if (request.status === 200) {
onLoad?.(request.response)

this.manager.itemEnd(url)
} else {
onError?.(event as unknown as ErrorEvent)

this.manager.itemError(url)
this.manager.itemEnd(url)
},
false,
)

if (this.responseType) request.responseType = this.responseType
if (this.withCredentials) request.withCredentials = this.withCredentials

for (const header in this.requestHeader) {
request.setRequestHeader(header, this.requestHeader[header])
}
}
},
false,
)

request.addEventListener(
'progress',
(event) => {
onProgress?.(event)
},
false,
)

request.addEventListener(
'error',
(event) => {
onError?.(event as unknown as ErrorEvent)

this.manager.itemError(url)
this.manager.itemEnd(url)
},
false,
)

request.addEventListener(
'abort',
(event) => {
onError?.(event as unknown as ErrorEvent)

this.manager.itemError(url)
this.manager.itemEnd(url)
},
false,
)

if (this.responseType) request.responseType = this.responseType
if (this.withCredentials) request.withCredentials = this.withCredentials

for (const header in this.requestHeader) {
request.setRequestHeader(header, this.requestHeader[header])
}

request.send(null)
request.send(null)

this.manager.itemStart(url)
})
.catch(onError)
this.manager.itemStart(url)
})
.catch(onError)

return request
}
return request
}
}
9 changes: 8 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4800,6 +4800,13 @@ expo-asset@^8.4.6:
path-browserify "^1.0.0"
url-parse "^1.4.4"

expo-file-system@^15.4.3:
version "15.4.3"
resolved "https://registry.yarnpkg.com/expo-file-system/-/expo-file-system-15.4.3.tgz#0cb2464c6e663ad8e8a742d5c538ed8ff1013b11"
integrity sha512-HaaCBTUATs2+i7T4jxIvoU9rViAHMvOD2eBaJ1H7xPHlwZlMORjQs7bsNKonR/TQoduxZBJLVZGawvaAJNCH8g==
dependencies:
uuid "^3.4.0"

expo-gl-cpp@~11.1.0:
version "11.1.1"
resolved "https://registry.yarnpkg.com/expo-gl-cpp/-/expo-gl-cpp-11.1.1.tgz#883781535658a3598f2262425b1d3527b0e72760"
Expand Down Expand Up @@ -10078,7 +10085,7 @@ [email protected]:
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=

uuid@^3.3.2:
uuid@^3.3.2, uuid@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
Expand Down

0 comments on commit 3c91eac

Please sign in to comment.