binary_option_tools_core/pocketoption/ws/
ssid.rs1use core::fmt;
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6use crate::{
7 general::traits::Credentials,
8 pocketoption::error::{PocketOptionError, PocketResult},
9};
10
11use super::regions::Regions;
12
13#[derive(Debug, Serialize, Deserialize, Clone)]
14pub struct SessionData {
15 session_id: String,
16 ip_address: String,
17 user_agent: String,
18 last_activity: u64,
19}
20
21#[derive(Debug, Serialize, Deserialize, Clone)]
22#[serde(rename_all = "camelCase")]
23pub struct Demo {
24 session: String,
25 is_demo: u32,
26 uid: u32,
27 platform: u32,
28}
29
30#[derive(Debug, Serialize, Clone)]
31#[serde(rename_all = "camelCase")]
32pub struct Real {
33 session: SessionData,
34 is_demo: u32,
35 uid: u32,
36 platform: u32,
37 raw: String,
38}
39
40#[derive(Debug, Serialize, Clone)]
41#[serde(untagged)]
42pub enum Ssid {
43 Demo(Demo),
44 Real(Real),
45}
46
47impl Ssid {
48 pub fn parse(data: impl ToString) -> PocketResult<Self> {
49 let data = data.to_string();
50 let parsed = data
51 .trim()
52 .strip_prefix(r#"42["auth","#)
53 .ok_or(PocketOptionError::SsidParsingError(
54 "Error parsing ssid string into object".into(),
55 ))?
56 .strip_suffix("]")
57 .ok_or(PocketOptionError::SsidParsingError(
58 "Error parsing ssid string into object".into(),
59 ))?;
60 let ssid: Demo = serde_json::from_str(parsed)
61 .map_err(|e| PocketOptionError::SsidParsingError(e.to_string()))?;
62 if ssid.is_demo == 1 {
63 Ok(Self::Demo(ssid))
64 } else {
65 let real = Real {
66 raw: data,
67 is_demo: ssid.is_demo,
68 session: php_serde::from_bytes(ssid.session.as_bytes()).map_err(|e| {
69 PocketOptionError::SsidParsingError(format!("Error parsing session data, {e}"))
70 })?,
71 uid: ssid.uid,
72 platform: ssid.platform,
73 };
74 Ok(Self::Real(real))
75 }
76 }
77
78 pub async fn server(&self) -> PocketResult<String> {
79 match self {
80 Self::Demo(_) => Ok(Regions::DEMO.to_string()),
81 Self::Real(_) => Regions.get_server().await.map(|s| s.to_string()),
82 }
83 }
84
85 pub async fn servers(&self) -> PocketResult<Vec<String>> {
86 match self {
87 Self::Demo(_) => Ok(vec![Regions::DEMO.to_string()]),
88 Self::Real(_) => Ok(Regions
89 .get_servers()
90 .await?
91 .iter()
92 .map(|s| s.to_string())
93 .collect()),
94 }
95 }
96
97 pub fn user_agent(&self) -> String {
98 match self {
99 Self::Demo(_) => "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36".into(),
100 Self::Real(real) => real.session.user_agent.clone()
101 }
102 }
103
104 pub fn demo(&self) -> bool {
105 match self {
106 Self::Demo(_) => true,
107 Self::Real(_) => false,
108 }
109 }
110}
111impl fmt::Display for Demo {
112 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113 let ssid = serde_json::to_string(&self).map_err(|_| fmt::Error)?;
114 write!(f, r#"42["auth",{}]"#, ssid)
115 }
116}
117
118impl fmt::Display for Real {
119 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
120 write!(f, "{}", self.raw)
121 }
122}
123
124impl fmt::Display for Ssid {
125 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
126 match self {
127 Self::Demo(demo) => demo.fmt(f),
128 Self::Real(real) => real.fmt(f),
129 }
130 }
131}
132
133impl<'de> Deserialize<'de> for Ssid {
134 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
135 where
136 D: serde::Deserializer<'de>,
137 {
138 let data: Value = Value::deserialize(deserializer)?;
139 Ssid::parse(data).map_err(serde::de::Error::custom)
140 }
141}
142
143impl Credentials for Ssid {}
144
145#[cfg(test)]
146mod tests {
147 use super::*;
148 use std::error::Error;
149
150 #[test]
151 fn test_descerialize_session() -> Result<(), Box<dyn Error>> {
152 let session_raw = b"a:4:{s:10:\"session_id\";s:32:\"ae3aa847add89c341ec18d8ae5bf8527\";s:10:\"ip_address\";s:15:\"191.113.157.139\";s:10:\"user_agent\";s:120:\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 OPR/114.\";s:13:\"last_activity\";i:1732926685;}31666d2dc07fdd866353937b97901e2b";
153 let session: SessionData = php_serde::from_bytes(session_raw)?;
154 dbg!(&session);
155 let session_php = php_serde::to_vec(&session)?;
156 dbg!(String::from_utf8(session_php).unwrap());
157 Ok(())
158 }
159
160 #[test]
161 fn test_parse_ssid() -> Result<(), Box<dyn Error>> {
162 let ssids = [
163 r#"42["auth",{"session":"looc69ct294h546o368s0lct7d","isDemo":1,"uid":87742848,"platform":2}] "#,
164 r#"42["auth",{"session":"a:4:{s:10:\"session_id\";s:32:\"ae3aa847add89c341ec18d8ae5bf8527\";s:10:\"ip_address\";s:15:\"191.113.157.139\";s:10:\"user_agent\";s:120:\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 OPR/114.\";s:13:\"last_activity\";i:1732926685;}31666d2dc07fdd866353937b97901e2b","isDemo":0,"uid":87742848,"platform":2}] "#,
165 r#"42["auth",{"session":"vtftn12e6f5f5008moitsd6skl","isDemo":1,"uid":27658142,"platform":2}]"#,
166 ];
167 for ssid in ssids {
168 let valid = Ssid::parse(ssid)?;
169 dbg!(valid);
170 }
171 Ok(())
172 }
173}