nx_friend_video_caller.nx
buildroot/runtime/nx_friend_video_caller.nx
about
nx_friend_video_caller.nx -- bits-up NishiLang FRIEND who joins a
/video signaling room and reports a substrate-honest verdict.
Replaces the python harness at bench/ops/nx_friend_video_caller.py
per cardinal feedback-no-third-party-in-build-path-source-of-truth-is-bits-up
and the operator's mandate "we are nishi lang from bits up".
Single-friend per process: opens a TCP socket to host:port,
completes the RFC 6455 client-side WebSocket upgrade against the
live nx_signaling daemon, sends a {"type":"hello"} JSON envelope,
elects offerer/answerer by who-sees-whose-hello-first, exchanges
offer+answer + one ICE candidate. Two FRIENDS launched in
parallel against the same room ID complete the dance like two
browsers on Zoom.
Sealed verdict enum (mirrors python harness keywords so deploy
scripts continue parsing):
NX_FRIEND_OK pair completed offer/answer/ice
NX_FRIEND_CONNECT_FAIL TCP connect failed
NX_FRIEND_UPGRADE_FAIL WS upgrade != 101
NX_FRIEND_ROLE_UNDECIDED never elected offerer/answerer
NX_FRIEND_OFFER_NEVER_ARRIVED elected answerer; no offer relayed
NX_FRIEND_ANSWER_NEVER_ARRIVED elected offerer; no answer relayed
NX_FRIEND_ICE_NEVER_RELAYED dance ok but no ICE candidate seen
NX_FRIEND_FRAME_BAD non-text frame from peer
NX_FRIEND_JSON_BAD payload not valid JSON envelope
NX_FRIEND_TIMEOUT 5s overall deadline elapsed
Composes:
nx_syscalls (sys_socket/connect/read/write/exit)
nx_websocket_client_upgrade (client-side WS HTTP upgrade)
nx_websocket_stream (frame-from-fd / send-text-to-fd)
nx_websocket_frame (opcode constants)
PROTOCOL ENVELOPES (hand-rolled byte literals per task addendum --
NishiLang has no json library; we write the bytes we want directly):
hello: {"type":"hello"} (15 bytes)
offer: {"type":"offer","sdp":{"type":"offer","sdp":"v=0\r\n"}}
answer: {"type":"answer","sdp":{"type":"answer","sdp":"v=0\r\n"}}
dependencies 5 imports · 1 importers
imports: nx_syscalls.nxnx_connect.nxnx_websocket_client_upgrade.nxnx_websocket_stream.nxnx_websocket_frame.nx
imported by: nx_friend_video_caller_test.nx
structs
| none |
consts
| 64 | const NX_FRIEND_OK: i64 = 1 |
| 65 | const NX_FRIEND_CONNECT_FAIL: i64 = 2 |
| 66 | const NX_FRIEND_UPGRADE_FAIL: i64 = 3 |
| 67 | const NX_FRIEND_ROLE_UNDECIDED: i64 = 4 |
| 68 | const NX_FRIEND_OFFER_NEVER_ARRIVED: i64 = 5 |
| 69 | const NX_FRIEND_ANSWER_NEVER_ARRIVED: i64 = 6 |
| 70 | const NX_FRIEND_ICE_NEVER_RELAYED: i64 = 7 |
| 71 | const NX_FRIEND_FRAME_BAD: i64 = 8 |
| 72 | const NX_FRIEND_JSON_BAD: i64 = 9 |
| 73 | const NX_FRIEND_TIMEOUT: i64 = 10 |
| 74 | const NX_FRIEND_VERDICT_N: i64 = 11 |
| 76 | const NX_FRIEND_ROLE_NONE: i64 = 0 |
| 77 | const NX_FRIEND_ROLE_OFFERER: i64 = 1 |
| 78 | const NX_FRIEND_ROLE_ANSWERER: i64 = 2 |
| 80 | const NX_FRIEND_AF_INET: i64 = 2 |
| 81 | const NX_FRIEND_SOCK_STREAM: i64 = 1 |
| 83 | const NX_FRIEND_HDR_BUF_BYTES: i64 = 2048 |
| 84 | const NX_FRIEND_FRAME_BUF_BYTES: i64 = 8192 |
| 85 | const NX_FRIEND_MAX_ITERS: i64 = 16 // hard ceiling on recv loop |
functions
| 87 | func nx_friend_verdict_is_valid(v: i64) -> i64 called by 1: main |
| 98 | func nx_friend_hello_bytes() -> *u8 |
| 102 | func nx_friend_offer_bytes() -> *u8 |
| 106 | func nx_friend_answer_bytes() -> *u8 |
| 110 | func nx_friend_ice_bytes() -> *u8 |
| 114 | func _friend_strlen(s: *u8) -> i64 |
| 120 | func nx_friend_hello_len() -> i64 { return _friend_strlen(nx_friend_hello_bytes()) } |
| 121 | func nx_friend_offer_len() -> i64 { return _friend_strlen(nx_friend_offer_bytes()) } |
| 122 | func nx_friend_answer_len() -> i64 { return _friend_strlen(nx_friend_answer_bytes()) } |
| 123 | func nx_friend_ice_len() -> i64 { return _friend_strlen(nx_friend_ice_bytes()) } |
| 128 | func _friend_build_sockaddr(out: *u8, a: i64, b: i64, c: i64, d: i64, port: i64) -> i64 |
| 148 | func nx_friend_envelope_type(payload: *u8, n: i64) -> i64 |
| 271 | func nx_friend_run_dance(fd: i64, |
| 351 | func nx_friend_video_call( |
| 386 | func main() -> i64 |