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] }