// Plan 018 harness: hub + intake + rehydrator + a stand-in /api/streams whose
// source always fails and whose server copy is gone. Port 8771.
// Run from server/: bun ../plans/harness/rehydrate-server.js (needs ffmpeg)
const { Hono } = await import(process.cwd() + '/node_modules/hono/dist/index.js');
import { mkdtempSync, readFileSync, unlinkSync } from 'node:fs';
import { spawnSync } from 'node:child_process';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { createHash } from 'node:crypto';
const root = mkdtempSync(join(tmpdir(), 'ytp-h18-'));
process.env.DB_PATH = join(root, 'h.db');
const dbmod = await import(process.cwd() + '/db.js');
const p2pDb = await import(process.cwd() + '/p2p-db.js');
const { registerP2pRoutes } = await import(process.cwd() + '/p2p-routes.js');
const { registerIntakeRoutes } = await import(process.cwd() + '/p2p-intake.js');
const { createP2pHub, createRehydrator } = await import(process.cwd() + '/p2p-hub.js');
const { admitFile } = await import(process.cwd() + '/p2p-admit.js');
const { validateMedia } = await import(process.cwd() + '/media-cache.js');
const FE = process.env.FE_DIR || new URL('../../frontend', import.meta.url).pathname;
await dbmod.initDb(); await p2pDb.initP2pSchema();
const fx = join(root, 'fx.mp4');
spawnSync('ffmpeg', ['-v', 'error', '-y', '-f', 'lavfi', '-i', 'testsrc=size=320x180:rate=25:duration=4', '-f', 'lavfi', '-i', 'sine=frequency=440:duration=4',
'-c:v', 'libx264', '-preset', 'ultrafast', '-pix_fmt', 'yuv420p', '-c:a', 'aac', '-shortest', '-movflags', '+faststart', fx]);
const bytes = readFileSync(fx);
const cid = createHash('sha256').update(bytes).digest('hex');
await p2pDb.upsertContent({ cid, videoId: 'goneAAAAAAA', size: bytes.length, origin: 'server', now: Date.now() }); // verified earlier, file since evicted
const cfg = { enabled: true, malwareScan: false, scanCmd: 'true', staleDays: 7, intakeDir: join(root, 'intake'), intakeMaxBytes: 50e6 };
const adopted = [];
const app = new Hono();
const p2p = registerP2pRoutes(app, { cfg, p2pDb, fileForCid: async () => null, sha256Range: async () => '' });
const hub = createP2pHub({ getDevice: p2pDb.getDevice });
registerIntakeRoutes(app, { cfg, p2pDb, gate: p2p.gate, requireDevice: p2p.requireDevice, validateMedia, admitFile,
serverHasCid: async () => adopted.length > 0,
adopt: async (videoId, path, info) => { adopted.push({ videoId, sha256: info.sha256 }); unlinkSync(path); return { adopted: true }; } });
const rehydrate = createRehydrator({ p2pDb, hub, hasServerCopy: async () => adopted.length > 0 });
app.get('/api/streams', async (c) => {
const v = c.req.query('v');
if (await rehydrate(v)) return c.json({ ok: false, restoring: true, error: 'restoring from a device' }, 503);
return c.json({ ok: false, error: 'source unavailable' }, 500);
});
app.get('/debug', (c) => c.json({ adopted, cid }));
app.get('/fixture.mp4', () => new Response(bytes));
app.get('/', (c) => c.html(''));
app.get('/:f', (c) => new Response(Bun.file(FE + '/' + c.req.param('f')), { headers: { 'Content-Type': 'text/javascript' } }));
Bun.serve({ port: 8771, fetch(req, server) {
if (new URL(req.url).pathname === '/ws/p2p') return hub.upgrade(req, server);
return app.fetch(req, server);
}, websocket: hub.websocket });
console.log('ready');