mesh: in-memory ring of the last 100 messages forwarded to opencode

This commit is contained in:
2026-09-25 15:48:09 +00:00
parent bd18bdfd8a
commit e62f831ee5
2 changed files with 185 additions and 0 deletions
+30
View File
@@ -51,6 +51,18 @@ export interface MessageRecord {
ackError?: string;
}
/** One entry in the forwarded ring: an rx text that passed the notify gate and was handed off to opencode. */
export interface ForwardedRecord {
/** packet id (real rx) or generated record id (injected) */
id: number;
/** sender node num — omitted when there is no sender */
from?: number;
text: string;
channel: number;
/** epoch ms */
at: number;
}
/** One entry in the telemetry history: a TELEMETRY_APP packet from some node. */
export interface TelemetryRecord {
/** sender node num */
@@ -215,6 +227,8 @@ export class MeshService implements OnModuleInit, OnModuleDestroy {
private moduleConfigSections = new Map<string, Record<string, unknown>>();
// message history (newest kept, capped at HISTORY_LIMIT) + pending tx records awaiting their routing ACK/NACK
private history: MessageRecord[] = [];
// rx texts handed off to the opencode notifier (newest first, capped at HISTORY_LIMIT); in-memory only
private forwardedHistory: ForwardedRecord[] = [];
private pendingTx = new Map<number, MessageRecord>();
// telemetry history (newest kept, capped at HISTORY_LIMIT)
private telemetryHistory: TelemetryRecord[] = [];
@@ -376,6 +390,14 @@ export class MeshService implements OnModuleInit, OnModuleDestroy {
return [...this.history].reverse();
}
/**
* The last HISTORY_LIMIT rx texts that passed the notify gate and were handed off to opencode, newest first:
* channel matched MESH_NOTIFY_CHANNEL, not a self-echo, and a notifier is wired. In-memory only — reset on restart.
*/
forwarded(): ForwardedRecord[] {
return [...this.forwardedHistory];
}
/**
* Re-upsert the entire in-memory history buffer into SQLite (INSERT OR REPLACE per row) and enforce
* retention: only the newest DB_RETENTION rows survive. Called by the poller every MESH_POLL_MS;
@@ -502,6 +524,14 @@ export class MeshService implements OnModuleInit, OnModuleDestroy {
this.logger.debug(`notify skipped: rx from our own node ${from}`);
return;
}
// record the forward at hand-off — the ring holds exactly what a wired notifier receives (newest first).
// Pinned semantics: an unwired notifier records nothing (early return above); a notifier disabled internally
// (empty credentials) still counts — MeshService cannot see its enabled flag.
const entry: ForwardedRecord = { id: id!, text, channel, at: Date.now() };
if (from !== undefined) entry.from = from;
this.forwardedHistory.unshift(entry);
if (this.forwardedHistory.length > HISTORY_LIMIT)
this.forwardedHistory.pop(); // oldest evicted
void this.opencode.notify(id!, text, from); // both call sites always pass the packet id
}