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}