mt-lang 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. checksums.yaml +4 -4
  2. data/docs/index.html +4 -3
  3. data/lib/milk_tea/base.rb +1 -1
  4. data/std/asset_pack.mt +267 -0
  5. data/std/async/libuv_runtime.mt +539 -0
  6. data/std/async/mailbox.mt +191 -0
  7. data/std/async/runtime.mt +87 -0
  8. data/std/async.mt +87 -0
  9. data/std/base64.mt +185 -0
  10. data/std/behavior_tree.mt +396 -0
  11. data/std/binary.mt +314 -0
  12. data/std/binary_heap.mt +157 -0
  13. data/std/bitset.mt +239 -0
  14. data/std/box2d.mt +535 -0
  15. data/std/bytes.mt +46 -0
  16. data/std/c/box2d.mt +1254 -0
  17. data/std/c/cgltf.mt +647 -0
  18. data/std/c/cjson.mt +106 -0
  19. data/std/c/crypto.mt +11 -0
  20. data/std/c/crypto_support.h +51 -0
  21. data/std/c/ctype.mt +19 -0
  22. data/std/c/ctype_bindgen.h +29 -0
  23. data/std/c/curl.mt +1223 -0
  24. data/std/c/enet.mt +473 -0
  25. data/std/c/errno.mt +41 -0
  26. data/std/c/errno_bindgen.h +53 -0
  27. data/std/c/flecs.mt +2945 -0
  28. data/std/c/fs.linux.mt +43 -0
  29. data/std/c/fs.windows.mt +43 -0
  30. data/std/c/fs_support.h +954 -0
  31. data/std/c/gl.mt +2065 -0
  32. data/std/c/gl_registry_helpers.h +10748 -0
  33. data/std/c/glfw.mt +499 -0
  34. data/std/c/libc.mt +167 -0
  35. data/std/c/libuv.mt +1491 -0
  36. data/std/c/math.mt +22 -0
  37. data/std/c/math_bindgen.h +31 -0
  38. data/std/c/miniaudio.mt +3420 -0
  39. data/std/c/pcre2.mt +735 -0
  40. data/std/c/process.mt +58 -0
  41. data/std/c/process_support.h +1147 -0
  42. data/std/c/raygui.mt +1602 -0
  43. data/std/c/raylib.mt +1245 -0
  44. data/std/c/raymath.mt +163 -0
  45. data/std/c/rlgl.mt +434 -0
  46. data/std/c/rpng.mt +60 -0
  47. data/std/c/rres.mt +187 -0
  48. data/std/c/sdl3.mt +4132 -0
  49. data/std/c/sqlite3.mt +951 -0
  50. data/std/c/stb_image.mt +52 -0
  51. data/std/c/stb_image_resize2.mt +128 -0
  52. data/std/c/stb_image_write.mt +19 -0
  53. data/std/c/stb_rect_pack.mt +38 -0
  54. data/std/c/stb_truetype.mt +175 -0
  55. data/std/c/stb_vorbis.mt +31 -0
  56. data/std/c/stdio.mt +90 -0
  57. data/std/c/steamworks.h +5769 -0
  58. data/std/c/steamworks.mt +4771 -0
  59. data/std/c/string.mt +16 -0
  60. data/std/c/string_bindgen.h +36 -0
  61. data/std/c/sync.mt +33 -0
  62. data/std/c/sync_support.h +219 -0
  63. data/std/c/terminal.mt +24 -0
  64. data/std/c/terminal_support.h +408 -0
  65. data/std/c/time.mt +26 -0
  66. data/std/c/tls.mt +24 -0
  67. data/std/c/tls_support.h +626 -0
  68. data/std/c/tracy.mt +53 -0
  69. data/std/c/zlib.mt +20 -0
  70. data/std/c/zlib_support.h +239 -0
  71. data/std/c/zstd.mt +231 -0
  72. data/std/cell.mt +60 -0
  73. data/std/cgltf.mt +115 -0
  74. data/std/cjson.mt +90 -0
  75. data/std/cli.mt +768 -0
  76. data/std/cookie.mt +198 -0
  77. data/std/counter.mt +160 -0
  78. data/std/crypto.mt +74 -0
  79. data/std/cstring.mt +13 -0
  80. data/std/ctype.mt +52 -0
  81. data/std/curl/runtime.mt +261 -0
  82. data/std/curl.mt +38 -0
  83. data/std/deque.mt +348 -0
  84. data/std/encoding.mt +93 -0
  85. data/std/enet.mt +133 -0
  86. data/std/env.mt +41 -0
  87. data/std/errno.mt +47 -0
  88. data/std/flecs.mt +978 -0
  89. data/std/fmt.mt +271 -0
  90. data/std/fs.linux.mt +696 -0
  91. data/std/fs.windows.mt +711 -0
  92. data/std/fsm.mt +267 -0
  93. data/std/gl.mt +2062 -0
  94. data/std/glfw.mt +471 -0
  95. data/std/goap.mt +342 -0
  96. data/std/graph.mt +521 -0
  97. data/std/gzip.mt +77 -0
  98. data/std/hash.mt +429 -0
  99. data/std/http/server.mt +810 -0
  100. data/std/http.mt +1227 -0
  101. data/std/intern.mt +53 -0
  102. data/std/jobs.mt +288 -0
  103. data/std/json.mt +627 -0
  104. data/std/libc.mt +34 -0
  105. data/std/libuv.mt +554 -0
  106. data/std/linear_algebra.mt +243 -0
  107. data/std/linked_map.mt +372 -0
  108. data/std/linked_map_view.mt +49 -0
  109. data/std/linked_set.mt +117 -0
  110. data/std/log.mt +69 -0
  111. data/std/map.mt +418 -0
  112. data/std/math.mt +24 -0
  113. data/std/mem/arena.mt +137 -0
  114. data/std/mem/endian.mt +51 -0
  115. data/std/mem/heap.mt +298 -0
  116. data/std/mem/pool.mt +164 -0
  117. data/std/mem/stack.mt +47 -0
  118. data/std/mem/tracking.mt +119 -0
  119. data/std/miniaudio.mt +1299 -0
  120. data/std/multiset.mt +191 -0
  121. data/std/net/channel.mt +727 -0
  122. data/std/net/clock.mt +237 -0
  123. data/std/net/discovery.mt +277 -0
  124. data/std/net/lobby.mt +813 -0
  125. data/std/net/manager.mt +539 -0
  126. data/std/net/mux.mt +839 -0
  127. data/std/net/nat.mt +122 -0
  128. data/std/net/packet.mt +219 -0
  129. data/std/net/punch.mt +162 -0
  130. data/std/net/rpc.mt +119 -0
  131. data/std/net/session.mt +1157 -0
  132. data/std/net/stun.mt +252 -0
  133. data/std/net/sync.mt +183 -0
  134. data/std/net/turn.mt +459 -0
  135. data/std/net.mt +2944 -0
  136. data/std/oauth2.mt +408 -0
  137. data/std/option.mt +51 -0
  138. data/std/ordered_map.mt +497 -0
  139. data/std/ordered_set.mt +348 -0
  140. data/std/path.mt +368 -0
  141. data/std/pcre2/runtime.mt +35 -0
  142. data/std/pcre2.mt +78 -0
  143. data/std/priority_queue.mt +55 -0
  144. data/std/process.mt +837 -0
  145. data/std/queue.mt +55 -0
  146. data/std/random.mt +146 -0
  147. data/std/raygui.mt +99 -0
  148. data/std/raylib/debug_console.mt +71 -0
  149. data/std/raylib/easing.mt +388 -0
  150. data/std/raylib/packed_assets.mt +255 -0
  151. data/std/raylib/runtime.mt +30 -0
  152. data/std/raylib/tracy_gpu.mt +37 -0
  153. data/std/raylib.mt +1510 -0
  154. data/std/raymath.mt +153 -0
  155. data/std/result.mt +89 -0
  156. data/std/rlgl.mt +268 -0
  157. data/std/rpng.mt +46 -0
  158. data/std/rres.mt +36 -0
  159. data/std/sdl3/runtime.mt +54 -0
  160. data/std/sdl3.mt +1731 -0
  161. data/std/serialize.mt +68 -0
  162. data/std/set.mt +124 -0
  163. data/std/spatial.mt +176 -0
  164. data/std/sqlite3.mt +151 -0
  165. data/std/stack.mt +55 -0
  166. data/std/stb_image.mt +47 -0
  167. data/std/stb_image_resize2.mt +41 -0
  168. data/std/stb_image_write.mt +17 -0
  169. data/std/stb_rect_pack.mt +15 -0
  170. data/std/stb_truetype.mt +77 -0
  171. data/std/stb_vorbis.mt +16 -0
  172. data/std/stdio.mt +88 -0
  173. data/std/steamworks.mt +1542 -0
  174. data/std/str.mt +293 -0
  175. data/std/string.mt +234 -0
  176. data/std/sync.mt +194 -0
  177. data/std/tar.mt +704 -0
  178. data/std/terminal.mt +1002 -0
  179. data/std/testing.mt +266 -0
  180. data/std/thread.mt +120 -0
  181. data/std/time.mt +105 -0
  182. data/std/tls.mt +616 -0
  183. data/std/toml.mt +1310 -0
  184. data/std/tracy.mt +42 -0
  185. data/std/uri.mt +118 -0
  186. data/std/url.mt +372 -0
  187. data/std/vec.mt +433 -0
  188. data/std/zstd.mt +94 -0
  189. metadata +187 -2
