feat: /api/channels endpoint, /api namespace, Scalar at root (v0.1.0) (#2)
feat: /api/channels endpoint, /api namespace, Scalar at root (v0.1.0) — closes #1
This commit was merged in pull request #2.
This commit is contained in:
@@ -18,11 +18,21 @@ export class MeshService implements OnModuleInit, OnModuleDestroy {
|
||||
private readonly logger = new Logger(MeshService.name);
|
||||
private readonly host = process.env.MESH_HOST ?? '192.168.1.4';
|
||||
private readonly port = parseInt(process.env.MESH_PORT ?? '4003', 10);
|
||||
// ponytail: fixed-interval retry, no backoff — fine for single-bridge use
|
||||
private readonly reconnectMs = parseInt(
|
||||
process.env.MESH_RECONNECT_MS ?? '5000',
|
||||
10,
|
||||
);
|
||||
|
||||
private socket: net.Socket | null = null;
|
||||
private buffer: Uint8Array = new Uint8Array(0);
|
||||
private connected = false;
|
||||
private myNodeNum: number | null = null;
|
||||
// channels streamed by the device during initial sync (before config_complete_id)
|
||||
private channelMap = new Map<
|
||||
number,
|
||||
import('@meshtastic/protobufs').Channel.Channel
|
||||
>();
|
||||
private reconnectTimer: NodeJS.Timeout | null = null;
|
||||
private shuttingDown = false;
|
||||
|
||||
@@ -45,6 +55,23 @@ export class MeshService implements OnModuleInit, OnModuleDestroy {
|
||||
};
|
||||
}
|
||||
|
||||
// psk/keys are deliberately not included — never expose them over HTTP
|
||||
channels(): {
|
||||
index: number;
|
||||
name: string;
|
||||
uplinkEnabled: boolean;
|
||||
downlinkEnabled: boolean;
|
||||
}[] {
|
||||
return [...this.channelMap.values()]
|
||||
.sort((a, b) => a.index - b.index)
|
||||
.map(({ index, settings }) => ({
|
||||
index,
|
||||
name: settings?.name ?? '',
|
||||
uplinkEnabled: settings?.uplinkEnabled ?? false,
|
||||
downlinkEnabled: settings?.downlinkEnabled ?? false,
|
||||
}));
|
||||
}
|
||||
|
||||
async sendText(to: number, text: string): Promise<number> {
|
||||
if (!this.connected || !this.socket)
|
||||
throw new ServiceUnavailableException('bridge not connected');
|
||||
@@ -59,6 +86,8 @@ export class MeshService implements OnModuleInit, OnModuleDestroy {
|
||||
this.socket = socket;
|
||||
socket.on('connect', () => {
|
||||
this.connected = true;
|
||||
// fresh sync on every (re)connect — drop stale channels from the old session
|
||||
this.channelMap = new Map();
|
||||
this.logger.log(`bridge connected ${this.host}:${this.port}`);
|
||||
});
|
||||
socket.on('data', (chunk) => {
|
||||
@@ -90,8 +119,7 @@ export class MeshService implements OnModuleInit, OnModuleDestroy {
|
||||
private scheduleReconnect(): void {
|
||||
if (this.shuttingDown) return;
|
||||
if (this.reconnectTimer) clearTimeout(this.reconnectTimer);
|
||||
// ponytail: fixed 5s retry, no backoff — fine for single-bridge use
|
||||
this.reconnectTimer = setTimeout(() => this.connect(), 5000);
|
||||
this.reconnectTimer = setTimeout(() => this.connect(), this.reconnectMs);
|
||||
}
|
||||
|
||||
private handleFromRadio(
|
||||
@@ -103,8 +131,14 @@ export class MeshService implements OnModuleInit, OnModuleDestroy {
|
||||
this.myNodeNum = v.value.myNodeNum;
|
||||
this.logger.log(`my node num: ${this.myNodeNum}`);
|
||||
break;
|
||||
case 'channel':
|
||||
// device streams one Channel per table slot during initial sync
|
||||
this.channelMap.set(v.value.index, v.value);
|
||||
break;
|
||||
case 'configCompleteId':
|
||||
this.logger.log('bridge ready (config complete)');
|
||||
this.logger.log(
|
||||
`bridge ready (config complete), ${this.channelMap.size} channels`,
|
||||
);
|
||||
break;
|
||||
case 'packet': {
|
||||
const pkt = v.value;
|
||||
|
||||
Reference in New Issue
Block a user