| … | … | @@ -18,11 +18,17 @@ export default function App () { |
| 18 | 18 | const boot = useCallback(async () => { |
| 19 | 19 | setError(null) |
| 20 | 20 | const host = await startWorklet() // memoised: a retry reuses the running worklet |
| 21 | let answered = false | |
| 21 | 22 | host.onMessage((m) => { |
| 22 | 23 | if (m.t === 'log') setStage(m.msg) |
| 23 | else if (m.t === 'ready') setUrl(m.url) | |
| 24 | else if (m.t === 'fatal') setError(m.error) | |
| 24 | else if (m.t === 'ready') { answered = true; setUrl(m.url) } | |
| 25 | else if (m.t === 'fatal') { answered = true; setError(m.error) } | |
| 25 | 26 | }) |
| 27 | // A worklet has no error or exit event: if it never speaks, say so rather | |
| 28 | // than spin for ever (0.1.0 did exactly that). | |
| 29 | setTimeout(() => { | |
| 30 | if (!answered) setError('The light controller did not answer within 20 s.') | |
| 31 | }, 20000) | |
| 26 | 32 | }, []) |
| 27 | 33 | |
| 28 | 34 | useEffect(() => { boot().catch((e) => setError(e.message)) }, [boot]) |
| … | … | @@ -31,6 +37,7 @@ export default function App () { |
| 31 | 37 | return ( |
| 32 | 38 | <Center> |
| 33 | 39 | <Text style={s.err}>{error}</Text> |
| 40 | <Text style={s.dim}>{stage}</Text> | |
| 34 | 41 | <Pressable onPress={() => boot().catch((e) => setError(e.message))}><Text style={s.retry}>try again</Text></Pressable> |
| 35 | 42 | </Center> |
| 36 | 43 | ) |
| … | … | @@ -0,0 +1,13 @@ |
| 1 | // Where the worklet's storage comes from. | |
| 2 | // | |
| 3 | // On the phone bare-kit passes EXACTLY the args the shell gives, so Bare.argv is | |
| 4 | // [storage] (react-native-bare-kit shared/BareKitModule.cc: bare_worklet_start( | |
| 5 | // ..., args.size(), args)). On a desktop `bare lib/worklet.js <storage>` gives | |
| 6 | // [runtime, script, storage]. 0.1.0 required argv.length > 1 -- true only on a | |
| 7 | // desktop -- so on the phone the worklet loaded and then never started. | |
| 8 | export function storageFromArgv (argv) { | |
| 9 | if (!Array.isArray(argv)) return null | |
| 10 | if (argv.length === 1) return argv[0] || null // phone | |
| 11 | if (argv.length >= 3) return argv[argv.length - 1] // desktop: runtime, script, storage | |
| 12 | return null // desktop, no storage given | |
| 13 | } |
| … | … | @@ -18,6 +18,7 @@ import fs from 'bare-fs' |
| 18 | 18 | import path from 'bare-path' |
| 19 | 19 | import { createApp } from 'cthuloid-web/lib/app.js' |
| 20 | 20 | import assets from 'cthuloid-web/lib/assets.generated.js' |
| 21 | import { storageFromArgv } from './argv.js' | |
| 21 | 22 | |
| 22 | 23 | const IPC = typeof BareKit !== 'undefined' ? BareKit.IPC : null |
| 23 | 24 | |
| … | … | @@ -62,7 +63,10 @@ export async function start (storage) { |
| 62 | 63 | return { app, url } |
| 63 | 64 | } |
| 64 | 65 | |
| 65 | if (typeof Bare !== 'undefined' && Bare.argv.length > 1 && !globalThis.CTHULOID_NO_AUTOSTART) { | |
| 66 | const storage = Bare.argv[Bare.argv.length - 1] | |
| 66 | const storage = typeof Bare !== 'undefined' ? storageFromArgv(Bare.argv) : null | |
| 67 | if (storage && !globalThis.CTHULOID_NO_AUTOSTART) { | |
| 67 | 68 | start(storage).catch((err) => send({ t: 'fatal', error: (err && err.stack) || String(err) })) |
| 69 | } else if (!globalThis.CTHULOID_NO_AUTOSTART) { | |
| 70 | // Never silent again: say why nothing started (0.1.0 hung with no output at all). | |
| 71 | send({ t: 'fatal', error: 'no storage directory in argv: ' + JSON.stringify(typeof Bare !== 'undefined' ? Bare.argv : null) }) | |
| 68 | 72 | } |
| … | … | @@ -0,0 +1,22 @@ |
| 1 | // Where the worklet finds its storage. On the PHONE, bare-kit passes exactly the | |
| 2 | // args the shell gives -- Bare.argv is [storage] (react-native-bare-kit | |
| 3 | // shared/BareKitModule.cc: bare_worklet_start(..., args.size(), args)). On a | |
| 4 | // desktop, `bare lib/worklet.js <storage>` puts the runtime and script first. | |
| 5 | // 0.1.0 required argv.length > 1 and so never started on a phone. | |
| 6 | import test from 'brittle' | |
| 7 | import { storageFromArgv } from '../lib/argv.js' | |
| 8 | ||
| 9 | const SELF = '/x/android/lib/worklet.js' | |
| 10 | ||
| 11 | test('phone: the only argument is the storage dir', (t) => { | |
| 12 | t.is(storageFromArgv(['/data/user/0/org.circusautomatic.cthuloid/files'], SELF), '/data/user/0/org.circusautomatic.cthuloid/files') | |
| 13 | }) | |
| 14 | ||
| 15 | test('desktop: runtime, script, storage', (t) => { | |
| 16 | t.is(storageFromArgv(['bare', SELF, '/tmp/s'], SELF), '/tmp/s') | |
| 17 | }) | |
| 18 | ||
| 19 | test('desktop with no storage given: do not start', (t) => { | |
| 20 | t.is(storageFromArgv(['bare', SELF], SELF), null) | |
| 21 | t.is(storageFromArgv([], SELF), null) | |
| 22 | }) |