| … | … | @@ -0,0 +1,91 @@ |
| 1 | #!/usr/bin/env node |
| 2 | /** |
| 3 | * pgh-hello — minimal test app for the pgh OTA demo. |
| 4 | * |
| 5 | * Prints its version and sleeps. If PghRuntime has access to a |
| 6 | * fetcher + store (typically supplied by the pgh install machinery |
| 7 | * via env vars), it polls for updates in the background and logs |
| 8 | * when a new tree is materialized. |
| 9 | */ |
| 10 | |
| 11 | import fs from 'fs' |
| 12 | import path from 'path' |
| 13 | import { fileURLToPath } from 'url' |
| 14 | |
| 15 | const HERE = path.dirname(fileURLToPath(import.meta.url)) |
| 16 | const pkg = JSON.parse(fs.readFileSync(path.join(HERE, 'package.json'), 'utf8')) |
| 17 | |
| 18 | console.log('pgh-hello v' + pkg.version) |
| 19 | console.log(' pid: ' + process.pid) |
| 20 | console.log(' path: ' + HERE) |
| 21 | |
| 22 | if (pkg.pgh && pkg.pgh.upgrade) { |
| 23 | console.log(' upgrade source: ' + pkg.pgh.upgrade) |
| 24 | } |
| 25 | |
| 26 | // Optional: wire up OTA via pgh-runtime if environment provides the |
| 27 | // necessary handles. Environment contract: |
| 28 | // PGH_CURRENT_TREE_HASH — tree hash pgh-hello was installed at |
| 29 | // PGH_STORE_ROOT — path to the pgh tree store |
| 30 | // PGH_TOPIC — 32-byte hex Hyperswarm topic to join |
| 31 | // |
| 32 | // This is an OPT-IN integration; if any env var is missing, pgh-hello |
| 33 | // just sleeps. |
| 34 | |
| 35 | async function startOTA () { |
| 36 | const topic = process.env.PGH_TOPIC |
| 37 | const currentTreeHash = process.env.PGH_CURRENT_TREE_HASH |
| 38 | const storeRoot = process.env.PGH_STORE_ROOT |
| 39 | |
| 40 | if (!topic || !currentTreeHash || !storeRoot) { |
| 41 | console.log(' OTA: disabled (missing PGH_TOPIC / PGH_CURRENT_TREE_HASH / PGH_STORE_ROOT)') |
| 42 | return null |
| 43 | } |
| 44 | |
| 45 | try { |
| 46 | const { PghRuntime } = await import('pgh-runtime') |
| 47 | const { TreeStore } = await import('pgh/store') |
| 48 | const { NetworkFetcher } = await import('pgh/network-fetcher') |
| 49 | |
| 50 | const store = new TreeStore({ root: storeRoot }) |
| 51 | store.init() |
| 52 | |
| 53 | const fetcher = new NetworkFetcher({ topic, timeout: 15000 }) |
| 54 | await fetcher.ready() |
| 55 | |
| 56 | const runtime = new PghRuntime({ |
| 57 | name: pkg.name, |
| 58 | currentTreeHash, |
| 59 | fetcher, |
| 60 | store, |
| 61 | interval: 15 * 1000, // 15s for demo |
| 62 | startImmediately: true |
| 63 | }) |
| 64 | |
| 65 | runtime.on('updating', (release) => { |
| 66 | console.log(' OTA updating → ' + release.version + ' (tree ' + release.treeHash.slice(0, 12) + ')') |
| 67 | }) |
| 68 | runtime.on('updated', (info) => { |
| 69 | console.log(' OTA updated — tree ready at ' + info.newTreeHash.slice(0, 12)) |
| 70 | console.log(' restart pgh-hello to apply (or pgh app rollback to revert)') |
| 71 | }) |
| 72 | runtime.on('error', (err) => { |
| 73 | console.error(' OTA error: ' + (err.message || err)) |
| 74 | }) |
| 75 | |
| 76 | await runtime.start() |
| 77 | console.log(' OTA: enabled, polling ' + topic.slice(0, 12) + '... every 15s') |
| 78 | return runtime |
| 79 | } catch (err) { |
| 80 | console.error(' OTA: failed to start — ' + err.message) |
| 81 | return null |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | startOTA().then(() => { |
| 86 | // Sleep forever |
| 87 | setInterval(() => {}, 1 << 30) |
| 88 | }) |
| 89 | |
| 90 | process.on('SIGINT', () => { console.log('\npgh-hello shutting down'); process.exit(0) }) |
| 91 | process.on('SIGTERM', () => { process.exit(0) }) |