diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-19 08:54:52 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-19 08:54:52 +0200 |
| commit | 933daccbcfde7705413d3a10db87d910c650ed42 (patch) | |
| tree | d9b9372868f8f71c4fcb9d6e85600977fcfc0df6 /packages/meshbay-node/src/meshbay_node/roster.py | |
| parent | 765214c22e7956f9add1501c69e00c918f3e5f2b (diff) | |
| download | meshbay-933daccbcfde7705413d3a10db87d910c650ed42.tar.gz | |
fix(node): node.toml's transfer pools reach the transport
The daemon built the defaults dict for `Roster.node_settings` by hand and
left out `max_concurrent_downloads` and `max_concurrent_uploads`. Absent
from the dict, both resolved to None, were assigned back onto the config,
and the transport skipped them — so node.toml was parsed, validated, and
then replaced by `transfers.py`'s own 8. Invisible to anyone who left the
value at 8, which is the value the template suggests.
There were three copies of that dict and they all disagreed: node_status'
was missing those two and `max_upload_gb` besides. One builder now,
`config.node_settings_defaults`, and the resolver's key list is a class
attribute the tests hold it to, along with the writer's.
1429 passed against a baseline of 1423; the two new behavioural tests fail
with the builder reverted.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-node/src/meshbay_node/roster.py')
| -rw-r--r-- | packages/meshbay-node/src/meshbay_node/roster.py | 53 |
1 files changed, 37 insertions, 16 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/roster.py b/packages/meshbay-node/src/meshbay_node/roster.py index 474db31..0753400 100644 --- a/packages/meshbay-node/src/meshbay_node/roster.py +++ b/packages/meshbay-node/src/meshbay_node/roster.py @@ -988,34 +988,55 @@ class Roster: SETTING_STUN_SERVERS = "stun_servers" SETTING_ICE_INTERFACES = "ice_interfaces" + # Every setting this resolver answers for, and how a stored string becomes + # a value. `node_settings` iterates these two and nothing else, and + # `config.node_settings_defaults` is built from the same names — so the + # defaults dict cannot quietly cover fewer settings than are resolved. + # + # It did. The daemon's dict was written by hand and omitted the two + # transfer pools, so on a node with no panel override they resolved to + # `defaults.get(key)` → None, were assigned back onto the config, and the + # transport skipped them: `node.toml` was parsed, validated, and then + # replaced by the transport's own defaults. A missing key is not an error + # anywhere along that path — it is a setting that stops working in silence, + # and invisible unless the operator picked a value other than the default. + NODE_SETTING_SCALARS: tuple[tuple[str, str, str], ...] = ( + ("invite_ttl_hours", SETTING_INVITE_TTL, "int"), + ("pair_ttl_hours", SETTING_PAIR_TTL, "int"), + ("device_request_ttl_minutes", SETTING_DEVICE_TTL, "int"), + ("max_concurrent_streams", SETTING_MAX_STREAMS, "int"), + ("max_concurrent_downloads", SETTING_MAX_DOWNLOADS, "int"), + ("max_concurrent_uploads", SETTING_MAX_UPLOADS, "int"), + ("transcode_incompatible_video", SETTING_TRANSCODE, "bool"), + ("max_upload_gb", SETTING_MAX_UPLOAD_GB, "float"), + ) + NODE_SETTING_LISTS: tuple[tuple[str, str], ...] = ( + ("stun_servers", SETTING_STUN_SERVERS), + ("ice_interfaces", SETTING_ICE_INTERFACES), + ) + + @classmethod + def node_setting_keys(cls) -> frozenset[str]: + """Every key `node_settings` returns — what a defaults dict must cover.""" + return frozenset([k for k, _, _ in cls.NODE_SETTING_SCALARS] + + [k for k, _ in cls.NODE_SETTING_LISTS]) + async def node_settings(self, defaults: dict) -> dict: """Current effective settings: roster override if present, else config default.""" import json as _json result = {} - for key, setting in [ - ("invite_ttl_hours", self.SETTING_INVITE_TTL), - ("pair_ttl_hours", self.SETTING_PAIR_TTL), - ("device_request_ttl_minutes", self.SETTING_DEVICE_TTL), - ("max_concurrent_streams", self.SETTING_MAX_STREAMS), - ("max_concurrent_downloads", self.SETTING_MAX_DOWNLOADS), - ("max_concurrent_uploads", self.SETTING_MAX_UPLOADS), - ("transcode_incompatible_video", self.SETTING_TRANSCODE), - ("max_upload_gb", self.SETTING_MAX_UPLOAD_GB), - ]: + for key, setting, kind in self.NODE_SETTING_SCALARS: stored = await self.get_setting(self.NODE_WIDE_GROUP_ID, setting) if stored is not None: - if key == "transcode_incompatible_video": + if kind == "bool": result[key] = stored != "0" - elif key == "max_upload_gb": + elif kind == "float": result[key] = float(stored) else: result[key] = int(stored) else: result[key] = defaults.get(key) - for list_key, setting in [ - ("stun_servers", self.SETTING_STUN_SERVERS), - ("ice_interfaces", self.SETTING_ICE_INTERFACES), - ]: + for list_key, setting in self.NODE_SETTING_LISTS: stored = await self.get_setting(self.NODE_WIDE_GROUP_ID, setting) if stored is not None: try: |