code wiki / _hdl_build / nx_room_relay.nx
nx_room_relay.nx source
↩ module page · 78 lines · 3370 B
1// nx_room_relay.nx -- the SOVEREIGN server-side relay core for Nishi video.
2// Per-room, per-peer latest-frame store + live roster. The no-WS down-channel
3// (nx_room_stream) pushes each peer the OTHER live peers' newest frames; peers
4// upload via POST. Server-relay model = works through any NAT with ZERO
5// WebRTC/STUN/TURN (the flaky third-party ICE the cardboard depended on).
6// Pure buffer ops: imports nothing, no syscalls -- caller supplies the state
7// arena (like nx_video_client_wasm / nx_room_stream). Proven by nx_room_relay_gate.
8//
9// State layout (st: *i64): st[0]=nslots, st[1]=slot_bytes, then 5 parallel
10// arrays of nslots each -> room_hash, peer_id, last_seq, last_seen_ms, frame_len.
11// A slot is FREE when room_hash==0 (room hashes are nonzero by construction).
12// Frame bytes for slot i live at arena[i*slot_bytes ..] (arena: nslots*slot_bytes).
13// license_tier: ORIGINAL
14
15func rr_init(st: *i64, nslots: i64, slotb: i64) -> i64 {
16 st[0] = nslots; st[1] = slotb
17 var i: i64 = 0
18 while i < 5 * nslots { st[2 + i] = 0; i = i + 1 }
19 return 0
20}
21
22// find slot for (room, peer) or -1
23func rr_find(st: *i64, rm: i64, pr: i64) -> i64 {
24 let n: i64 = st[0]; var i: i64 = 0
25 while i < n { if st[2 + i] == rm { if st[2 + n + i] == pr { return i } } i = i + 1 }
26 return 0 - 1
27}
28
29// first free slot or -1
30func rr_alloc(st: *i64) -> i64 {
31 let n: i64 = st[0]; var i: i64 = 0
32 while i < n { if st[2 + i] == 0 { return i } i = i + 1 }
33 return 0 - 1
34}
35
36// store/update a peer's latest frame in its room; returns slot or -1 if room full
37func rr_post(st: *i64, arena: *u8, rm: i64, pr: i64, now: i64, sq: i64, frame: *u8, fl: i64) -> i64 {
38 let n: i64 = st[0]; let slotb: i64 = st[1]
39 var s: i64 = rr_find(st, rm, pr)
40 if s < 0 { s = rr_alloc(st); if s < 0 { return 0 - 1 } st[2 + s] = rm; st[2 + n + s] = pr }
41 var f: i64 = fl
42 if f > slotb { f = slotb }
43 var j: i64 = 0
44 while j < f { arena[s * slotb + j] = frame[j]; j = j + 1 }
45 st[2 + 2 * n + s] = sq; st[2 + 3 * n + s] = now; st[2 + 4 * n + s] = f
46 return s
47}
48
49// list OTHER live peers (seen within ttl) in a room into out[]; returns count
50func rr_roster(st: *i64, rm: i64, self_pr: i64, now: i64, ttl: i64, out: *i64) -> i64 {
51 let n: i64 = st[0]; var c: i64 = 0; var i: i64 = 0
52 while i < n {
53 if st[2 + i] == rm {
54 if st[2 + n + i] != self_pr {
55 if (now - st[2 + 3 * n + i]) <= ttl { out[c] = st[2 + n + i]; c = c + 1 }
56 }
57 }
58 i = i + 1
59 }
60 return c
61}
62
63// slot of a live target peer (for relaying its frame), or -1 if absent/stale
64func rr_live(st: *i64, rm: i64, pr: i64, now: i64, ttl: i64) -> i64 {
65 let n: i64 = st[0]
66 let s: i64 = rr_find(st, rm, pr)
67 if s < 0 { return 0 - 1 }
68 if (now - st[2 + 3 * n + s]) > ttl { return 0 - 1 }
69 return s
70}
71
72func rr_seq(st: *i64, s: i64) -> i64 { let n: i64 = st[0]; return st[2 + 2 * n + s] }
73func rr_flen(st: *i64, s: i64) -> i64 { let n: i64 = st[0]; return st[2 + 4 * n + s] }
74// slot iteration accessors (for the live chunked-push stream)
75func rr_nslots(st: *i64) -> i64 { return st[0] }
76func rr_room(st: *i64, s: i64) -> i64 { return st[2 + s] }
77func rr_peer(st: *i64, s: i64) -> i64 { let n: i64 = st[0]; return st[2 + n + s] }
78func rr_seen(st: *i64, s: i64) -> i64 { let n: i64 = st[0]; return st[2 + 3 * n + s] }