// Start the worklet and read what it says. The ONLY file that knows
// react-native-bare-kit exists.
//
// Patterns from favela-surface-android/lib/host/worklet.js, where each was paid for:
// * The bundle is started from a FILE PATH (Worklet.start(path, null, args)), copied
// out of the APK assets natively. Passing it as a JS string ran the RN heap out of
// memory on a phone once the bundle grew (ours is ~0.8 MB, but the path costs nothing).
// * IPC is BYTES both ways; text conversion is ours (./utf8.js), and chunk
// boundaries are neither message nor character boundaries.
// * bare-kit suspends the worklet whenever the app goes to the background. favela
// had to override that; here it is exactly right -- the lamps see the sockets go
// and free this phone's slots at once.
import { Worklet } from 'react-native-bare-kit'
import RNFS from 'react-native-fs'
import { encodeUtf8, createUtf8Decoder } from './utf8'
const BUNDLE = 'worklet.bundle'
let started = null
// Copy the bundle out of the APK when this APK's build stamp differs from the copy's
// (a new APK). Not by size: two builds can produce bundles of the same size.
async function bundlePath (storage) {
const dest = storage + '/' + BUNDLE
const stampFile = dest + '.stamp'
let want = null
try { want = (await RNFS.readFileAssets(BUNDLE + '.stamp', 'utf8')).trim() } catch {}
let have = null
try { have = (await RNFS.readFile(stampFile, 'utf8')).trim() } catch {}
if (!want || want !== have || !(await RNFS.exists(dest))) {
try { await RNFS.unlink(dest) } catch {}
await RNFS.copyFileAssets(BUNDLE, dest)
if (want) await RNFS.writeFile(stampFile, want, 'utf8')
}
return dest
}
// Resolves { onMessage(fn), send(obj), worklet } once the worklet is started.
export function startWorklet () {
if (started) return started
started = (async () => {
const storage = RNFS.DocumentDirectoryPath
const path = await bundlePath(storage)
const worklet = new Worklet()
// Storage is the one positional argument, ever (see lib/worklet.js).
worklet.start(path, null, [storage])
const listeners = []
const decode = createUtf8Decoder()
let buf = ''
worklet.IPC.on('data', (data) => {
buf += decode(data)
let i
while ((i = buf.indexOf('\n')) !== -1) {
const line = buf.slice(0, i)
buf = buf.slice(i + 1)
let msg
try { msg = JSON.parse(line) } catch { continue }
for (const fn of listeners) fn(msg)
}
})
return {
worklet,
onMessage (fn) { listeners.push(fn) },
send (obj) { worklet.IPC.write(encodeUtf8(JSON.stringify(obj) + '\n')) }
}
})()
return started
}