Skip to main content

layer_mtproto/
session.rs

1//! MTProto client session state.
2
3use layer_tl_types::RemoteCall;
4
5use crate::message::{Message, MessageId};
6
7/// Tracks per-connection MTProto session state.
8///
9/// A `Session` is cheap to create and can be reset on reconnect.
10///
11/// # Example
12///
13/// ```rust
14/// use layer_mtproto::Session;
15/// use layer_tl_types::functions;
16///
17/// let mut session = Session::new();
18/// // let msg = session.pack(&my_request);
19/// // send(msg.to_plaintext_bytes()).await?;
20/// ```
21pub struct Session {
22    /// Monotonically increasing counter used to generate unique message IDs.
23    msg_counter: u32,
24    /// The sequence number for the next message.
25    /// Even for content-unrelated messages, odd for content-related (RPC calls).
26    seq_no: i32,
27}
28
29impl Session {
30    /// Create a fresh session.
31    pub fn new() -> Self {
32        Self {
33            msg_counter: 0,
34            seq_no: 0,
35        }
36    }
37
38    /// Allocate a new message ID.
39    pub fn next_msg_id(&mut self) -> MessageId {
40        self.msg_counter = self.msg_counter.wrapping_add(1);
41        MessageId::generate(self.msg_counter)
42    }
43
44    /// Return the next sequence number for a content-related message (RPC call).
45    ///
46    /// Increments by 2 after each call so that even slots remain available
47    /// for content-unrelated messages (acks, pings, etc.).
48    pub fn next_seq_no(&mut self) -> i32 {
49        let n = self.seq_no;
50        self.seq_no += 2;
51        n | 1 // odd = content-related
52    }
53
54    /// Return the next sequence number for a content-*un*related message.
55    pub fn next_seq_no_unrelated(&mut self) -> i32 {
56        let n = self.seq_no;
57        n & !1 // even = content-unrelated (don't increment)
58    }
59
60    /// Serialize an RPC function into a [`Message`] ready to send.
61    ///
62    /// The message body is just the TL-serialized `call`; the surrounding
63    /// transport framing (auth_key_id, etc.) is applied in [`Message::to_plaintext_bytes`].
64    pub fn pack<R: RemoteCall>(&mut self, call: &R) -> Message {
65        let id = self.next_msg_id();
66        let seq_no = self.next_seq_no();
67        let body = call.to_bytes();
68        Message::plaintext(id, seq_no, body)
69    }
70}
71
72impl Default for Session {
73    fn default() -> Self {
74        Self::new()
75    }
76}