grammers_session/storages/
tl_session.rs1#![allow(deprecated)]
10
11use crate::dc_options::DEFAULT_DC;
12use crate::defs::PeerAuth;
13use crate::generated::{enums, types};
14use crate::{KNOWN_DC_OPTIONS, Session};
15use grammers_tl_types::deserialize::Error as DeserializeError;
16use grammers_tl_types::{Deserializable, Serializable};
17use std::fmt;
18use std::fs::{File, OpenOptions};
19use std::io::{self, Read, Seek, Write};
20use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
21use std::path::Path;
22use std::sync::Mutex;
23
24#[cfg_attr(
29 feature = "impl-serde",
30 derive(serde_derive::Serialize, serde_derive::Deserialize)
31)]
32#[deprecated(note = "Migrate to a different storage")]
33pub struct TlSession {
34 session: Mutex<types::Session>,
35}
36
37#[allow(clippy::new_without_default)]
38impl TlSession {
39 pub fn new() -> Self {
40 let this = Self {
41 session: Mutex::new(types::Session {
42 dcs: Vec::with_capacity(KNOWN_DC_OPTIONS.len()),
43 user: None,
44 state: None,
45 }),
46 };
47 KNOWN_DC_OPTIONS
48 .iter()
49 .for_each(|dc_option| this.set_dc_option(dc_option));
50 this
51 }
52
53 pub fn load_file_or_create<P: AsRef<Path>>(path: P) -> io::Result<Self> {
56 let path = path.as_ref();
57 if !path.exists() {
58 File::create(path)?;
59 let session = TlSession::new();
60 session.save_to_file(path)?;
61 Ok(session)
62 } else {
63 Self::load_file(path)
64 }
65 }
66
67 pub fn load_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
69 let mut data = Vec::new();
70 File::open(path.as_ref())?.read_to_end(&mut data)?;
71
72 Self::load(&data).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
73 }
74
75 pub fn load(data: &[u8]) -> Result<Self, Error> {
76 let this = Self {
77 session: Mutex::new(
78 enums::Session::from_bytes(data)
79 .map_err(|e| match e {
80 DeserializeError::UnexpectedEof => Error::MalformedData,
81 DeserializeError::UnexpectedConstructor { .. } => Error::UnsupportedVersion,
82 })?
83 .into(),
84 ),
85 };
86 KNOWN_DC_OPTIONS.iter().for_each(|dc_option| {
87 if this.dc_option(dc_option.id).is_none() {
88 this.set_dc_option(dc_option);
89 }
90 });
91 Ok(this)
92 }
93
94 #[must_use]
95 pub fn save(&self) -> Vec<u8> {
96 enums::Session::Session(self.session.lock().unwrap().clone()).to_bytes()
97 }
98
99 pub fn save_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
101 let mut file = OpenOptions::new().write(true).open(path.as_ref())?;
102 file.seek(io::SeekFrom::Start(0))?;
103 file.set_len(0)?;
104 file.write_all(&self.save())?;
105 file.sync_data()
106 }
107}
108
109impl crate::Session for TlSession {
110 fn home_dc_id(&self) -> i32 {
111 let session = self.session.lock().unwrap();
112 session
113 .user
114 .as_ref()
115 .map(|enums::User::User(user)| user.dc)
116 .unwrap_or(DEFAULT_DC)
117 }
118
119 fn set_home_dc_id(&self, dc_id: i32) {
120 let mut session = self.session.lock().unwrap();
121 if let Some(enums::User::User(user)) = &mut session.user {
122 user.dc = dc_id
123 } else {
124 session.user = Some(enums::User::User(types::User {
125 id: 0,
126 bot: false,
127 dc: dc_id,
128 }))
129 }
130 }
131
132 fn dc_option(&self, dc_id: i32) -> Option<crate::defs::DcOption> {
133 let session = self.session.lock().unwrap();
134 session.dcs.iter().find_map(|dc| match dc {
135 enums::DataCenter::Center(center) if center.id == dc_id => {
136 Some(crate::defs::DcOption {
137 id: center.id,
138 ipv4: SocketAddrV4::new(
139 Ipv4Addr::from_bits(center.ipv4.unwrap() as _),
140 center.port as _,
141 ),
142 ipv6: SocketAddrV6::new(
143 center
144 .ipv6
145 .map(|ipv6| Ipv6Addr::from_bits(u128::from_le_bytes(ipv6)))
146 .unwrap_or_else(|| {
147 Ipv4Addr::from_bits(center.ipv4.unwrap() as _).to_ipv6_mapped()
148 }),
149 center.port as _,
150 0,
151 0,
152 ),
153 auth_key: center.auth.as_deref().map(|auth| auth.try_into().unwrap()),
154 })
155 }
156 _ => None,
157 })
158 }
159
160 fn set_dc_option(&self, dc_option: &crate::defs::DcOption) {
161 let mut session = self.session.lock().unwrap();
162
163 if let Some(pos) = session.dcs.iter().position(|dc| dc.id() == dc_option.id) {
164 session.dcs.remove(pos);
165 }
166 session
167 .dcs
168 .push(enums::DataCenter::Center(types::DataCenter {
169 id: dc_option.id,
170 ipv4: Some(dc_option.ipv4.ip().to_bits() as _),
171 ipv6: Some(dc_option.ipv6.ip().to_bits().to_le_bytes()),
172 port: dc_option.ipv4.port() as _,
173 auth: dc_option.auth_key.map(|auth| auth.to_vec()),
174 }));
175 }
176
177 fn peer(&self, peer: crate::defs::PeerId) -> Option<crate::defs::PeerInfo> {
178 let session = self.session.lock().unwrap();
179 if peer.kind() == crate::defs::PeerKind::UserSelf {
180 session
181 .user
182 .as_ref()
183 .map(|enums::User::User(user)| crate::defs::PeerInfo::User {
184 id: user.id,
185 auth: Some(PeerAuth::default()),
186 bot: Some(user.bot),
187 is_self: Some(true),
188 })
189 } else {
190 None
191 }
192 }
193
194 fn cache_peer(&self, peer: &crate::defs::PeerInfo) {
195 let mut session = self.session.lock().unwrap();
196 match peer {
197 crate::defs::PeerInfo::User {
198 id,
199 auth: _,
200 bot,
201 is_self,
202 } if *is_self == Some(true) => {
203 if let Some(enums::User::User(user)) = &mut session.user {
204 user.id = *id;
205 user.bot = bot.unwrap_or_default();
206 } else {
207 session.user = Some(enums::User::User(types::User {
208 id: *id,
209 bot: bot.unwrap_or_default(),
210 dc: DEFAULT_DC,
211 }))
212 }
213 }
214 _ => {}
215 }
216 }
217
218 fn updates_state(&self) -> crate::defs::UpdatesState {
219 let session = self.session.lock().unwrap();
220 session
221 .state
222 .as_ref()
223 .map(
224 |enums::UpdateState::State(state)| crate::defs::UpdatesState {
225 pts: state.pts,
226 qts: state.qts,
227 date: state.date,
228 seq: state.seq,
229 channels: state
230 .channels
231 .iter()
232 .map(
233 |enums::ChannelState::State(channel)| crate::defs::ChannelState {
234 id: channel.channel_id,
235 pts: channel.pts,
236 },
237 )
238 .collect(),
239 },
240 )
241 .unwrap_or_default()
242 }
243
244 fn set_update_state(&self, update: crate::defs::UpdateState) {
245 match update {
246 crate::defs::UpdateState::All(updates_state) => {
247 let mut session = self.session.lock().unwrap();
248 session.state = Some(
249 types::UpdateState {
250 pts: updates_state.pts,
251 qts: updates_state.qts,
252 date: updates_state.date,
253 seq: updates_state.seq,
254 channels: updates_state
255 .channels
256 .iter()
257 .map(|channel| {
258 types::ChannelState {
259 channel_id: channel.id,
260 pts: channel.pts,
261 }
262 .into()
263 })
264 .collect(),
265 }
266 .into(),
267 )
268 }
269 crate::defs::UpdateState::Primary { pts, date, seq } => {
270 let mut current = self.updates_state();
271 current.pts = pts;
272 current.date = date;
273 current.seq = seq;
274 self.set_update_state(crate::defs::UpdateState::All(current));
275 }
276 crate::defs::UpdateState::Secondary { qts } => {
277 let mut current = self.updates_state();
278 current.qts = qts;
279 self.set_update_state(crate::defs::UpdateState::All(current));
280 }
281 crate::defs::UpdateState::Channel { id, pts } => {
282 let mut current = self.updates_state();
283 if let Some(pos) = current.channels.iter().position(|channel| channel.id == id) {
284 current.channels[pos] = crate::defs::ChannelState { id: id, pts }
285 } else {
286 current
287 .channels
288 .push(crate::defs::ChannelState { id: id, pts });
289 }
290 self.set_update_state(crate::defs::UpdateState::All(current));
291 }
292 }
293 }
294}
295
296#[derive(Debug)]
297pub enum Error {
298 MalformedData,
299 UnsupportedVersion,
300}
301
302impl fmt::Display for Error {
303 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
304 match self {
305 Error::MalformedData => write!(f, "malformed data"),
306 Error::UnsupportedVersion => write!(f, "unsupported version"),
307 }
308 }
309}
310
311impl std::error::Error for Error {}