@@ -0,0 +1,1157 @@
1
+ import std.async as aio
2
+ import std.binary as bin
3
+ import std.bytes as bytes
4
+ import std.crypto as crypto
5
+ import std.deque as deque
6
+ import std.net as net
7
+ import std.net.channel as chan
8
+ import std.string as string
9
+ import std.vec as vec
10
+
11
+ const msg_type_user: ubyte = 0x00
12
+ const msg_type_connect_request: ubyte = 0x01
13
+ const msg_type_connect_accept: ubyte = 0x02
14
+ const msg_type_connect_reject: ubyte = 0x03
15
+ const msg_type_heartbeat: ubyte = 0x04
16
+ const msg_type_heartbeat_ack: ubyte = 0x05
17
+ const msg_type_disconnect: ubyte = 0x06
18
+
19
+ const reject_reason_version: ubyte = 1
20
+ const reject_reason_full: ubyte = 2
21
+ const reject_reason_refused: ubyte = 3
22
+ const disconnect_reason_local: ubyte = 1
23
+ const disconnect_reason_timeout: ubyte = 2
24
+ const disconnect_reason_remote: ubyte = 3
25
+
26
+ const connect_request_payload_bytes: ptr_uint = 12
27
+ const connect_accept_payload_bytes: ptr_uint = 4
28
+ const heartbeat_payload_bytes: ptr_uint = 4
29
+
30
+ type ChanMessageTask = Task[Result[Option[chan.Message], net.Error]]
31
+ type ChanHostMessageTask = Task[Result[Option[chan.HostMessage], net.Error]]
32
+
33
+ public enum ConnectionState: int
34
+ disconnected = 0
35
+ connecting = 1
36
+ connected = 2
37
+
38
+ public struct Config:
39
+ max_payload_bytes: ptr_uint
40
+ protocol_version: uint
41
+ heartbeat_interval: uint
42
+ heartbeat_timeout: uint
43
+ resend_after_frames: uint
44
+ max_pending_reliable: ptr_uint
45
+
46
+ public enum PeerEventKind: ubyte
47
+ user_data = 0
48
+ peer_joined = 1
49
+ peer_left = 2
50
+
51
+ public struct PeerEvent:
52
+ kind: PeerEventKind
53
+ peer_id: uint
54
+ payload: bytes.Bytes
55
+ reliable: bool
56
+ reason: ubyte
57
+
58
+ public struct Connection:
59
+ channel: chan.Channel
60
+ state: ConnectionState
61
+ protocol_version: uint
62
+ heartbeat_interval: uint
63
+ heartbeat_timeout: uint
64
+ frame_since_last_recv: uint
65
+ ping_rtt_frames: uint
66
+ last_heartbeat_sent: uint
67
+ pending_recv: Option[ChanMessageTask]
68
+ event_queue: deque.Deque[PeerEvent]
69
+ outgoing: deque.Deque[OutgoingMessage]
70
+
71
+ public struct PeerConnection:
72
+ peer_id: uint
73
+ channel_state: ConnectionState
74
+ frame_since_last_recv: uint
75
+ last_heartbeat_sent: uint
76
+ heartbeat_ack_received: bool
77
+
78
+ public struct Session:
79
+ host: chan.Host
80
+ config: Config
81
+ next_peer_id: uint
82
+ peers: vec.Vec[PeerConnection]
83
+ pending_recv: Option[ChanHostMessageTask]
84
+ event_queue: deque.Deque[PeerEvent]
85
+ outgoing: deque.Deque[OutgoingMessage]
86
+
87
+ struct OutgoingMessage:
88
+ address: net.SocketAddress
89
+ payload: bytes.Bytes
90
+ reliable: bool
91
+
92
+
93
+ extending PeerEvent:
94
+ public editable function release() -> void:
95
+ if this.kind == PeerEventKind.user_data:
96
+ this.payload.release()
97
+
98
+
99
+ function build_connect_request(version: uint, key: ulong) -> bytes.Bytes:
100
+ var w = bin.Writer.with_capacity(1 + connect_request_payload_bytes)
101
+ w.write_ubyte(msg_type_connect_request)
102
+ w.write_uint(version)
103
+ w.write_ulong(key)
104
+ return w.finish()
105
+
106
+
107
+ function build_connect_accept(peer_id: uint) -> bytes.Bytes:
108
+ var w = bin.Writer.with_capacity(1 + connect_accept_payload_bytes)
109
+ w.write_ubyte(msg_type_connect_accept)
110
+ w.write_uint(peer_id)
111
+ return w.finish()
112
+
113
+
114
+ function build_connect_reject(reason: ubyte) -> bytes.Bytes:
115
+ var w = bin.Writer.with_capacity(2)
116
+ w.write_ubyte(msg_type_connect_reject)
117
+ w.write_ubyte(reason)
118
+ return w.finish()
119
+
120
+
121
+ function build_heartbeat(frame: uint) -> bytes.Bytes:
122
+ var w = bin.Writer.with_capacity(1 + heartbeat_payload_bytes)
123
+ w.write_ubyte(msg_type_heartbeat)
124
+ w.write_uint(frame)
125
+ return w.finish()
126
+
127
+
128
+ function build_heartbeat_ack(frame: uint) -> bytes.Bytes:
129
+ var w = bin.Writer.with_capacity(1 + heartbeat_payload_bytes)
130
+ w.write_ubyte(msg_type_heartbeat_ack)
131
+ w.write_uint(frame)
132
+ return w.finish()
133
+
134
+
135
+ function build_disconnect(reason: ubyte) -> bytes.Bytes:
136
+ var w = bin.Writer.with_capacity(2)
137
+ w.write_ubyte(msg_type_disconnect)
138
+ w.write_ubyte(reason)
139
+ return w.finish()
140
+
141
+
142
+ function build_user_data(payload: span[ubyte]) -> bytes.Bytes:
143
+ var w = bin.Writer.with_capacity(1 + payload.len)
144
+ w.write_ubyte(msg_type_user)
145
+ w.write_bytes(payload)
146
+ return w.finish()
147
+
148
+
149
+ function generate_handshake_key() -> Result[ulong, net.Error]:
150
+ let key_result = crypto.random_bytes(8)
151
+ match key_result:
152
+ Result.failure as p:
153
+ return Result[ulong, net.Error].failure(error = net.Error(code = -1, message = p.error.message))
154
+ Result.success as payload:
155
+ var rand = payload.value
156
+ var reader = bin.reader(rand.as_span())
157
+ match reader.read_ulong():
158
+ Result.failure as rp:
159
+ rand.release()
160
+ return Result[ulong, net.Error].failure(error = net.Error(
161
+ code = rp.error.code,
162
+ message = rp.error.message
163
+ ))
164
+ Result.success as read_payload:
165
+ let value = read_payload.value
166
+ rand.release()
167
+ return Result[ulong, net.Error].success(value = value)
168
+
169
+
170
+ function decode_u32_at(data: span[ubyte], offset: ptr_uint) -> uint:
171
+ unsafe:
172
+ return uint<-read(data.data + offset) | (uint<-read(data.data + offset + 1) << 8) | (uint<-read(data.data + offset + 2) << 16) | (uint<-read(data.data + offset + 3) << 24)
173
+
174
+
175
+ function channel_config_for(config: Config) -> chan.Config:
176
+ return chan.Config(
177
+ max_payload_bytes = config.max_payload_bytes + 1,
178
+ max_pending_reliable = config.max_pending_reliable,
179
+ resend_after_frames = config.resend_after_frames
180
+ )
181
+
182
+
183
+ extending Config:
184
+ public static function default(max_payload_bytes: ptr_uint) -> Config:
185
+ return Config(
186
+ max_payload_bytes = max_payload_bytes,
187
+ protocol_version = 1,
188
+ heartbeat_interval = 60,
189
+ heartbeat_timeout = 300,
190
+ resend_after_frames = 5,
191
+ max_pending_reliable = 32
192
+ )
193
+
194
+
195
+ public function connect_on(
196
+ runtime: aio.Runtime,
197
+ local_address: net.SocketAddress,
198
+ remote_address: net.SocketAddress,
199
+ config: Config
200
+ ) -> Result[Connection, net.Error]:
201
+ let channel_config = channel_config_for(config)
202
+ let channel_result = chan.connect_on(runtime, local_address, remote_address, channel_config)
203
+ match channel_result:
204
+ Result.failure as payload:
205
+ return Result[Connection, net.Error].failure(error = net.Error(
206
+ code = payload.error.code,
207
+ message = payload.error.message
208
+ ))
209
+ Result.success as payload:
210
+ let conn = Connection(
211
+ channel = payload.value,
212
+ state = ConnectionState.disconnected,
213
+ protocol_version = config.protocol_version,
214
+ heartbeat_interval = config.heartbeat_interval,
215
+ heartbeat_timeout = config.heartbeat_timeout,
216
+ frame_since_last_recv = 0,
217
+ ping_rtt_frames = 0,
218
+ last_heartbeat_sent = 0,
219
+ pending_recv = Option[ChanMessageTask].none,
220
+ event_queue = deque.Deque[PeerEvent].create(),
221
+ outgoing = deque.Deque[OutgoingMessage].create()
222
+ )
223
+ return Result[Connection, net.Error].success(value = conn)
224
+
225
+
226
+ public async function connect(
227
+ local_address: net.SocketAddress,
228
+ remote_address: net.SocketAddress,
229
+ config: Config
230
+ ) -> Result[Connection, net.Error]:
231
+ match connect_on(aio.current_runtime(), local_address, remote_address, config):
232
+ Result.failure as p:
233
+ return Result[Connection, net.Error].failure(error = p.error)
234
+ Result.success as p:
235
+ var conn = p.value
236
+ match await conn.connect_to_peer():
237
+ Result.failure as cp:
238
+ conn.release()
239
+ return Result[Connection, net.Error].failure(error = cp.error)
240
+ Result.success:
241
+ return Result[Connection, net.Error].success(value = conn)
242
+
243
+
244
+ public function listen_on(
245
+ runtime: aio.Runtime,
246
+ local_address: net.SocketAddress,
247
+ config: Config
248
+ ) -> Result[Session, net.Error]:
249
+ let channel_config = channel_config_for(config)
250
+ let channel_result = chan.listen_on(runtime, local_address, channel_config)
251
+ match channel_result:
252
+ Result.failure as payload:
253
+ return Result[Session, net.Error].failure(error = net.Error(
254
+ code = payload.error.code,
255
+ message = payload.error.message
256
+ ))
257
+ Result.success as payload:
258
+ let session = Session(
259
+ host = payload.value,
260
+ config = config,
261
+ next_peer_id = 1,
262
+ peers = vec.Vec[PeerConnection].create(),
263
+ pending_recv = Option[ChanHostMessageTask].none,
264
+ event_queue = deque.Deque[PeerEvent].create(),
265
+ outgoing = deque.Deque[OutgoingMessage].create()
266
+ )
267
+ return Result[Session, net.Error].success(value = session)
268
+
269
+
270
+ public function listen(local_address: net.SocketAddress, config: Config) -> Result[Session, net.Error]:
271
+ return listen_on(aio.current_runtime(), local_address, config)
272
+
273
+
274
+ extending Connection:
275
+ public editable function release() -> void:
276
+ if this.pending_recv.is_some():
277
+ let task = this.pending_recv.unwrap()
278
+ let raw_frame = unsafe: reinterpret[ptr_int](task.frame)
279
+ if raw_frame != 0:
280
+ task.release(task.frame)
281
+ this.pending_recv = Option[ChanMessageTask].none
282
+ drain_release_outgoing_conn(ref_of(this))
283
+ this.outgoing.release()
284
+ drain_release_events(ref_of(this.event_queue))
285
+ this.event_queue.release()
286
+ this.channel.release()
287
+
288
+
289
+ public function state() -> ConnectionState:
290
+ return this.state
291
+
292
+
293
+ public function local_address() -> Result[net.SocketAddress, net.Error]:
294
+ return this.channel.local_address()
295
+
296
+
297
+ public function peer_address() -> Result[net.SocketAddress, net.Error]:
298
+ return this.channel.peer_address()
299
+
300
+
301
+ public function ping_rtt_frames() -> uint:
302
+ return this.ping_rtt_frames
303
+
304
+
305
+ public editable function start_recv() -> void:
306
+ start_recv_if_idle(ref_of(this))
307
+
308
+
309
+ public async editable function tick(frame: uint) -> Result[bool, net.Error]:
310
+ start_recv_if_idle(ref_of(this))
311
+
312
+ if this.state == ConnectionState.connected:
313
+ if frame >= this.last_heartbeat_sent + this.heartbeat_interval:
314
+ var hb = build_heartbeat(frame)
315
+ defer hb.release()
316
+ let send_result = await this.channel.send(hb.as_span())
317
+ match send_result:
318
+ Result.failure:
319
+ pass
320
+ Result.success:
321
+ pass
322
+ this.last_heartbeat_sent = frame
323
+
324
+ this.frame_since_last_recv += 1
325
+ if this.frame_since_last_recv >= this.heartbeat_timeout:
326
+ this.state = ConnectionState.disconnected
327
+
328
+ let channel_tick_result = await this.channel.tick(frame)
329
+ match channel_tick_result:
330
+ Result.failure:
331
+ pass
332
+ Result.success:
333
+ pass
334
+
335
+ await aio.sleep(1)
336
+
337
+ process_pending_recv_conn(ref_of(this))
338
+ await drain_outgoing_conn(ref_of(this))
339
+
340
+ return Result[bool, net.Error].success(value = this.state == ConnectionState.connected)
341
+
342
+
343
+ public editable function try_recv() -> Option[PeerEvent]:
344
+ return this.event_queue.pop_front()
345
+
346
+
347
+ public async editable function recv() -> Result[Option[PeerEvent], net.Error]:
348
+ while true:
349
+ let ev = this.try_recv()
350
+ match ev:
351
+ Option.some as payload:
352
+ return Result[Option[PeerEvent], net.Error].success(
353
+ value = Option[PeerEvent].some(value = payload.value)
354
+ )
355
+ Option.none:
356
+ process_pending_recv_conn(ref_of(this))
357
+ await drain_outgoing_conn(ref_of(this))
358
+ let ready = this.try_recv()
359
+ match ready:
360
+ Option.some as ready_payload:
361
+ return Result[Option[PeerEvent], net.Error].success(
362
+ value = Option[PeerEvent].some(value = ready_payload.value)
363
+ )
364
+ Option.none:
365
+ let recv_result = await this.channel.recv()
366
+ match recv_result:
367
+ Result.failure as payload:
368
+ return Result[Option[PeerEvent], net.Error].failure(
369
+ error = net.Error(code = payload.error.code, message = payload.error.message)
370
+ )
371
+ Result.success as recv_payload:
372
+ let msg_opt = recv_payload.value
373
+ match msg_opt:
374
+ Option.none:
375
+ pass
376
+ Option.some as msg_payload:
377
+ var msg = msg_payload.value
378
+ handle_incoming_conn(ref_of(this), ref_of(msg))
379
+ await drain_outgoing_conn(ref_of(this))
380
+ let ev2 = this.try_recv()
381
+ match ev2:
382
+ Option.some as p2:
383
+ return Result[Option[PeerEvent], net.Error].success(
384
+ value = Option[PeerEvent].some(value = p2.value)
385
+ )
386
+ Option.none:
387
+ pass
388
+
389
+
390
+ public async editable function send(data: span[ubyte]) -> Result[bool, net.Error]:
391
+ if this.state != ConnectionState.connected:
392
+ return Result[bool, net.Error].failure(error = net.Error(
393
+ code = -2,
394
+ message = string.String.from_str("session not connected")
395
+ ))
396
+
397
+ var framed = build_user_data(data)
398
+ defer framed.release()
399
+ let send_result = await this.channel.send(framed.as_span())
400
+ match send_result:
401
+ Result.failure as payload:
402
+ return Result[bool, net.Error].failure(error = net.Error(
403
+ code = payload.error.code,
404
+ message = payload.error.message
405
+ ))
406
+ Result.success:
407
+ return Result[bool, net.Error].success(value = true)
408
+
409
+
410
+ public async editable function send_reliable(data: span[ubyte], frame: uint) -> Result[bool, net.Error]:
411
+ if this.state != ConnectionState.connected:
412
+ return Result[bool, net.Error].failure(error = net.Error(
413
+ code = -2,
414
+ message = string.String.from_str("session not connected")
415
+ ))
416
+
417
+ var framed = build_user_data(data)
418
+ defer framed.release()
419
+ let send_result = await this.channel.send_reliable(framed.as_span(), frame)
420
+ match send_result:
421
+ Result.failure as payload:
422
+ return Result[bool, net.Error].failure(error = net.Error(
423
+ code = payload.error.code,
424
+ message = payload.error.message
425
+ ))
426
+ Result.success:
427
+ return Result[bool, net.Error].success(value = true)
428
+
429
+
430
+ public async editable function connect_to_peer() -> Result[bool, net.Error]:
431
+ if this.state != ConnectionState.disconnected:
432
+ return Result[bool, net.Error].failure(error = net.Error(
433
+ code = -3,
434
+ message = string.String.from_str("session already connected or connecting")
435
+ ))
436
+
437
+ this.state = ConnectionState.connecting
438
+
439
+ var key: ulong = 0
440
+ match generate_handshake_key():
441
+ Result.failure as kp:
442
+ this.state = ConnectionState.disconnected
443
+ return Result[bool, net.Error].failure(error = kp.error)
444
+ Result.success as ksp:
445
+ key = ksp.value
446
+ var req = build_connect_request(this.protocol_version, key)
447
+ defer req.release()
448
+ let send_result = await this.channel.send_reliable(req.as_span(), this.last_heartbeat_sent)
449
+ match send_result:
450
+ Result.failure as send_payload:
451
+ this.state = ConnectionState.disconnected
452
+ return Result[bool, net.Error].failure(error = send_payload.error)
453
+ Result.success:
454
+ this.frame_since_last_recv = 0
455
+ return Result[bool, net.Error].success(value = true)
456
+
457
+
458
+ public async editable function disconnect_peer() -> Result[bool, net.Error]:
459
+ if this.state != ConnectionState.connected:
460
+ return Result[bool, net.Error].failure(error = net.Error(
461
+ code = -4,
462
+ message = string.String.from_str("session not connected")
463
+ ))
464
+
465
+ var d = build_disconnect(disconnect_reason_local)
466
+ defer d.release()
467
+ let send_result = await this.channel.send_reliable(d.as_span(), 0)
468
+ this.state = ConnectionState.disconnected
469
+ match send_result:
470
+ Result.failure:
471
+ return Result[bool, net.Error].success(value = true)
472
+ Result.success:
473
+ return Result[bool, net.Error].success(value = true)
474
+
475
+
476
+ function start_recv_if_idle(conn: ref[Connection]) -> void:
477
+ match conn.pending_recv:
478
+ Option.some:
479
+ return
480
+ Option.none:
481
+ conn.pending_recv = Option[ChanMessageTask].some(
482
+ value = conn.channel.recv()
483
+ )
484
+
485
+
486
+ function process_pending_recv_conn(conn: ref[Connection]) -> void:
487
+ match conn.pending_recv:
488
+ Option.none:
489
+ return
490
+ Option.some as task_opt:
491
+ let task = task_opt.value
492
+ if not aio.completed(task):
493
+ return
494
+ let result = aio.result(task)
495
+ conn.pending_recv = Option[ChanMessageTask].none
496
+ start_recv_if_idle(conn)
497
+ match result:
498
+ Result.failure:
499
+ return
500
+ Result.success as result_payload:
501
+ let msg_opt = result_payload.value
502
+ match msg_opt:
503
+ Option.none:
504
+ pass
505
+ Option.some as msg_payload:
506
+ var msg = msg_payload.value
507
+ handle_incoming_conn(conn, ref_of(msg))
508
+
509
+
510
+ function handle_incoming_conn(conn: ref[Connection], msg: ref[chan.Message]) -> void:
511
+ let span = msg.payload.as_span()
512
+ if span.len == 0:
513
+ msg.release()
514
+ return
515
+
516
+ let tag = unsafe: read(span.data)
517
+
518
+ if tag == msg_type_user:
519
+ conn.frame_since_last_recv = 0
520
+ let payload_len = span.len - 1
521
+ var payload = bytes.Bytes.empty()
522
+ if payload_len > 0:
523
+ unsafe:
524
+ payload = bytes.Bytes.copy(span[ubyte](data = span.data + 1, len = payload_len))
525
+ conn.event_queue.push_back(PeerEvent(
526
+ kind = PeerEventKind.user_data,
527
+ peer_id = 0,
528
+ payload = payload,
529
+ reliable = msg.reliable,
530
+ reason = 0
531
+ ))
532
+ msg.release()
533
+ return
534
+
535
+ if tag == msg_type_heartbeat:
536
+ conn.frame_since_last_recv = 0
537
+ let hb_span = unsafe: span[ubyte](data = span.data + 1, len = span.len - 1)
538
+ if hb_span.len >= 4:
539
+ let echoed = decode_u32_at(hb_span, 0)
540
+ var ack = build_heartbeat_ack(echoed)
541
+ let peer_addr_result = conn.channel.peer_address()
542
+ match peer_addr_result:
543
+ Result.success as peer_addr:
544
+ conn.outgoing.push_back(OutgoingMessage(
545
+ address = peer_addr.value,
546
+ payload = ack,
547
+ reliable = false
548
+ ))
549
+ Result.failure:
550
+ ack.release()
551
+ msg.release()
552
+ return
553
+
554
+ if tag == msg_type_heartbeat_ack:
555
+ conn.frame_since_last_recv = 0
556
+ let echo_span = unsafe: span[ubyte](data = span.data + 1, len = span.len - 1)
557
+ if echo_span.len >= 4:
558
+ let echoed = decode_u32_at(echo_span, 0)
559
+ if conn.last_heartbeat_sent > echoed:
560
+ conn.ping_rtt_frames = conn.last_heartbeat_sent - echoed
561
+ msg.release()
562
+ return
563
+
564
+ if tag == msg_type_connect_accept:
565
+ conn.frame_since_last_recv = 0
566
+ conn.state = ConnectionState.connected
567
+ msg.release()
568
+ return
569
+
570
+ if tag == msg_type_connect_reject:
571
+ conn.state = ConnectionState.disconnected
572
+ msg.release()
573
+ return
574
+
575
+ if tag == msg_type_disconnect:
576
+ conn.state = ConnectionState.disconnected
577
+ msg.release()
578
+ return
579
+
580
+ msg.release()
581
+
582
+
583
+ async function drain_outgoing_conn(conn: ref[Connection]) -> Result[bool, net.Error]:
584
+ while true:
585
+ let msg = conn.outgoing.pop_front()
586
+ match msg:
587
+ Option.none:
588
+ return Result[bool, net.Error].success(value = true)
589
+ Option.some as payload:
590
+ var outgoing = payload.value
591
+ defer outgoing.release()
592
+ if outgoing.reliable:
593
+ let _ = await conn.channel.send_reliable(
594
+ outgoing.payload.as_span(),
595
+ 0
596
+ )
597
+ else:
598
+ let _ = await conn.channel.send(
599
+ outgoing.payload.as_span()
600
+ )
601
+
602
+
603
+ extending OutgoingMessage:
604
+ public editable function release() -> void:
605
+ this.address.release()
606
+ this.payload.release()
607
+
608
+
609
+ extending Session:
610
+ public editable function release() -> void:
611
+ match this.pending_recv:
612
+ Option.some as task_opt:
613
+ let task = task_opt.value
614
+ let raw_frame = unsafe: reinterpret[ptr_int](task.frame)
615
+ if raw_frame != 0:
616
+ task.release(task.frame)
617
+ Option.none:
618
+ pass
619
+ this.pending_recv = Option[ChanHostMessageTask].none
620
+ drain_release_outgoing(ref_of(this))
621
+ this.outgoing.release()
622
+ drain_release_events(ref_of(this.event_queue))
623
+ this.event_queue.release()
624
+ this.peers.release()
625
+ this.host.release()
626
+
627
+
628
+ public function local_address() -> Result[net.SocketAddress, net.Error]:
629
+ return this.host.local_address()
630
+
631
+
632
+ public function peer_count() -> ptr_uint:
633
+ return this.peers.len()
634
+
635
+
636
+ public editable function start_recv() -> void:
637
+ start_recv_if_idle_session(ref_of(this))
638
+
639
+
640
+ public async editable function tick(frame: uint) -> Result[bool, net.Error]:
641
+ start_recv_if_idle_session(ref_of(this))
642
+
643
+ var peer_index: ptr_uint = 0
644
+ while peer_index < this.peers.len():
645
+ let peer_ptr = this.peers.get(peer_index) else:
646
+ fatal(c"session peer missing storage")
647
+
648
+ if unsafe: read(peer_ptr).channel_state == ConnectionState.connected:
649
+ if frame >= unsafe: read(peer_ptr).last_heartbeat_sent + this.config.heartbeat_interval:
650
+ var hb = build_heartbeat(frame)
651
+ defer hb.release()
652
+ let peer_id = unsafe: read(peer_ptr).peer_id
653
+ let peer_address_result = find_peer_address(ref_of(this), peer_id)
654
+ match peer_address_result:
655
+ Result.success as addr_payload:
656
+ var addr = addr_payload.value
657
+ defer addr.release()
658
+ let send_result = await this.host.send(addr, hb.as_span())
659
+ match send_result:
660
+ Result.failure:
661
+ pass
662
+ Result.success:
663
+ pass
664
+ Result.failure:
665
+ pass
666
+ unsafe: read(peer_ptr).last_heartbeat_sent = frame
667
+
668
+ unsafe: read(peer_ptr).frame_since_last_recv += 1
669
+ if unsafe: read(peer_ptr).frame_since_last_recv >= this.config.heartbeat_timeout:
670
+ unsafe: read(peer_ptr).channel_state = ConnectionState.disconnected
671
+ this.event_queue.push_back(PeerEvent(
672
+ kind = PeerEventKind.peer_left,
673
+ peer_id = unsafe: read(peer_ptr).peer_id,
674
+ payload = bytes.Bytes.empty(),
675
+ reliable = false,
676
+ reason = disconnect_reason_timeout
677
+ ))
678
+
679
+ peer_index += 1
680
+
681
+ let host_tick_result = await this.host.tick(frame)
682
+ match host_tick_result:
683
+ Result.failure:
684
+ pass
685
+ Result.success:
686
+ pass
687
+
688
+ await aio.sleep(1)
689
+
690
+ process_pending_recv_session(ref_of(this))
691
+ await drain_outgoing_session(ref_of(this))
692
+
693
+ let connected_count = connected_peer_count(ref_of(this))
694
+ return Result[bool, net.Error].success(value = connected_count > 0)
695
+
696
+
697
+ public editable function try_recv() -> Option[PeerEvent]:
698
+ return this.event_queue.pop_front()
699
+
700
+
701
+ public async editable function recv() -> Result[Option[PeerEvent], net.Error]:
702
+ while true:
703
+ let ev = this.try_recv()
704
+ match ev:
705
+ Option.some as payload:
706
+ return Result[Option[PeerEvent], net.Error].success(
707
+ value = Option[PeerEvent].some(value = payload.value)
708
+ )
709
+ Option.none:
710
+ process_pending_recv_session(ref_of(this))
711
+ await drain_outgoing_session(ref_of(this))
712
+ let ready = this.try_recv()
713
+ match ready:
714
+ Option.some as ready_payload:
715
+ return Result[Option[PeerEvent], net.Error].success(
716
+ value = Option[PeerEvent].some(value = ready_payload.value)
717
+ )
718
+ Option.none:
719
+ let recv_result = await this.host.recv()
720
+ match recv_result:
721
+ Result.failure as payload:
722
+ return Result[Option[PeerEvent], net.Error].failure(
723
+ error = net.Error(code = payload.error.code, message = payload.error.message)
724
+ )
725
+ Result.success as recv_payload:
726
+ let msg_opt = recv_payload.value
727
+ match msg_opt:
728
+ Option.none:
729
+ pass
730
+ Option.some as msg_payload:
731
+ var msg = msg_payload.value
732
+ handle_incoming_session(ref_of(this), ref_of(msg))
733
+ await drain_outgoing_session(ref_of(this))
734
+ let ev2 = this.try_recv()
735
+ match ev2:
736
+ Option.some as p2:
737
+ return Result[Option[PeerEvent], net.Error].success(
738
+ value = Option[PeerEvent].some(value = p2.value)
739
+ )
740
+ Option.none:
741
+ pass
742
+
743
+
744
+ public async editable function send(peer_id: uint, data: span[ubyte]) -> Result[bool, net.Error]:
745
+ let peer_address_result = find_peer_address(ref_of(this), peer_id)
746
+ match peer_address_result:
747
+ Result.failure as payload:
748
+ return Result[bool, net.Error].failure(error = payload.error)
749
+ Result.success as payload:
750
+ var address = payload.value
751
+ defer address.release()
752
+ var framed = build_user_data(data)
753
+ defer framed.release()
754
+ let send_result = await this.host.send(address, framed.as_span())
755
+ match send_result:
756
+ Result.failure as send_payload:
757
+ return Result[bool, net.Error].failure(error = net.Error(
758
+ code = send_payload.error.code,
759
+ message = send_payload.error.message
760
+ ))
761
+ Result.success:
762
+ return Result[bool, net.Error].success(value = true)
763
+
764
+
765
+ public async editable function send_reliable(
766
+ peer_id: uint,
767
+ data: span[ubyte],
768
+ frame: uint
769
+ ) -> Result[bool, net.Error]:
770
+ let peer_address_result = find_peer_address(ref_of(this), peer_id)
771
+ match peer_address_result:
772
+ Result.failure as payload:
773
+ return Result[bool, net.Error].failure(error = payload.error)
774
+ Result.success as payload:
775
+ var address = payload.value
776
+ defer address.release()
777
+ var framed = build_user_data(data)
778
+ defer framed.release()
779
+ let send_result = await this.host.send_reliable(address, framed.as_span(), frame)
780
+ match send_result:
781
+ Result.failure as send_payload:
782
+ return Result[bool, net.Error].failure(error = net.Error(
783
+ code = send_payload.error.code,
784
+ message = send_payload.error.message
785
+ ))
786
+ Result.success:
787
+ return Result[bool, net.Error].success(value = true)
788
+
789
+
790
+ public async editable function kick(peer_id: uint, reason: ubyte) -> Result[bool, net.Error]:
791
+ let peer_address_result = find_peer_address(ref_of(this), peer_id)
792
+ match peer_address_result:
793
+ Result.failure as payload:
794
+ return Result[bool, net.Error].failure(error = payload.error)
795
+ Result.success as payload:
796
+ var address = payload.value
797
+ defer address.release()
798
+ var d = build_disconnect(reason)
799
+ defer d.release()
800
+ let send_result = await this.host.send_reliable(address, d.as_span(), 0)
801
+ match send_result:
802
+ Result.failure:
803
+ pass
804
+ Result.success:
805
+ pass
806
+ mark_peer_disconnected(ref_of(this), peer_id)
807
+ this.event_queue.push_back(PeerEvent(
808
+ kind = PeerEventKind.peer_left,
809
+ peer_id = peer_id,
810
+ reason = reason
811
+ ))
812
+ return Result[bool, net.Error].success(value = true)
813
+
814
+
815
+ function find_peer_address(session: ref[Session], peer_id: uint) -> Result[net.SocketAddress, net.Error]:
816
+ var peer_index: ptr_uint = 0
817
+ while peer_index < session.peers.len():
818
+ let peer_ptr = session.peers.get(peer_index) else:
819
+ fatal(c"session peer missing storage in address lookup")
820
+
821
+ if unsafe: read(peer_ptr).peer_id == peer_id:
822
+ var host_peer_index: ptr_uint = 0
823
+ let host_peers = session.host.peers
824
+ while host_peer_index < host_peers.len():
825
+ let host_peer_ptr = host_peers.get(host_peer_index) else:
826
+ fatal(c"session host peer missing storage")
827
+ if host_peer_index == peer_index:
828
+ let copy_result = unsafe: read(host_peer_ptr).address.copy()
829
+ match copy_result:
830
+ Result.failure as copy_err:
831
+ let copy_message = copy_err.error.message.as_str()
832
+ return Result[net.SocketAddress, net.Error].failure(
833
+ error = net.Error(code = -5, message = string.String.from_str(copy_message))
834
+ )
835
+ Result.success as addr_payload:
836
+ return Result[net.SocketAddress, net.Error].success(value = addr_payload.value)
837
+ host_peer_index += 1
838
+ peer_index += 1
839
+
840
+ return Result[net.SocketAddress, net.Error].failure(error = net.Error(
841
+ code = -6,
842
+ message = string.String.from_str("session peer not found")
843
+ ))
844
+
845
+
846
+ function start_recv_if_idle_session(session: ref[Session]) -> void:
847
+ match session.pending_recv:
848
+ Option.some:
849
+ return
850
+ Option.none:
851
+ session.pending_recv = Option[ChanHostMessageTask].some(
852
+ value = session.host.recv()
853
+ )
854
+
855
+
856
+ function process_pending_recv_session(session: ref[Session]) -> void:
857
+ match session.pending_recv:
858
+ Option.none:
859
+ return
860
+ Option.some as task_opt:
861
+ let task = task_opt.value
862
+ if not aio.completed(task):
863
+ return
864
+ let result = aio.result(task)
865
+ session.pending_recv = Option[ChanHostMessageTask].none
866
+ start_recv_if_idle_session(session)
867
+ match result:
868
+ Result.failure:
869
+ return
870
+ Result.success as result_payload:
871
+ let msg_opt = result_payload.value
872
+ match msg_opt:
873
+ Option.none:
874
+ pass
875
+ Option.some as msg_payload:
876
+ var msg = msg_payload.value
877
+ handle_incoming_session(session, ref_of(msg))
878
+
879
+
880
+ function handle_incoming_session(session: ref[Session], msg: ref[chan.HostMessage]) -> void:
881
+ let span = msg.payload.as_span()
882
+ if span.len == 0:
883
+ msg.release()
884
+ return
885
+
886
+ let tag = unsafe: read(span.data)
887
+
888
+ if tag == msg_type_connect_request:
889
+ handle_connect_request(session, msg, span)
890
+ return
891
+
892
+ if tag == msg_type_user:
893
+ let peer_result = find_peer_by_address(session, msg.source)
894
+ match peer_result:
895
+ Result.failure:
896
+ msg.release()
897
+ return
898
+ Result.success as peer_payload:
899
+ let peer_id = peer_payload.value
900
+ update_peer_last_recv(session, peer_id)
901
+ let payload_len = span.len - 1
902
+ var payload = bytes.Bytes.empty()
903
+ if payload_len > 0:
904
+ unsafe:
905
+ payload = bytes.Bytes.copy(span[ubyte](data = span.data + 1, len = payload_len))
906
+ session.event_queue.push_back(PeerEvent(
907
+ kind = PeerEventKind.user_data,
908
+ peer_id = peer_id,
909
+ payload = payload,
910
+ reliable = msg.reliable,
911
+ reason = 0
912
+ ))
913
+ msg.release()
914
+ return
915
+
916
+ if tag == msg_type_heartbeat:
917
+ let peer_result = find_peer_by_address(session, msg.source)
918
+ match peer_result:
919
+ Result.success as peer_payload:
920
+ update_peer_last_recv(session, peer_payload.value)
921
+ let hb_span = unsafe: span[ubyte](data = span.data + 1, len = span.len - 1)
922
+ if hb_span.len >= 4:
923
+ let echoed = decode_u32_at(hb_span, 0)
924
+ var ack = build_heartbeat_ack(echoed)
925
+ let addr_result = msg.source.copy()
926
+ match addr_result:
927
+ Result.success as addr_payload:
928
+ session.outgoing.push_back(OutgoingMessage(
929
+ address = addr_payload.value,
930
+ payload = ack,
931
+ reliable = false
932
+ ))
933
+ Result.failure:
934
+ ack.release()
935
+ Result.failure:
936
+ pass
937
+ msg.release()
938
+ return
939
+
940
+ if tag == msg_type_heartbeat_ack:
941
+ let peer_result = find_peer_by_address(session, msg.source)
942
+ match peer_result:
943
+ Result.success as peer_payload:
944
+ update_peer_last_recv(session, peer_payload.value)
945
+ mark_peer_heartbeat_ack(session, peer_payload.value)
946
+ Result.failure:
947
+ pass
948
+ msg.release()
949
+ return
950
+
951
+ if tag == msg_type_disconnect:
952
+ let peer_result = find_peer_by_address(session, msg.source)
953
+ match peer_result:
954
+ Result.success as peer_payload:
955
+ let peer_id = peer_payload.value
956
+ mark_peer_disconnected(session, peer_id)
957
+ session.event_queue.push_back(PeerEvent(
958
+ kind = PeerEventKind.peer_left,
959
+ peer_id = peer_id,
960
+ reason = disconnect_reason_remote
961
+ ))
962
+ Result.failure:
963
+ pass
964
+ msg.release()
965
+ return
966
+
967
+ msg.release()
968
+
969
+
970
+ function handle_connect_request(session: ref[Session], msg: ref[chan.HostMessage], span: span[ubyte]) -> void:
971
+ let req_span = unsafe: span[ubyte](data = span.data + 1, len = span.len - 1)
972
+ if req_span.len < 4:
973
+ msg.release()
974
+ return
975
+
976
+ let client_version = decode_u32_at(req_span, 0)
977
+ if client_version != session.config.protocol_version:
978
+ var reject = build_connect_reject(reject_reason_version)
979
+ let addr_result = msg.source.copy()
980
+ match addr_result:
981
+ Result.success as addr_payload:
982
+ session.outgoing.push_back(OutgoingMessage(
983
+ address = addr_payload.value,
984
+ payload = reject,
985
+ reliable = true
986
+ ))
987
+ Result.failure:
988
+ reject.release()
989
+ msg.release()
990
+ return
991
+
992
+ let peer_id = session.next_peer_id
993
+ session.next_peer_id += 1
994
+
995
+ var accept = build_connect_accept(peer_id)
996
+ let addr_result = msg.source.copy()
997
+ match addr_result:
998
+ Result.success as addr_payload:
999
+ session.outgoing.push_back(OutgoingMessage(
1000
+ address = addr_payload.value,
1001
+ payload = accept,
1002
+ reliable = true
1003
+ ))
1004
+ Result.failure:
1005
+ accept.release()
1006
+ msg.release()
1007
+
1008
+ session.peers.push(PeerConnection(
1009
+ peer_id = peer_id,
1010
+ channel_state = ConnectionState.connected,
1011
+ frame_since_last_recv = 0,
1012
+ last_heartbeat_sent = 0,
1013
+ heartbeat_ack_received = false
1014
+ ))
1015
+
1016
+ session.event_queue.push_back(PeerEvent(
1017
+ kind = PeerEventKind.peer_joined,
1018
+ peer_id = peer_id
1019
+ ))
1020
+
1021
+
1022
+ function find_peer_by_address(session: ref[Session], address: net.SocketAddress) -> Result[uint, net.Error]:
1023
+ var index: ptr_uint = 0
1024
+ while index < session.host.peers.len():
1025
+ let host_peer_ptr = session.host.peers.get(index) else:
1026
+ fatal(c"session host peer missing storage")
1027
+
1028
+ let same_address = unsafe: read(host_peer_ptr).address.equal(address)
1029
+ if same_address:
1030
+ if index < session.peers.len():
1031
+ let session_peer_ptr = session.peers.get(index) else:
1032
+ return Result[uint, net.Error].failure(error = net.Error(
1033
+ code = -6,
1034
+ message = string.String.from_str("session peer not found")
1035
+ ))
1036
+ return Result[uint, net.Error].success(value = unsafe: read(session_peer_ptr).peer_id)
1037
+ return Result[uint, net.Error].failure(error = net.Error(
1038
+ code = -6,
1039
+ message = string.String.from_str("session peer not found")
1040
+ ))
1041
+ index += 1
1042
+
1043
+ return Result[uint, net.Error].failure(error = net.Error(
1044
+ code = -6,
1045
+ message = string.String.from_str("session peer not found")
1046
+ ))
1047
+
1048
+
1049
+ async function drain_outgoing_session(session: ref[Session]) -> Result[bool, net.Error]:
1050
+ while true:
1051
+ let msg = session.outgoing.pop_front()
1052
+ match msg:
1053
+ Option.none:
1054
+ return Result[bool, net.Error].success(value = true)
1055
+ Option.some as payload:
1056
+ var outgoing = payload.value
1057
+ defer outgoing.release()
1058
+ if outgoing.reliable:
1059
+ let send_result = await session.host.send_reliable(
1060
+ outgoing.address,
1061
+ outgoing.payload.as_span(),
1062
+ 0
1063
+ )
1064
+ match send_result:
1065
+ Result.failure:
1066
+ pass
1067
+ Result.success:
1068
+ pass
1069
+ else:
1070
+ let send_result = await session.host.send(
1071
+ outgoing.address,
1072
+ outgoing.payload.as_span()
1073
+ )
1074
+ match send_result:
1075
+ Result.failure:
1076
+ pass
1077
+ Result.success:
1078
+ pass
1079
+
1080
+
1081
+ function drain_release_outgoing(session: ref[Session]) -> void:
1082
+ while true:
1083
+ let msg = session.outgoing.pop_front()
1084
+ match msg:
1085
+ Option.none:
1086
+ break
1087
+ Option.some as payload:
1088
+ var outgoing = payload.value
1089
+ outgoing.release()
1090
+
1091
+
1092
+ function drain_release_outgoing_conn(conn: ref[Connection]) -> void:
1093
+ while true:
1094
+ let msg = conn.outgoing.pop_front()
1095
+ match msg:
1096
+ Option.none:
1097
+ break
1098
+ Option.some as payload:
1099
+ var outgoing = payload.value
1100
+ outgoing.release()
1101
+
1102
+
1103
+ function drain_release_events(queue: ref[deque.Deque[PeerEvent]]) -> void:
1104
+ while true:
1105
+ let ev = queue.pop_front()
1106
+ match ev:
1107
+ Option.none:
1108
+ break
1109
+ Option.some as payload:
1110
+ var pe = payload.value
1111
+ if pe.kind == PeerEventKind.user_data:
1112
+ pe.payload.release()
1113
+
1114
+
1115
+ function mark_peer_disconnected(session: ref[Session], peer_id: uint) -> void:
1116
+ var index: ptr_uint = 0
1117
+ while index < session.peers.len():
1118
+ let peer_ptr = session.peers.get(index) else:
1119
+ return
1120
+ if unsafe: read(peer_ptr).peer_id == peer_id:
1121
+ unsafe: read(peer_ptr).channel_state = ConnectionState.disconnected
1122
+ return
1123
+ index += 1
1124
+
1125
+
1126
+ function connected_peer_count(session: ref[Session]) -> ptr_uint:
1127
+ var count: ptr_uint = 0
1128
+ var index: ptr_uint = 0
1129
+ while index < session.peers.len():
1130
+ let peer_ptr = session.peers.get(index) else:
1131
+ return count
1132
+ if unsafe: read(peer_ptr).channel_state == ConnectionState.connected:
1133
+ count += 1
1134
+ index += 1
1135
+ return count
1136
+
1137
+
1138
+ function update_peer_last_recv(session: ref[Session], peer_id: uint) -> void:
1139
+ var index: ptr_uint = 0
1140
+ while index < session.peers.len():
1141
+ let peer_ptr = session.peers.get(index) else:
1142
+ return
1143
+ if unsafe: read(peer_ptr).peer_id == peer_id:
1144
+ unsafe: read(peer_ptr).frame_since_last_recv = 0
1145
+ return
1146
+ index += 1
1147
+
1148
+
1149
+ function mark_peer_heartbeat_ack(session: ref[Session], peer_id: uint) -> void:
1150
+ var index: ptr_uint = 0
1151
+ while index < session.peers.len():
1152
+ let peer_ptr = session.peers.get(index) else:
1153
+ return
1154
+ if unsafe: read(peer_ptr).peer_id == peer_id:
1155
+ unsafe: read(peer_ptr).heartbeat_ack_received = true
1156
+ return
1157
+ index += 1