Skip to content

fix: prevent virtual node from broadcasting channel config to clients (#1567)#1659

Merged
Yeraze merged 1 commit into
mainfrom
fix/1567-virtual-node-channel-name-broadcast
Jan 27, 2026
Merged

fix: prevent virtual node from broadcasting channel config to clients (#1567)#1659
Yeraze merged 1 commit into
mainfrom
fix/1567-virtual-node-channel-name-broadcast

Conversation

@Yeraze

@Yeraze Yeraze commented Jan 27, 2026

Copy link
Copy Markdown
Owner

Summary

  • Filter out FromRadio.channel type messages from real-time virtual node broadcast — these should only reach clients through the controlled sendInitialConfig() flow. Broadcasting them during physical node reconnection caused Android/iOS clients to receive unsolicited channel updates with empty name fields, displayed as "Channel Name" placeholder text.
  • Add refreshAllClients() method to VirtualNodeServer that re-sends full initial config to all connected clients when the physical node reconnects and config capture completes.
  • Update the config capture complete callback to trigger client refresh on reconnection rather than only initializing the server once.

Closes #1567

Test plan

  • All 2248 unit tests pass
  • Docker build succeeds
  • Connect Android client via virtual node, verify channel names display correctly
  • Disconnect physical node from web UI, verify Android client recovers channel names after reconnection
  • Verify real-time messages (text, telemetry, position) still flow to Android client
  • Verify prolonged use does not cause channel names to revert to "Channel Name"

🤖 Generated with Claude Code

…#1567)

When the physical node reconnects, its full config dump (including
FromRadio.channel messages) was broadcast to all connected virtual node
clients. Channel 0 typically has an empty name in the protobuf, which
the Android app displays as the placeholder "Channel Name". This fix:

1. Filters out 'channel' type FromRadio messages from real-time broadcast
   so clients only receive channel config through sendInitialConfig()
2. Adds refreshAllClients() to VirtualNodeServer to re-send config to
   all connected clients when the physical node reconnects
3. Updates the config capture complete callback to trigger a client
   refresh on reconnection rather than only initializing once

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jan 27, 2026

Copy link
Copy Markdown

Claude finished @Yeraze's task —— View job


PR Review Analysis

I've thoroughly reviewed this PR that addresses the virtual node channel name broadcasting issue (#1567). Here's my comprehensive feedback:

Todo List:

  • Read and analyze changed files
  • Review the virtual node filtering implementation
  • Check the refreshAllClients method
  • Assess error handling and edge cases
  • Review performance implications
  • Check security considerations
  • Evaluate test coverage needs
  • Provide comprehensive feedback

✅ Code Quality and Implementation

Strong Points:

  1. Clear Problem Resolution: The fix directly addresses the root cause - preventing FromRadio.channel messages from being broadcast to virtual node clients during physical node reconnection
  2. Well-documented Logic: Excellent inline comments explaining the filtering logic at src/server/meshtasticManager.ts:1510-1518
  3. Robust Parsing Strategy: The code parses messages first to determine type, then filters appropriately, with fallback to broadcast unparsed messages
  4. Clean Architecture: The refreshAllClients() method provides a controlled way to update clients through the proper sendInitialConfig() flow

🔍 Implementation Review

Message Filtering Logic (src/server/meshtasticManager.ts:1520-1522):

const shouldBroadcast = !context?.skipVirtualNodeBroadcast &&
  (!parsed || parsed.type !== 'channel');
  • ✅ Correctly filters out 'channel' type messages
  • ✅ Gracefully handles parse failures by allowing broadcast
  • ✅ Respects existing skipVirtualNodeBroadcast context flag

Refresh Mechanism (src/server/server.ts:252-265):

  • ✅ Function renamed from initializeVirtualNodeServer to initializeOrRefreshVirtualNodeServer clearly indicates dual purpose
  • ✅ Proper handling of both initial setup and reconnection scenarios
  • ✅ Error handling with try-catch for client refresh failures

⚠️ Potential Issues

  1. Error Handling in Parse Failure: At src/server/meshtasticManager.ts:1521, if parsing fails (!parsed), the message is still broadcast. This is reasonable for compatibility but consider logging parse failures for debugging:

    if (!parsed) {
      logger.debug(`Failed to parse message for filtering, broadcasting anyway (${data.length} bytes)`);
    }
  2. Race Condition Risk: The refreshAllClients() method iterates through clients without synchronization. If clients disconnect during iteration, it's handled gracefully, but consider adding a warning if the client list changes significantly during refresh.

  3. No Rate Limiting: refreshAllClients() sends full config to all clients simultaneously. For deployments with many virtual node clients, this could create traffic bursts. Consider adding a small delay between client refreshes.

🚀 Performance Considerations

Positive:

  • ✅ Parsing is done once per message, then reused for both filtering and processing
  • ✅ Early filtering prevents unnecessary network traffic to virtual clients
  • ✅ Refresh only triggers on reconnection, not on every message

Recommendations:

  • Consider adding metrics/logging for filtered channel messages to monitor effectiveness
  • The refreshAllClients() could benefit from parallel execution with Promise.all() for better performance with multiple clients

🔒 Security Assessment

  • ✅ No security concerns introduced
  • ✅ Filtering logic is conservative - when in doubt, it broadcasts (fail-safe approach)
  • ✅ No changes to existing admin command blocking or authentication flows

🧪 Test Coverage Analysis

Current State:

  • ✅ 2248 unit tests pass
  • ✅ Basic virtual node server tests exist (src/server/virtualNodeServer.test.ts)

Missing Coverage:

  • ❗ No tests for the new filtering logic in meshtasticManager.ts
  • ❗ No tests for refreshAllClients() method
  • ❗ No integration tests for the reconnection scenario

Recommended Test Additions:

// Test filtering logic
it('should filter out channel messages from virtual node broadcast', () => {
  // Test that FromRadio.channel messages are not broadcast to virtual clients
});

it('should broadcast non-channel messages to virtual clients', () => {
  // Test that other message types still get broadcast
});

// Test refresh functionality  
it('should refresh all connected clients after reconnection', () => {
  // Test refreshAllClients() behavior
});

🎯 Overall Assessment

This is a high-quality fix that addresses the specific issue effectively:

  • Bug Fix Quality: Directly solves the "Channel Name" placeholder issue
  • Code Quality: Clean, well-documented implementation
  • Architecture: Follows existing patterns and doesn't introduce technical debt
  • Backwards Compatibility: No breaking changes to existing functionality

Minor Improvements Suggested:

  1. Add debug logging for filtered messages
  2. Consider rate limiting for refreshAllClients()
  3. Add unit tests for the new filtering logic
  4. Consider adding a metric for filtered channel message count

The implementation is production-ready and effectively addresses the issue described in #1567.


@Yeraze Yeraze merged commit 80c29ad into main Jan 27, 2026
11 checks passed
@Yeraze Yeraze deleted the fix/1567-virtual-node-channel-name-broadcast branch January 27, 2026 14:30
Yeraze added a commit that referenced this pull request Jan 27, 2026
The previous fix (#1659) prevented broadcasting channel config during
physical node reconnection, but sendInitialConfig() still replayed
cached channel bytes from the radio. Since the radio sends channels
with empty name strings, the Android app would display "Channel NAme"
after every container restart.

Now channels are rebuilt fresh from the database (like NodeInfo and
MyNodeInfo already were), ensuring proper channel names are always
sent to virtual node clients.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
dpaschal pushed a commit to dpaschal/meshcore-monitor that referenced this pull request Mar 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] After upgrading to 3.1.x all channels on Meshtastic app show as "Channel Name"

1 participant