code wiki / (root) / nx_chat_session.nx

nx_chat_session.nx source

↩ module page · 140 lines · 4928 B

1// nx_chat_session.nx -- concrete chat-session subtype. 2// 3// Extends nx_media_session (embedded as FIRST field per the OOP 4// inheritance pattern). Wraps nx_chat_ring (the bounded-ring buffer 5// promoted from nishi_video_room_synology.nx) and exposes the 6// standard session vtable. 7// 8// Consumers: 9// nx_video_room.nx -- chat alongside audio + video 10// nx_call.nx -- chat in a 1:1 call 11// nx_iot_intercom.nx -- async text between devices 12// nx_cli_meet.nx -- text-only conferencing 13 14// nx_safety_envelope: 15// intended_use: reusable chat session for sovereign media stack 16// sil_target: SIL2 17// evidence: composes nx_chat_ring + nx_media_session; 18// bench/nx_chat_session_smoke.nx asserts 19// open -> post -> read -> close 20// verdict: NOT_YET_EVALUATED -- pending smoke 21 22import "nx_syscalls_x86_64.nx" 23import "nx_media_session.nx" 24import "nx_chat_ring.nx" 25 26// ---- The struct ---- 27 28struct nx_chat_session { 29 base: nx_media_session, // FIRST -- pointer-cast-up 30 ring: *nx_chat_ring, 31 // Pluggable persistence (null = ephemeral, future: *nx_chat_persist). 32 persist: i64, 33 // Future MLS group-key holder (null until L8 nx_mls lands). 34 mls_state: i64, 35} 36 37const NX_CHAT_SESSION_BYTES: i64 = 160 38 39// ---- Vtable impls ---- 40 41func nx_chat_session_open_impl(ms: *nx_media_session) -> i64 { 42 let s: *nx_chat_session = ms as *nx_chat_session 43 if s.ring as i64 == 0 { 44 s.base.state = NX_MEDIA_STATE_ERROR 45 return -1 46 } 47 s.base.state = NX_MEDIA_STATE_ACTIVE 48 return 0 49} 50 51func nx_chat_session_close_impl(ms: *nx_media_session) -> i64 { 52 let s: *nx_chat_session = ms as *nx_chat_session 53 s.base.state = NX_MEDIA_STATE_CLOSED 54 return 0 55} 56 57func nx_chat_session_on_peer_join_impl(ms: *nx_media_session, 58 peer_id: i64, reason: i64) -> i64 { 59 return 0 60} 61 62func nx_chat_session_on_peer_leave_impl(ms: *nx_media_session, 63 peer_id: i64, reason: i64) -> i64 { 64 return 0 65} 66 67func nx_chat_session_on_tier_change_impl(ms: *nx_media_session, 68 new_bw_tier: i64, 69 new_hw_tier: i64) -> i64 { 70 return 0 71} 72 73func nx_chat_session_health_check_impl(ms: *nx_media_session) -> i64 { 74 let s: *nx_chat_session = ms as *nx_chat_session 75 if s.base.state == NX_MEDIA_STATE_ACTIVE { return NX_MEDIA_HEALTH_OK } 76 if s.base.state == NX_MEDIA_STATE_ERROR { return NX_MEDIA_HEALTH_FAILING } 77 if s.base.state == NX_MEDIA_STATE_CLOSED { return NX_MEDIA_HEALTH_DEAD } 78 return NX_MEDIA_HEALTH_UNKNOWN 79} 80 81// ---- Constructor ---- 82 83func nx_chat_session_new(out: *nx_chat_session, 84 room_id: i64, 85 ring_cap_slots: i64, ring_txt_cap: i64) -> i64 { 86 let ms: *nx_media_session = out as *nx_media_session 87 nx_media_session_init(ms, NX_MEDIA_KIND_CHAT, room_id) 88 89 out.base.open_fn = nx_chat_session_open_impl 90 out.base.close_fn = nx_chat_session_close_impl 91 out.base.on_peer_join_fn = nx_chat_session_on_peer_join_impl 92 out.base.on_peer_leave_fn = nx_chat_session_on_peer_leave_impl 93 out.base.on_tier_change_fn = nx_chat_session_on_tier_change_impl 94 out.base.health_check_fn = nx_chat_session_health_check_impl 95 96 let ring: *nx_chat_ring = sys_mmap(NX_CHAT_RING_BYTES) as *nx_chat_ring 97 nx_chat_ring_new(ring, ring_cap_slots, ring_txt_cap) 98 out.ring = ring 99 out.persist = 0 100 out.mls_state = 0 101 return 0 102} 103 104// ---- API ---- 105 106// Post a message; returns the assigned seq, or NX_CHAT_RING_ERR_*. 107func nx_chat_session_post(s: *nx_chat_session, 108 peer_id: i64, kind: i64, 109 txt: *u8, txt_len: i64, 110 unix_ms: i64) -> i64 { 111 if s.base.state != NX_MEDIA_STATE_ACTIVE { return -1 } 112 nx_media_session_touch(s as *nx_media_session, unix_ms) 113 return nx_chat_ring_append(s.ring, peer_id, kind, txt, txt_len, unix_ms) 114} 115 116// Read message count. 117func nx_chat_session_count(s: *nx_chat_session) -> i64 { 118 return nx_chat_ring_count(s.ring) 119} 120 121// Read the next seq number that would be assigned. 122func nx_chat_session_next_seq(s: *nx_chat_session) -> i64 { 123 return nx_chat_ring_next_seq(s.ring) 124} 125 126// Read a slot by index in ring order. 127func nx_chat_session_get_at(s: *nx_chat_session, i: i64) -> *ChatSlot { 128 return nx_chat_ring_get_at(s.ring, i) 129} 130 131// Resolve a seq number to its slot. 132func nx_chat_session_get_by_seq(s: *nx_chat_session, seq: i64) -> *ChatSlot { 133 return nx_chat_ring_get_by_seq(s.ring, seq) 134} 135 136// Copy a slot's text out. 137func nx_chat_session_copy_text(s: *nx_chat_session, slot: *ChatSlot, 138 dst: *u8, dst_cap: i64) -> i64 { 139 return nx_chat_ring_copy_text(s.ring, slot, dst, dst_cap) 140}