pub mod error;
pub mod miner;
pub mod params;
pub mod stratum_error;
pub mod traits;
use crate::params::{Params, Results};
pub use crate::stratum_error::StratumError;
use crate::traits::{PoolParams, StratumParams};
pub use error::Error;
pub use miner::{MinerAuth, MinerInfo, MinerJobStats};
use serde::de::{self, MapAccess, SeqAccess, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;
use std::marker::PhantomData;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Serialize, Deserialize)]
#[serde(untagged)]
pub enum StratumPacket<PP, SP>
where
PP: PoolParams,
SP: StratumParams,
{
Request(Request<PP, SP>),
Response(Response<PP>),
}
#[derive(Serialize, Deserialize)]
pub struct Response<PP>
where
PP: PoolParams,
{
pub id: ID,
#[serde(skip_serializing_if = "StratumMethod::is_classic")]
pub method: StratumMethod,
pub result: Option<Results<PP>>,
pub error: Option<StratumError>,
}
#[derive(Serialize)]
pub struct Request<PP, SP>
where
PP: PoolParams,
SP: StratumParams,
{
pub id: ID,
pub method: StratumMethod,
pub params: Params<PP, SP>,
}
impl<'de, PP, SP> Deserialize<'de> for Request<PP, SP>
where
PP: PoolParams + Deserialize<'de>,
SP: StratumParams + Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
enum Field {
Id,
Method,
Params,
};
impl<'de> Deserialize<'de> for Field {
fn deserialize<D>(deserializer: D) -> std::result::Result<Field, D::Error>
where
D: Deserializer<'de>,
{
struct FieldVisitor;
impl<'de> Visitor<'de> for FieldVisitor {
type Value = Field;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("`id` or `method` or params")
}
fn visit_str<E>(self, value: &str) -> std::result::Result<Field, E>
where
E: de::Error,
{
match value {
"id" => Ok(Field::Id),
"method" => Ok(Field::Method),
"params" => Ok(Field::Params),
_ => Err(de::Error::unknown_field(value, FIELDS)),
}
}
}
deserializer.deserialize_identifier(FieldVisitor)
}
}
struct RequestVisitor<SP, PP>
where
PP: PoolParams,
SP: StratumParams,
{
marker: PhantomData<fn() -> Request<PP, SP>>,
};
impl<SP, PP> RequestVisitor<SP, PP>
where
PP: PoolParams,
SP: StratumParams,
{
fn new() -> Self {
RequestVisitor {
marker: PhantomData,
}
}
}
impl<'de, SP, PP> Visitor<'de> for RequestVisitor<SP, PP>
where
PP: PoolParams + Deserialize<'de>,
SP: StratumParams + Deserialize<'de>,
{
type Value = Request<PP, SP>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct Request")
}
fn visit_map<V>(self, mut map: V) -> std::result::Result<Request<PP, SP>, V::Error>
where
V: MapAccess<'de>,
{
let mut id = None;
let mut method = None;
let mut params = None;
while let Some(key) = map.next_key()? {
match key {
Field::Id => {
if id.is_some() {
return Err(de::Error::duplicate_field("id"));
}
id = Some(map.next_value()?);
}
Field::Method => {
if method.is_some() {
return Err(de::Error::duplicate_field("method"));
}
method = Some(map.next_value()?);
}
Field::Params => {
if params.is_some() {
return Err(de::Error::duplicate_field("params"));
}
if let Some(temp_method) = &method {
if &StratumMethod::ClassicSubscribe == temp_method
|| &StratumMethod::Subscribe == temp_method
{
let temp: PP::Subscribe = map.next_value()?;
params = Some(Params::Subscribe(temp));
} else {
params = Some(map.next_value()?);
}
}
}
}
}
let id = id.ok_or_else(|| de::Error::missing_field("id"))?;
let method = method.ok_or_else(|| de::Error::missing_field("method"))?;
let params = params.ok_or_else(|| de::Error::missing_field("params"))?;
Ok(Request { id, method, params })
}
}
const FIELDS: &'static [&'static str] = &["id", "method", "params"];
deserializer.deserialize_struct("Request", FIELDS, RequestVisitor::new())
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(untagged)]
pub enum ID {
Num(u64),
Str(String),
Null(serde_json::Value),
}
impl std::fmt::Display for ID {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ID::Num(ref e) => write!(f, "{}", e),
ID::Str(ref e) => write!(f, "{}", e),
ID::Null(ref _e) => write!(f, "null"),
}
}
}
#[derive(Debug, PartialEq)]
pub enum StratumMethod {
Authorize,
ClassicAuthorize,
Submit,
ClassicSubmit,
Subscribe,
ClassicSubscribe,
Notify,
ClassicNotify,
SetDifficulty,
ClassicSetDifficulty,
Unknown(String),
}
impl StratumMethod {
pub fn is_classic(&self) -> bool {
match self {
StratumMethod::ClassicAuthorize => true,
StratumMethod::ClassicSubmit => true,
StratumMethod::ClassicNotify => true,
StratumMethod::ClassicSetDifficulty => true,
_ => false,
}
}
}
impl Serialize for StratumMethod {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(match *self {
StratumMethod::Authorize => "authorize",
StratumMethod::ClassicAuthorize => "mining.authorize",
StratumMethod::Submit => "submit",
StratumMethod::ClassicSubmit => "mining.submit",
StratumMethod::Subscribe => "subscribe",
StratumMethod::ClassicSubscribe => "mining.subscribe",
StratumMethod::Notify => "notify",
StratumMethod::ClassicNotify => "mining.notify",
StratumMethod::SetDifficulty => "set_difficulty",
StratumMethod::ClassicSetDifficulty => "mining.set_difficulty",
StratumMethod::Unknown(ref s) => s,
})
}
}
impl<'de> Deserialize<'de> for StratumMethod {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Ok(match s.as_str() {
"authorize" => StratumMethod::Authorize,
"mining.authorize" => StratumMethod::ClassicAuthorize,
"submit" => StratumMethod::Submit,
"mining.submit" => StratumMethod::ClassicSubmit,
"subscribe" => StratumMethod::Subscribe,
"mining.subscribe" => StratumMethod::ClassicSubscribe,
"notify" => StratumMethod::Notify,
"mining.notify" => StratumMethod::ClassicNotify,
"set_difficulty" => StratumMethod::SetDifficulty,
"mining.set_difficulty" => StratumMethod::ClassicSetDifficulty,
_ => StratumMethod::Unknown(s),
})
}
}