Skip to content

Add targeted RPC transmission by ClientNo (#239)#286

Closed
hacha wants to merge 14 commits intodevelopfrom
feature/239-targeted-rpc
Closed

Add targeted RPC transmission by ClientNo (#239)#286
hacha wants to merge 14 commits intodevelopfrom
feature/239-targeted-rpc

Conversation

@hacha
Copy link
Collaborator

@hacha hacha commented Jan 15, 2026

Summary

  • Add ability to send RPC messages to specific client(s) by ClientNo instead of broadcasting to all clients
  • New public API: RpcTo(int targetClientNo, ...) and RpcTo(int[] targetClientNos, ...)
  • Uses ROUTER→DEALER direct delivery for efficient targeted messaging

Changes

Server (Python)

  • Add MSG_RPC_TARGETED (11) message type
  • Add _get_client_identity_by_client_no() helper for identity lookup
  • Add _send_rpc_to_clients() for ROUTER-based direct delivery
  • Add sender verification to reject RPCs from unknown identities
  • Add function name length validation (max 255 bytes)

Unity Client (C#)

  • Add RpcTo() public API methods to NetSyncManager
  • Add SendTo() method to RPCManager with queuing support
  • Add DEALER socket polling in ConnectionManager for incoming targeted messages
  • Add MSG_RPC_TARGETED handling in MessageProcessor

Tests

  • Add comprehensive unit tests for targeted RPC serialization (test_rpc_targeted.py)

Binary Format

[1 byte]  MSG_RPC_TARGETED (11)
[2 bytes] senderClientNo (ushort LE)
[2 bytes] targetCount (ushort LE)
[2 bytes * N] targetClientNos (ushort array LE)
[1 byte]  functionName length
[N bytes] functionName (UTF-8)
[2 bytes] argsJson length (ushort LE)
[N bytes] argsJson (UTF-8)

Usage

// Send to single client
NetSyncManager.Instance.RpcTo(2, "FunctionName", args);

// Send to multiple clients
NetSyncManager.Instance.RpcTo(new[] { 2, 3, 5 }, "FunctionName", args);

// Existing broadcast API unchanged
NetSyncManager.Instance.Rpc("FunctionName", args);  // All clients

Test plan

  • Verify Python tests pass: pytest tests/test_rpc_targeted.py
  • Verify Unity compilation succeeds
  • Test single-target RPC delivery
  • Test multi-target RPC delivery
  • Verify existing Rpc() broadcast still works
  • Test RpcTo() queuing before ready state

Closes #239

🤖 Generated with Claude Code

hacha and others added 14 commits January 14, 2026 12:16
Introduce configuration file support for STYLY NetSync Server.
This commit adds:

- New config.py module with ServerConfig dataclass
- --config CLI option to specify TOML configuration file
- Network settings: dealer_port, pub_port, server_discovery_port,
  server_name, enable_server_discovery
- Configuration validation and CLI argument merging
- Comprehensive unit tests for configuration module

Configuration priority: CLI args > config file > defaults

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extend configuration file support with timing and performance settings:

- base_broadcast_interval, idle_broadcast_interval, dirty_threshold
- client_timeout, cleanup_interval, device_id_expiry_time
- status_log_interval, main_loop_sleep, poll_timeout

NetSyncServer now accepts a ServerConfig object and uses timing values
from configuration instead of class constants. Backward compatibility
is maintained when config is not provided.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extend configuration with NetworkVariable limit and monitoring settings:

- max_global_vars, max_client_vars: Variable count limits
- max_var_name_length, max_var_value_length: Size limits
- nv_flush_interval: Flush cadence configuration
- nv_monitor_window_size, nv_monitor_threshold: Monitoring settings

NetSyncServer now reads NV limits and monitoring parameters from config.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extend configuration with internal system limits:

- max_virtual_transforms: Maximum virtual transforms per client
- pub_queue_maxsize: Publisher queue size limit
- delta_ring_size: NV sync delta ring buffer size

Add set/get_max_virtual_transforms() functions to binary_serializer.py
for dynamic configuration of the virtual transform limit.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add logging section to TOML configuration with:
  - log_dir: Directory for log files (None = console only)
  - log_level_console: Console log level (default: INFO)
  - log_json_console: Enable JSON console output
  - log_rotation: Custom rotation rule (None = use internal default)
  - log_retention: Custom retention rule (None = use internal default)
- Add validation for log_level_console (must be valid log level)
- Add CLI args merging for logging settings
- Refactor main() to configure logging after config loading
  so that config file settings can be applied
- Add comprehensive tests for logging configuration

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add examples/config.toml with all configurable settings
- Include comprehensive comments explaining each setting
- Show default values and usage examples
- Document configuration priority: CLI args > config file > defaults

Usage:
  styly-netsync-server --config examples/config.toml

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change argparse default from "INFO" to None so that CLI args only
override config file values when explicitly specified by the user.

Previously, argparse default="INFO" meant args.log_level_console was
never None, so merge_cli_args always overwrote the config file value.

Add regression test to verify None CLI values preserve config settings.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace SystemExit(1) with typed ConfigurationError exception that
stores the list of validation errors. This allows main() to catch
validation errors specifically and print user-friendly messages.

- Add ConfigurationError class with errors attribute
- Update create_config_from_args to raise ConfigurationError
- Update main() to catch ConfigurationError and print each error
- Add tests for ConfigurationError behavior

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add get_unknown_keys() function to detect unknown sections and keys
in TOML configuration files. This helps catch typos like "log_levl_console"
that would otherwise be silently ignored.

- Add get_unknown_keys() function to detect unknown sections/keys
- Warn about unknown keys in create_config_from_args (using print()
  since logging is not yet configured at that point)
- Add comprehensive tests for unknown key detection

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Log the "Loaded configuration from" message after configure_logging()
is called, ensuring the log output uses the properly configured
logging settings rather than loguru's defaults.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add bundled default.toml with all default configuration values
- Remove hardcoded defaults from ServerConfig dataclass
- Remove DEFAULT_* global constants from server.py
- Remove _DEFAULT_* class constants from NetSyncServer
- NetSyncServer now loads default.toml when config is not provided
- Implement layered config: CLI args > user.toml > default.toml
- Rename --config to --user-config for clarity
- Add DefaultConfigError for fatal config loading failures
- Exit with error if default.toml cannot be loaded

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add ability to send RPC messages to specific client(s) by ClientNo
instead of broadcasting to all clients in the room.

Changes:
- binary_serializer.py: Add MSG_RPC_TARGETED (11), serialize/deserialize functions
- server.py: Add _get_client_identity_by_client_no() helper
- server.py: Add _send_rpc_to_clients() for ROUTER-based direct delivery
- server.py: Handle MSG_RPC_TARGETED in receive loop

Binary format for MSG_RPC_TARGETED:
[1b] type | [2b] sender | [2b] count | [2b*N] targets | [1b+N] name | [2b+N] args

Part of #239

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add ability to send RPC messages to specific client(s) by ClientNo
instead of broadcasting to all clients in the room.

Changes:
- BinarySerializer.cs: Add MSG_RPC_TARGETED (11), serialize/deserialize
- DataStructure.cs: Add RPCTargetedMessage class
- RPCManager.cs: Add SendTo() method for targeted RPC sending
- NetSyncManager.cs: Add public RpcTo() API methods
- ConnectionManager.cs: Poll DEALER socket for incoming targeted messages
- MessageProcessor.cs: Handle MSG_RPC_TARGETED in ProcessIncomingMessage

Public API:
- RpcTo(int targetClientNo, string functionName, string[] args)
- RpcTo(int[] targetClientNos, string functionName, string[] args)

Part of #239

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add sender verification to reject RPCs from unknown identities (Server)
- Add function name length validation (max 255 bytes) to prevent overflow
- Unify logging to use argumentsJson key consistently
- Add queuing support for SendTo() when not ready (Unity)
- Add comprehensive unit tests for targeted RPC serialization
- Update README with RpcTo() API examples

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@from2001
Copy link
Collaborator

We'll use #348

#286 #345 #346 #347 #348
Title Add targeted RPC transmission by ClientNo Add RpcTo targeted client delivery Add targeted RpcTo delivery API Add RpcTo targeted client delivery Add targeted RpcTo delivery by client number
Approach New MSG_RPC_TARGETED message type + ROUTER→DEALER direct delivery Encode targets in function name @target:1,2:Fn, filter in MessageProcessor Wrap as system RPC @system:rpc_to with JSON payload Encode targets in function name @target[1,2]|Fn, filter in OnRPCReceivedHandler Extend existing MSG_RPC binary format with targetClientNos field
Lines changed +2335 / -89 +93 / -4 +81 / -0 +106 / -0 +106 / -17
Files changed 15 3 (Unity) 1 (Unity) 2 (Unity) 6 (Unity + Python)
Server changes Yes (new message type + ROUTER delivery) None None None Yes (server-side filtering in _send_rpc_to_room)
Protocol change New message type ID (11) None None None Extends existing RPC binary format

@from2001 from2001 closed this Feb 27, 2026
@from2001 from2001 deleted the feature/239-targeted-rpc branch February 27, 2026 03:46
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.

Support for Individual RPC Transmission by ClientNo

2 participants