feat: add world voxel snapshot forwarding

Collect chunk voxel data from the bot world and stream snapshot,
chunk, and unwatch messages through the forward protocol.
This commit is contained in:
2026-10-23 10:44:37 +08:00
parent 0acef64f48
commit 6c69afb38a
11 changed files with 1997 additions and 18 deletions
+18 -5
View File
@@ -484,7 +484,7 @@ test('execute_function traverses the relay with boolean results, permission chec
assert.equal(success_data(await ack(web.socket, 'relay_request', request('execute_function', payload))), false);
});
test('actual manager serves snapshots, logs and chat without forwarding bot events', async t => {
test('actual manager pushes lifecycle changes to snapshot readers without exposing other bot events', async t => {
const f = await real_fixture(t); const s = scope(); await f.open(s);
const manager = f.manager(s); const cmd = f.cmd(s);
assert.deepEqual(await manager.ensure(cmd), success({...s, node_ready: true, lease_expires_at: cmd.expires_at}));
@@ -497,21 +497,29 @@ test('actual manager serves snapshots, logs and chat without forwarding bot even
assert.deepEqual(Object.keys(absent).sort(), ['bot_id', 'bot_status', 'captured_at', 'context_exists', 'context_generation', 'seq', 'stream_id']);
assert.equal(absent.context_exists, false); assert.equal(absent.context_generation, null); assert.equal(absent.bot_status, 'offline');
code(await ack(web.socket, 'relay_request', request('bot.chat', {message: 'hello'})), 'NO_CONTEXT');
let leaks = 0; other.socket.on('relay_request', () => leaks++); other.socket.on('bot_event', () => leaks++);
let leaks = 0; other.socket.on('relay_request', () => leaks++);
const reader_events = []; other.socket.on('bot_event', event => reader_events.push(event));
assert.equal((await ack(web.socket, 'relay_request', request('bot.subscribe', {events: ['status_update', 'log', 'message', 'bot_error']}))).status, 'success');
const events = []; web.socket.on('bot_event', value => events.push(value));
const bot = online_context();
const initial_status = received(other.socket, 'bot_event', event => event.payload.status === 'online');
f.source(s.bot_id).set(bot);
await initial_status;
const snapshot = success_data(await ack(web.socket, 'relay_request', request()));
assert.equal(snapshot.context_exists, true); assert.equal(snapshot.bot_status, 'online');
assert.equal(snapshot.stream_id, absent.stream_id); assert.ok(snapshot.context_generation);
for (const state of ['offline', 'ready', 'connecting', 'online', 'disconnecting', 'reconnecting']) {
const pushed = received(web.socket, 'bot_event', event => event.payload.status === state);
const reader_pushed = received(other.socket, 'bot_event', event => event.payload.status === state);
bot.bot_status = state; bot.emit('status_update', state);
await Promise.all([pushed, reader_pushed]);
const current = success_data(await ack(web.socket, 'relay_request', request()));
assert.equal(current.context_exists, true);
assert.equal(current.bot_status, state); assert.equal(current.context_generation, snapshot.context_generation);
}
const back_online = received(web.socket, 'bot_event', event => event.payload.status === 'online');
bot.bot_status = 'online'; bot.emit('status_update', 'online');
await back_online;
const log_packet = received(web.socket, 'bot_log');
const metadata = {hoverEvent: {action: 'show_text', value: '悬停说明'},
clickEvent: {action: 'suggest_command', value: '/help'}, insertion: 'Alex'};
@@ -555,8 +563,9 @@ test('actual manager serves snapshots, logs and chat without forwarding bot even
bot.emit('error', new Error('SECRET stack'));
assert.equal(JSON.stringify({snapshot, logs}).includes('SECRET'), false);
await ack(other.socket, 'relay_request', request()); assert.equal(leaks, 0);
assert.deepEqual(events, []);
assert.equal(f.packets.some(packet => packet.event === 'bot_event'), false);
assert.ok(events.length >= 7 && reader_events.length >= 7);
assert.ok([...events, ...reader_events].every(event => event.name === 'status_update'));
assert.ok(f.packets.some(packet => packet.event === 'bot_event'));
manager.stop(); assert.equal(f.source(s.bot_id).count, 0); assert.equal(bot.listenerCount('log'), 0);
});
@@ -626,16 +635,20 @@ test('one Node manager isolates multiple Bot sessions and observes stop/start wi
await ack(web_a.socket, 'relay_request', request('bot.chat', {message: 'a'}));
await ack(web_b.socket, 'relay_request', request('bot.chat', {message: 'b'}));
assert.deepEqual(bot_a.sent, ['a']); assert.deepEqual(bot_b.sent, ['b']);
const stopped = received(web_a.socket, 'bot_event', event => event.payload.status === 'offline');
f.source(a.bot_id).set(undefined);
await stopped;
const absent = success_data(await ack(web_a.socket, 'relay_request', request()));
assert.equal(absent.bot_status, 'offline'); assert.equal(absent.context_generation, null);
const replacement = online_context();
const started = received(web_a.socket, 'bot_event', event => event.payload.status === 'online');
f.source(a.bot_id).set(replacement);
await started;
const after = success_data(await ack(web_a.socket, 'relay_request', request()));
assert.equal(after.stream_id, before.stream_id); assert.notEqual(after.context_generation, before.context_generation);
assert.equal(web_a.socket.connected, true); assert.equal(f.node_sockets.length, 2);
assert.equal(events_b.length, 0);
assert.equal(events_a.length, 0);
assert.deepEqual(events_a.map(event => event.payload.status), ['offline', 'online']);
assert.equal(bot_a.listenerCount('log'), 0);
});