feat: multi-network namespace multiplexing

Multiplex all networks onto a single client connection using /network
suffixes on channels and nicks. PASS is now just the password (no
network prefix). Channels appear as #channel/network, foreign nicks as
nick/network, own nicks stay bare.

New namespace.py module with pure encode/decode functions. Router
tracks clients globally (not per-network), namespaces messages before
delivery. Client attaches to all networks on connect, sends synthetic
JOIN/TOPIC/NAMES for every channel across all networks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
user
2026-02-20 19:03:58 +01:00
parent ab7603f638
commit 8cc57a7af4
13 changed files with 512 additions and 131 deletions

View File

@@ -82,59 +82,78 @@ Configure your IRC client to connect to the bouncer:
|---------|-------|
| Server | `127.0.0.1` |
| Port | `6667` (or as configured) |
| Password | `networkname:yourpassword` |
| Password | `yourpassword` |
### Password Format
```
PASS <network>:<password>
PASS <password>
```
- `network` -- matches a `[networks.NAME]` section in config
- `password` -- the `bouncer.password` value from config
If you omit the network prefix (`PASS yourpassword`), the first configured
network is used.
The password is the `bouncer.password` value from config. A single connection
automatically attaches to **all** configured networks.
### Client Examples
**irssi:**
```
/connect -password libera:mypassword 127.0.0.1 6667
/connect -password mypassword 127.0.0.1 6667
```
**weechat:**
```
/server add bouncer 127.0.0.1/6667 -password=libera:mypassword
/server add bouncer 127.0.0.1/6667 -password=mypassword
/connect bouncer
```
**hexchat:**
Set server password to `libera:mypassword` in the network settings.
Set server password to `mypassword` in the network settings.
## Multiple Networks
## Multi-Network Namespacing
Define multiple `[networks.*]` sections in the config. Each gets its own
persistent server connection through the SOCKS5 proxy.
Connect your client with the appropriate network prefix:
All configured networks are multiplexed onto a single client connection. Channels
and nicks carry a `/network` suffix so you can tell which network they belong to:
```
PASS libera:mypassword # connects to [networks.libera]
PASS oftc:mypassword # connects to [networks.oftc]
Client sees: Server wire:
#libera/libera <-> #libera (on libera network)
#debian/oftc <-> #debian (on oftc network)
user123/libera <-> user123 (on libera network)
```
Multiple clients can attach to the same network simultaneously. All receive
the same messages in real time.
### Rules
- **Channels**: `#channel/network` in client, `#channel` on wire
- **Foreign nicks**: `nick/network` in client, `nick` on wire
- **Own nicks**: shown without suffix (prevents client confusion)
- **Sending messages**: include the `/network` suffix in the target
```
/msg #libera/libera hello -> sends "hello" to #libera on libera network
/join #test/oftc -> joins #test on oftc network
/msg user123/libera hi -> private message to user123 on libera
```
### Comma-Separated JOIN/PART
Targets can span networks:
```
/join #a/libera,#b/oftc -> joins #a on libera AND #b on oftc
```
Multiple clients can attach simultaneously. All receive the same namespaced
messages in real time.
## What Clients Receive on Connect
When a client authenticates and attaches to a network:
When a client authenticates:
1. **Backlog replay** -- missed messages since last disconnect
2. **Synthetic welcome** -- 001-004 numeric replies from the bouncer
3. **Channel state** -- TOPIC and NAMES for each joined channel
1. **Backlog replay** -- missed messages (namespaced) from all networks
2. **Synthetic welcome** -- 001-004 numeric replies listing all networks
3. **Channel state** -- synthetic JOIN, TOPIC, and NAMES for every joined
channel across all networks (all namespaced with `/network` suffix)
## Backlog