fix: local decoding of MQTT proxy messages in Virtual Node Server (#2358)#2363
fix: local decoding of MQTT proxy messages in Virtual Node Server (#2358)#2363
Conversation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Load mqtt.proto for ServiceEnvelope support and add decode method for extracting MeshPackets from MQTT proxy messages. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…Node Server Intercepts ToRadio.mqttClientProxyMessage, decodes the ServiceEnvelope, extracts the MeshPacket, marks it viaMqtt=true, and feeds it through processIncomingData for Server Channel Database decryption. The original message is still forwarded to the physical radio. Closes #2358 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
| return null; | ||
| } | ||
|
|
||
| if (!data || data.length === 0) { |
There was a problem hiding this comment.
Consider adding more specific error context here to aid debugging:
| if (!data || data.length === 0) { | |
| if (!data || data.length === 0) { | |
| logger.debug('decodeServiceEnvelope: Empty or null data provided'); | |
| return null; | |
| } |
This will help distinguish between different failure modes when troubleshooting MQTT proxy issues.
| gatewayId: decoded.gatewayId || undefined, | ||
| }; | ||
| } catch (error) { | ||
| logger.warn('⚠️ Failed to decode ServiceEnvelope:', error); |
There was a problem hiding this comment.
Consider logging the error details to aid troubleshooting:
| logger.warn('⚠️ Failed to decode ServiceEnvelope:', error); | |
| logger.warn('⚠️ Failed to decode ServiceEnvelope:', (error as Error).message); |
This provides more actionable debugging information for MQTT proxy issues while keeping logs clean.
| // MQTT Proxy message: decode ServiceEnvelope locally for Server Channel Database decryption | ||
| // Then forward to physical radio as normal | ||
| const proxyMsg = toRadio.mqttClientProxyMessage; | ||
| const proxyData = proxyMsg.data; |
There was a problem hiding this comment.
Consider adding type safety and input validation:
| const proxyData = proxyMsg.data; | |
| const proxyData = proxyMsg?.data; | |
| if (!proxyData || !(proxyData instanceof Uint8Array) || proxyData.length === 0) { | |
| logger.warn(`Virtual node: MQTT proxy message from ${clientId} has invalid data payload`); | |
| // Still forward to radio | |
| logger.info(`Virtual node: Forwarding MQTT proxy message from ${clientId} to physical node`); | |
| this.queueMessage(clientId, payload); | |
| return; | |
| } |
This improves robustness by handling edge cases where proxyMsg.data might not be a Uint8Array as expected.
| } else { | ||
| logger.warn(`Virtual node: MQTT proxy message from ${clientId} has no decodable packet, forwarding to radio only`); | ||
| } | ||
| } catch (error) { |
There was a problem hiding this comment.
Consider adding more specific error context:
| } catch (error) { | |
| } catch (error) { | |
| logger.error(`Virtual node: Failed to process MQTT proxy message locally from ${clientId}: ${(error as Error).message}`, error); | |
| // Continue - still forward to physical node | |
| } |
This provides better debugging information while maintaining the robust error handling approach.
|
|
||
| it('returns null for invalid data', () => { | ||
| if (!protobufInitialized) return; | ||
|
|
There was a problem hiding this comment.
Great test case! Consider making the assertion more explicit about what constitutes valid vs invalid results:
| const result = service.decodeServiceEnvelope(new Uint8Array([0xFF, 0xFF, 0xFF])); | |
| // Should return null for invalid data that cannot be decoded as ServiceEnvelope | |
| expect(result).toBeNull(); |
This makes the test intent clearer and ensures we're specifically testing the invalid data path.
| }); | ||
| }); | ||
|
|
||
| describe('Virtual Node Server - MQTT Proxy Message Handling', () => { |
There was a problem hiding this comment.
These tests are well-designed for documenting the expected behavior! Consider adding a test that verifies the actual flow integration:
| describe('Virtual Node Server - MQTT Proxy Message Handling', () => { | |
| describe('Virtual Node Server - MQTT Proxy Message Handling', () => { | |
| // ... existing tests ... | |
| it('should process MQTT proxy messages through the complete flow', async () => { | |
| // Test that demonstrates the full: ToRadio → ServiceEnvelope decode → FromRadio → processIncomingData flow | |
| // This would help catch integration issues between the components | |
| }); | |
| }); |
This would verify the end-to-end integration between the VNS and protobuf service.
Summary
Fixes #2358 — MQTT proxy messages (
mqttClientProxyMessage) sent to the Virtual Node Server are now locally decoded via the Server Channel Database, so traffic from channels not configured on the physical radio still appears in the UI.Problem
When an MQTT proxy sends
ToRadio.mqttClientProxyMessageto MeshMonitor via TCP, the VNS forwarded it directly to the physical radio without local processing. If the radio didn't have the channel configured, the message was silently dropped and never appeared in the UI.Solution
mqtt.protoin the protobuf loader forServiceEnvelopesupportdecodeServiceEnvelope()tomeshtasticProtobufService— extractsMeshPacketfrom theServiceEnvelopewrappermqttClientProxyMessageinhandleClientMessage— decodes the envelope, setsviaMqtt=true, wraps inFromRadio, and feeds throughprocessIncomingData()for server-side decryptionToRadiois always forwarded regardless of local processing resultFiles Changed
src/server/protobufLoader.tsmqtt.protofor ServiceEnvelope supportsrc/server/meshtasticProtobufService.tsdecodeServiceEnvelope()methodsrc/server/meshtasticProtobufService.test.tssrc/server/virtualNodeServer.tsmqttClientProxyMessagehandling blocksrc/server/virtualNodeServer.test.tsTest plan
🤖 Generated with Claude Code