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)]
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 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<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_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 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 }
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 } 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
219impl 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 Authorize,
247 ClassicAuthorize,
248 Submit,
249 ClassicSubmit,
250 Subscribe,
251 ClassicSubscribe,
252 Notify,
253 ClassicNotify,
254 SetDifficulty,
255 ClassicSetDifficulty,
256
257 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}