diff options
Diffstat (limited to 'packages/meshbay-node/src/meshbay_node/config.py')
| -rw-r--r-- | packages/meshbay-node/src/meshbay_node/config.py | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/config.py b/packages/meshbay-node/src/meshbay_node/config.py index e4444d3..3de2473 100644 --- a/packages/meshbay-node/src/meshbay_node/config.py +++ b/packages/meshbay-node/src/meshbay_node/config.py @@ -37,6 +37,13 @@ ui_port = 18000 # local admin UI (127.0.0.1 only) invite_ttl_hours = 168 # 7 days pair_ttl_hours = 24 +# How many people may watch a video at once. One ffmpeg runs per viewer for as +# long as they watch — it remuxes rather than re-encodes, so it costs little CPU +# and around 50 MB of memory, and spends most of the film idle. Past this, a +# viewer is told the server is busy. Raise it on a machine with memory to spare; +# lower it on a Pi. +max_concurrent_streams = 8 + # Browser and native clients reach this node over WebRTC DataChannel via hub # signaling — no inbound port to open. QUIC is the optional direct path. @@ -82,6 +89,11 @@ class NodeConfig: # the SSH session that printed it. invite_ttl_hours: int = 168 # 7 days pair_ttl_hours: int = 24 + # How many people may watch a video at the same time. One ffmpeg runs per + # viewer for as long as they watch, so this is the knob that decides when + # the node answers "server busy" — see MAX_CONCURRENT_TRANSCODES in + # transport/webrtc_server.py for what one costs. + max_concurrent_streams: int = 8 @dataclass @@ -121,6 +133,30 @@ class Config: return self.groups[0] if self.groups else GroupConfig() +def _positive(value: object, default: int, name: str) -> int: + """A count that must be at least one, or the default with a word about it. + + Zero is the dangerous one: `asyncio.Semaphore(0)` is not "no limit", it is + a node where no video ever plays and nothing in the log says why. + """ + # bool before int: TOML `true` is a bool, and `int(True)` is 1 — a node + # where exactly one person may watch, arrived at by a typo and announced + # nowhere. + if isinstance(value, bool) or not isinstance(value, (int, str)): + log.warning("%s = %r is not a count — using %d", name, value, default) + return default + try: + n = int(value) + except (TypeError, ValueError): + log.warning("%s = %r is not a number — using %d", name, value, default) + return default + if n < 1: + log.warning("%s = %d would stop the feature entirely — using %d", + name, n, default) + return default + return n + + def load_config(path: Path = DEFAULT_CONFIG_PATH) -> Config: """ Load config from TOML file. Supports both single [group] and @@ -144,6 +180,9 @@ def load_config(path: Path = DEFAULT_CONFIG_PATH) -> Config: nd.get("invite_ttl_hours", cfg.node.invite_ttl_hours)) cfg.node.pair_ttl_hours = int( nd.get("pair_ttl_hours", cfg.node.pair_ttl_hours)) + cfg.node.max_concurrent_streams = _positive( + nd.get("max_concurrent_streams", cfg.node.max_concurrent_streams), + cfg.node.max_concurrent_streams, "max_concurrent_streams") # Multi-group: [[groups]] array if "groups" in raw: @@ -189,6 +228,10 @@ def load_config(path: Path = DEFAULT_CONFIG_PATH) -> Config: cfg.hub.username = user if port := os.environ.get("MESHBAY_QUIC_PORT"): cfg.node.quic_port = int(port) + if streams := os.environ.get("MESHBAY_MAX_CONCURRENT_STREAMS"): + cfg.node.max_concurrent_streams = _positive( + streams, cfg.node.max_concurrent_streams, + "MESHBAY_MAX_CONCURRENT_STREAMS") return cfg |