stratum_types/
lib.rs

1pub mod error;
2pub mod miner;
3pub mod params;
4pub mod stratum_error;
5pub mod traits;
6use crate::params::{Params, Results};
7pub use crate::stratum_error::StratumError;
8use crate::traits::{PoolParams, StratumParams};
9pub use error::Error;
10pub use miner::{MinerAuth, MinerInfo, MinerJobStats};
11use serde::de::{self, MapAccess, SeqAccess, Visitor};
12use serde::{Deserialize, Deserializer, Serialize, Serializer};
13use std::fmt;
14use std::marker::PhantomData;
15
16pub type Result<T> = std::result::Result<T, Error>;
17
18
19#[derive(Serialize, Deserialize)]
20#[serde(untagged)]
21pub enum StratumPacket<PP, SP>
22where
23    PP: PoolParams,
24    SP: StratumParams,
25{
26    Request(Request<PP, SP>),
27    Response(Response<PP>),
28}
29
30#[derive(Serialize, Deserialize)]
31pub struct Response<PP>
32where
33    PP: PoolParams,
34{
35    pub id: ID,
36    #[serde(skip_serializing_if = "StratumMethod::is_classic")]
37    pub method: StratumMethod,
38    pub result: Option<Results<PP>>,
39    pub error: Option<StratumError>,
40}
41
42// #[derive(Serialize, Deserialize)]
43#[derive(Serialize)]
44pub struct Request<PP, SP>
45where
46    PP: PoolParams,
47    SP: StratumParams,
48{
49    pub id: ID,
50    pub method: StratumMethod,
51    pub params: Params<PP, SP>,
52}
53
54impl<'de, PP, SP> Deserialize<'de> for Request<PP, SP>
55where
56    PP: PoolParams + Deserialize<'de>,
57    SP: StratumParams + Deserialize<'de>,
58{
59    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
60    where
61        D: Deserializer<'de>,
62    {
63        enum Field {
64            Id,
65            Method,
66            Params,
67            JsonRPC,
68        };
69
70        // This part could also be generated independently by:
71        //
72        //    #[derive(Deserialize)]
73        //    #[serde(field_identifier, rename_all = "lowercase")]
74        //    enum Field { Secs, Nanos }
75        impl<'de> Deserialize<'de> for Field {
76            fn deserialize<D>(deserializer: D) -> std::result::Result<Field, D::Error>
77            where
78                D: Deserializer<'de>,
79            {
80                struct FieldVisitor;
81
82                impl<'de> Visitor<'de> for FieldVisitor {
83                    type Value = Field;
84
85                    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
86                        formatter.write_str("`id` or `method` or params")
87                    }
88
89                    fn visit_str<E>(self, value: &str) -> std::result::Result<Field, E>
90                    where
91                        E: de::Error,
92                    {
93                        match value {
94                            "id" => Ok(Field::Id),
95                            "method" => Ok(Field::Method),
96                            "params" => Ok(Field::Params),
97                            "jsonrpc" => Ok(Field::JsonRPC),
98                            _ => Err(de::Error::unknown_field(value, FIELDS)),
99                        }
100                    }
101                }
102
103                deserializer.deserialize_identifier(FieldVisitor)
104            }
105        }
106
107        // struct RequestVisitor;
108        struct RequestVisitor<SP, PP>
109        where
110            PP: PoolParams,
111            SP: StratumParams,
112        {
113            marker: PhantomData<fn() -> Request<PP, SP>>,
114        };
115
116        impl<SP, PP> RequestVisitor<SP, PP>
117        where
118            PP: PoolParams,
119            SP: StratumParams,
120        {
121            fn new() -> Self {
122                RequestVisitor {
123                    marker: PhantomData,
124                }
125            }
126        }
127
128        impl<'de, SP, PP> Visitor<'de> for RequestVisitor<SP, PP>
129        where
130            PP: PoolParams + Deserialize<'de>,
131            SP: StratumParams + Deserialize<'de>,
132        {
133            type Value = Request<PP, SP>;
134
135            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
136                formatter.write_str("struct Request")
137            }
138
139            //     fn visit_seq<V>(self, mut seq: V) -> Result<Request, V::Error>
140            //     where
141            //         V: SeqAccess<'de>,
142            //     {
143            //         let secs = seq
144            //             .next_element()?
145            //             .ok_or_else(|| de::Error::invalid_length(0, &self))?;
146            //         let nanos = seq
147            //             .next_element()?
148            //             .ok_or_else(|| de::Error::invalid_length(1, &self))?;
149            //         Ok(Duration::new(secs, nanos))
150            //     }
151
152            fn visit_map<V>(self, mut map: V) -> std::result::Result<Request<PP, SP>, V::Error>
153            where
154                V: MapAccess<'de>,
155            {
156                let mut id = None;
157                let mut method = None;
158                // let mut jsonrpc = None;
159                let mut params = None;
160                while let Some(key) = map.next_key()? {
161                    match key {
162                        Field::Id => {
163                            if id.is_some() {
164                                return Err(de::Error::duplicate_field("id"));
165                            }
166                            id = Some(map.next_value()?);
167                        }
168                        Field::Method => {
169                            if method.is_some() {
170                                return Err(de::Error::duplicate_field("method"));
171                            }
172                            method = Some(map.next_value()?);
173                        }
174                        Field::JsonRPC => {
175                            //Do nothing but don't error out.
176                        }
177                        Field::Params => {
178                            if params.is_some() {
179                                return Err(de::Error::duplicate_field("params"));
180                            }
181                            if let Some(temp_method) = &method {
182                                if &StratumMethod::ClassicSubscribe == temp_method
183                                    || &StratumMethod::Subscribe == temp_method
184                                {
185                                    let temp: PP::Subscribe = map.next_value()?;
186                                    params = Some(Params::Subscribe(temp));
187                                // params: PP::Subscribe = Some(map.next_value()?);
188                                } else {
189                                    params = Some(map.next_value()?);
190                                }
191                            } else {
192                                params = Some(map.next_value()?);
193                            }
194                        }
195                    }
196                }
197
198                let id = id.ok_or_else(|| de::Error::missing_field("id"))?;
199                let method = method.ok_or_else(|| de::Error::missing_field("method"))?;
200                let params = params.ok_or_else(|| de::Error::missing_field("params"))?;
201
202                Ok(Request { id, method, params })
203            }
204        }
205
206        const FIELDS: &'static [&'static str] = &["id", "method", "params", "jsonrpc"];
207        deserializer.deserialize_struct("Request", FIELDS, RequestVisitor::new())
208    }
209}
210
211#[derive(Serialize, Deserialize, Clone, Debug)]
212#[serde(untagged)]
213pub enum ID {
214    Num(u64),
215    Str(String),
216    Null(serde_json::Value),
217}
218
219// impl Serialize for ID {
220//     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
221//     where
222//         S: Serializer,
223//     {
224//         let id = match *self {
225//             ID::Num(num) => num.to_string(),
226//             ID::Str(ref string) => string.clone(),
227//         };
228
229//         serializer.serialize_str(&id)
230//     }
231// }
232
233impl std::fmt::Display for ID {
234    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
235        match self {
236            ID::Num(ref e) => write!(f, "{}", e),
237            ID::Str(ref e) => write!(f, "{}", e),
238            ID::Null(ref _e) => write!(f, "null"),
239        }
240    }
241}
242
243#[derive(Debug, PartialEq)]
244pub enum StratumMethod {
245    //Sending and receiving
246    Authorize,
247    ClassicAuthorize,
248    Submit,
249    ClassicSubmit,
250    Subscribe,
251    ClassicSubscribe,
252    Notify,
253    ClassicNotify,
254    SetDifficulty,
255    ClassicSetDifficulty,
256
257    //Future methods potentially not implemented yet.
258    Unknown(String),
259}
260
261impl StratumMethod {
262    pub fn is_classic(&self) -> bool {
263        match self {
264            StratumMethod::ClassicAuthorize => true,
265            StratumMethod::ClassicSubmit => true,
266            StratumMethod::ClassicNotify => true,
267            StratumMethod::ClassicSetDifficulty => true,
268            _ => false,
269        }
270    }
271}
272
273impl Serialize for StratumMethod {
274    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
275    where
276        S: Serializer,
277    {
278        serializer.serialize_str(match *self {
279            StratumMethod::Authorize => "authorize",
280            StratumMethod::ClassicAuthorize => "mining.authorize",
281            StratumMethod::Submit => "submit",
282            StratumMethod::ClassicSubmit => "mining.submit",
283            StratumMethod::Subscribe => "subscribe",
284            StratumMethod::ClassicSubscribe => "mining.subscribe",
285            StratumMethod::Notify => "notify",
286            StratumMethod::ClassicNotify => "mining.notify",
287            StratumMethod::SetDifficulty => "set_difficulty",
288            StratumMethod::ClassicSetDifficulty => "mining.set_difficulty",
289            StratumMethod::Unknown(ref s) => s,
290        })
291    }
292}
293
294impl<'de> Deserialize<'de> for StratumMethod {
295    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
296    where
297        D: Deserializer<'de>,
298    {
299        let s = String::deserialize(deserializer)?;
300        Ok(match s.as_str() {
301            "authorize" => StratumMethod::Authorize,
302            "mining.authorize" => StratumMethod::ClassicAuthorize,
303            "submit" => StratumMethod::Submit,
304            "mining.submit" => StratumMethod::ClassicSubmit,
305            "subscribe" => StratumMethod::Subscribe,
306            "mining.subscribe" => StratumMethod::ClassicSubscribe,
307            "notify" => StratumMethod::Notify,
308            "mining.notify" => StratumMethod::ClassicNotify,
309            "set_difficulty" => StratumMethod::SetDifficulty,
310            "mining.set_difficulty" => StratumMethod::ClassicSetDifficulty,
311            _ => StratumMethod::Unknown(s),
312        })
313    }
314}