feat: relay several servers, registered through the control API

This commit is contained in:
rmanach
2026-10-01 13:32:45 +02:00
parent af2dc3af53
commit 6b2b137c1d
18 changed files with 1496 additions and 376 deletions
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 43 KiB

+2 -1
View File
@@ -9,13 +9,14 @@ participant "ET server" as et
actor "Player\n203.0.113.7" as player
note over admin, et : the ET server shows the player as <front-wg>:51234
note over admin, control : every call carries the key the server registered with
admin -> control : GET /sessions
control --> admin : [{client: 203.0.113.7:27960, port: 51234}]
note right of admin : port 51234 = 203.0.113.7
== Ban ==
admin -> control : PUT /bans/203.0.113.7\n{reason, minutes}
control -> control : bans.json (atomic write)\ncut 203.0.113.7's sessions
control -> control : bans-<port>.json (atomic write)\ncut 203.0.113.7's sessions
player -> relay : game packets
relay -> relay : banned: dropped
note over et : no packet: times the player out
Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

+29
View File
@@ -0,0 +1,29 @@
@startuml
skinparam shadowing false
title Registering a server (pairing)
participant "Admin tool\n(etadm)" as admin
participant "ET server\n<et-server>:27960" as et
participant "etrelay control API\n<front-wg>:8090" as control
participant "Masters" as master
note over admin : picks a key once\n(kept on its side)
admin -> et : rcon: sets etrelay_proof <fingerprint of the key>
admin -> control : PUT /server {port: 27960, upstream_port: 27960, key}\nBearer: the relay's token
control -> control : port offered and free?\n(409: held by another server)
control -> et : getstatus
et --> control : statusResponse\n...\\etrelay_proof\\<fingerprint>...
control -> control : fingerprint == sha256(key)?\n(403: not shown)
control -> control : bind :27960, keep sha256(key)\nin servers.json
control --> admin : 200 {port, upstream, since, alive}
admin -> et : rcon: set etrelay_proof ""
control -> master : heartbeat EnemyTerritory-1\nfrom :27960
== Later ==
admin -> control : GET /sessions, /bans...\nBearer: the key (names the server)
control --> admin : this server's only
note over admin, control : 401 (the relay lost its state):\nthe admin tool registers again
admin -> control : DELETE /server
control -> master : heartbeat ETFlatline-1
note over control : port freed, bans dropped
@enduml
Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 83 KiB

+12 -4
View File
@@ -2,14 +2,18 @@
skinparam shadowing false
title Tasks and data flow
rectangle "relay loop (main task)" as loop {
rectangle "relay loop (one per server)" as loop {
card "public socket\nrecv_from" as recv
card "filter\n(commands, query rate)" as filter
}
rectangle "shared state (Mutex)" as shared {
rectangle "server state (Mutex, one per server)" as shared {
card "sessions:\nHashMap<client, Session>" as map
card "bans\n(bans.json)" as bans
card "bans\n(bans-<port>.json)" as bans
}
rectangle "registry (Mutex)" as registry {
card "servers by public port,\ntheir key's hash\n(servers.json)" as servers
}
rectangle "session task (one per client)" as st {
@@ -17,12 +21,13 @@ rectangle "session task (one per client)" as st {
card "upstream socket\n(connected to ET)" as up
}
rectangle "heartbeat task" as hb {
rectangle "heartbeat task (one per server)" as hb {
card "interval 5 min" as tick
card "probe socket" as probe
}
rectangle "control API task (axum)" as ctl {
card "PUT/GET/DELETE /server" as pairing
card "GET /sessions\nGET/PUT/DELETE /bans" as routes
}
@@ -36,4 +41,7 @@ tick --> probe : getinfo
tick --> recv : heartbeat via public socket
routes --> map : list ports,\ndrop a banned IP's sessions
routes --> bans : set / lift
routes --> servers : key -> server
pairing --> servers : register / leave
servers --> loop : start / stop\n(with its heartbeat)
@enduml