// session.mbt — KcpSession 会话壳(K3)
//
// 宿主侧 API 门面:bundle Kcp 状态机 + 应用消息队列 + 背压。
// 集成面(与 heart tick / UDP adapter 对接的形状):
// - 宿主收到 UDP 报文 → on_datagram(报文)
// - 宿主时钟到点 → frames = tick(current);逐帧走 UDP 发出
// - 应用发消息 → send_message(载荷)(窗口满拒收 = 背压)
// - 应用收消息 → poll_message()(FIFO)
// 仍是纯形:零 IO 零时钟,帧与报文进出由宿主搬运。消息面全 Bytes(K1 刀1)。
///|
/// KCP 会话:状态机 + 收件队列 + 发送背压水位。
pub(all) struct KcpSession {
kcp : Kcp
inbound : Array[FixedArray[Byte]]
high_water : Int32
}
///|
/// 新会话:conv 双端一致;high_water = waitsnd 背压上限
/// (snd_queue + snd_buf 达此值 send_message 拒收)。
pub fn KcpSession::new(conv : Int32, high_water : Int32) -> KcpSession {
{ kcp: Kcp::create(conv), inbound: [], high_water, }
}
///|
/// 应用下发一消息。waitsnd 达 high_water 返回 -2(窗口满背压);
/// 否则转 Kcp::send(负错码直传;成功返回字节数)。
pub fn KcpSession::send_message(
self : KcpSession,
payload : FixedArray[Byte],
) -> Int32 {
if self.kcp.waitsnd() >= self.high_water {
return -2
}
self.kcp.send(payload)
}
///|
/// 宿主投递一 UDP 报文:状态机结算后,把已就绪的整消息
/// 全部搬入收件队列。返回 input 错码(0 = 正常)。
pub fn KcpSession::on_datagram(
self : KcpSession,
datagram : FixedArray[Byte],
) -> Int32 {
let code = self.kcp.input(datagram)
let mut go = true
while go {
match self.kcp.recv() {
Some(msg) => self.inbound.push(msg)
None => go = false
}
}
code
}
///|
/// 宿主时钟推进:到 interval 点则 flush,返回待发送帧
/// (宿主逐帧走 UDP 发出)。
pub fn KcpSession::tick(
self : KcpSession,
current : Int32,
) -> Array[FixedArray[Byte]] {
self.kcp.update(current)
}
///|
/// 应用收一消息(FIFO);无消息返回 None。
pub fn KcpSession::poll_message(self : KcpSession) -> FixedArray[Byte]? {
if self.inbound.length() == 0 {
return None
}
Some(self.inbound.remove(0))
}
///|
/// 链路判死(dead_link 触发后 state = -1)。
pub fn KcpSession::is_dead(self : KcpSession) -> Bool {
self.kcp.state != 0
}
///|
/// 观测快照透传(运维/调试面)。
pub fn KcpSession::stats(self : KcpSession) -> KcpStats {
self.kcp.stats()
}
///|
/// 活性戳透传(最近一次合法对端报文的注入 ms;闲置回收判据)。
pub fn KcpSession::last_active(self : KcpSession) -> Int32 {
self.kcp.last_active
}