layer_mtproto/session.rs
1// Copyright (c) Ankit Chaubey <ankitchaubey.dev@gmail.com>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4// NOTE:
5// The "Layer" project is no longer maintained or supported.
6// Its original purpose for personal SDK/APK experimentation and learning
7// has been fulfilled.
8//
9// Please use Ferogram instead:
10// https://github.com/ankit-chaubey/ferogram
11// Ferogram will receive future updates and development, although progress
12// may be slower.
13//
14// Ferogram is an async Telegram MTProto client library written in Rust.
15// Its implementation follows the behaviour of the official Telegram clients,
16// particularly Telegram Desktop and TDLib, and aims to provide a clean and
17// modern async interface for building Telegram clients and tools.
18
19//! MTProto client session state.
20
21use layer_tl_types::RemoteCall;
22
23use crate::message::{Message, MessageId};
24
25/// Tracks per-connection MTProto session state.
26///
27/// A `Session` is cheap to create and can be reset on reconnect.
28///
29/// # Example
30///
31/// ```rust
32/// use layer_mtproto::Session;
33/// use layer_tl_types::functions;
34///
35/// let mut session = Session::new();
36/// // let msg = session.pack(&my_request);
37/// // send(msg.to_plaintext_bytes()).await?;
38/// ```
39pub struct Session {
40 /// Monotonically increasing counter used to generate unique message IDs.
41 msg_counter: u32,
42 /// The sequence number for the next message.
43 /// Even for content-unrelated messages, odd for content-related (RPC calls).
44 seq_no: i32,
45}
46
47impl Session {
48 /// Create a fresh session.
49 pub fn new() -> Self {
50 Self {
51 msg_counter: 0,
52 seq_no: 0,
53 }
54 }
55
56 /// Allocate a new message ID.
57 pub fn next_msg_id(&mut self) -> MessageId {
58 self.msg_counter = self.msg_counter.wrapping_add(1);
59 MessageId::generate(self.msg_counter)
60 }
61
62 /// Return the next sequence number for a content-related message (RPC call).
63 ///
64 /// Increments by 2 after each call so that even slots remain available
65 /// for content-unrelated messages (acks, pings, etc.).
66 pub fn next_seq_no(&mut self) -> i32 {
67 let n = self.seq_no;
68 self.seq_no += 2;
69 n | 1 // odd = content-related
70 }
71
72 /// Return the next sequence number for a content-*un*related message.
73 pub fn next_seq_no_unrelated(&mut self) -> i32 {
74 let n = self.seq_no;
75 n & !1 // even = content-unrelated (don't increment)
76 }
77
78 /// Serialize an RPC function into a [`Message`] ready to send.
79 ///
80 /// The message body is just the TL-serialized `call`; the surrounding
81 /// transport framing (auth_key_id, etc.) is applied in [`Message::to_plaintext_bytes`].
82 pub fn pack<R: RemoteCall>(&mut self, call: &R) -> Message {
83 let id = self.next_msg_id();
84 let seq_no = self.next_seq_no();
85 let body = call.to_bytes();
86 Message::plaintext(id, seq_no, body)
87 }
88}
89
90impl Default for Session {
91 fn default() -> Self {
92 Self::new()
93 }
94}