asic_rs/data/device/models/
mod.rs

1#[cfg(feature = "python")]
2use pyo3::prelude::*;
3
4use super::{MinerFirmware, MinerMake};
5use antminer::AntMinerModel;
6use avalon::AvalonMinerModel;
7use bitaxe::BitaxeModel;
8use braiins::BraiinsModel;
9use epic::EPicModel;
10use serde::{Deserialize, Serialize};
11use std::{fmt::Display, str::FromStr};
12use whatsminer::WhatsMinerModel;
13
14pub mod antminer;
15pub mod avalon;
16pub mod bitaxe;
17pub mod braiins;
18pub mod epic;
19pub mod whatsminer;
20
21#[derive(Debug, Clone)]
22pub enum ModelSelectionError {
23    UnknownModel(String),
24    NoModelResponse,
25    UnexpectedModelResponse,
26}
27
28impl Display for ModelSelectionError {
29    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30        match self {
31            ModelSelectionError::UnknownModel(model) => write!(f, "Unknown model: {}", model),
32            ModelSelectionError::NoModelResponse => write!(f, "No response when querying model"),
33            ModelSelectionError::UnexpectedModelResponse => {
34                write!(f, "Response to model query was formatted unexpectedly")
35            }
36        }
37    }
38}
39
40impl std::error::Error for ModelSelectionError {}
41
42impl FromStr for WhatsMinerModel {
43    type Err = ModelSelectionError;
44
45    fn from_str(s: &str) -> Result<Self, Self::Err> {
46        serde_json::from_value(serde_json::Value::String(s.to_string()))
47            .map_err(|_| ModelSelectionError::UnknownModel(s.to_string()))
48    }
49}
50impl FromStr for AntMinerModel {
51    type Err = ModelSelectionError;
52
53    fn from_str(s: &str) -> Result<Self, Self::Err> {
54        serde_json::from_value(serde_json::Value::String(s.to_string()))
55            .map_err(|_| ModelSelectionError::UnknownModel(s.to_string()))
56    }
57}
58impl FromStr for BitaxeModel {
59    type Err = ModelSelectionError;
60
61    fn from_str(s: &str) -> Result<Self, Self::Err> {
62        serde_json::from_value(serde_json::Value::String(s.to_string()))
63            .map_err(|_| ModelSelectionError::UnknownModel(s.to_string()))
64    }
65}
66
67impl FromStr for BraiinsModel {
68    type Err = ModelSelectionError;
69
70    fn from_str(s: &str) -> Result<Self, Self::Err> {
71        serde_json::from_value(serde_json::Value::String(s.to_string()))
72            .map_err(|_| ModelSelectionError::UnknownModel(s.to_string()))
73    }
74}
75
76impl FromStr for AvalonMinerModel {
77    type Err = ModelSelectionError;
78
79    fn from_str(s: &str) -> Result<Self, Self::Err> {
80        serde_json::from_value(serde_json::Value::String(s.to_string()))
81            .map_err(|_| ModelSelectionError::UnknownModel(s.to_string()))
82    }
83}
84
85impl FromStr for EPicModel {
86    type Err = ModelSelectionError;
87
88    fn from_str(s: &str) -> Result<Self, Self::Err> {
89        serde_json::from_value(serde_json::Value::String(s.to_string()))
90            .map_err(|_| ModelSelectionError::UnknownModel(s.to_string()))
91    }
92}
93
94#[cfg_attr(feature = "python", pyclass(str, module = "asic_rs"))]
95#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Serialize, Deserialize)]
96#[serde(untagged)]
97pub enum MinerModel {
98    AntMiner(AntMinerModel),
99    WhatsMiner(WhatsMinerModel),
100    Braiins(BraiinsModel),
101    Bitaxe(BitaxeModel),
102    AvalonMiner(AvalonMinerModel),
103    EPic(EPicModel),
104}
105
106impl Display for MinerModel {
107    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108        match self {
109            MinerModel::AntMiner(m) => Ok(m.fmt(f)?),
110            MinerModel::WhatsMiner(m) => Ok(m.fmt(f)?),
111            MinerModel::Braiins(m) => Ok(m.fmt(f)?),
112            MinerModel::Bitaxe(m) => Ok(m.fmt(f)?),
113            MinerModel::EPic(m) => Ok(m.fmt(f)?),
114            MinerModel::AvalonMiner(m) => Ok(m.fmt(f)?),
115        }
116    }
117}
118
119impl From<MinerModel> for MinerMake {
120    fn from(model: MinerModel) -> Self {
121        match model {
122            MinerModel::AntMiner(_) => MinerMake::AntMiner,
123            MinerModel::WhatsMiner(_) => MinerMake::WhatsMiner,
124            MinerModel::Braiins(_) => MinerMake::Braiins,
125            MinerModel::Bitaxe(_) => MinerMake::Bitaxe,
126            MinerModel::EPic(_) => MinerMake::EPic,
127            MinerModel::AvalonMiner(_) => MinerMake::AvalonMiner,
128        }
129    }
130}
131
132pub(crate) struct MinerModelFactory {
133    make: Option<MinerMake>,
134    firmware: Option<MinerFirmware>,
135}
136
137impl MinerModelFactory {
138    pub fn new() -> Self {
139        MinerModelFactory {
140            make: None,
141            firmware: None,
142        }
143    }
144
145    pub(crate) fn with_make(&mut self, make: MinerMake) -> &Self {
146        self.make = Some(make);
147        self
148    }
149    pub(crate) fn with_firmware(&mut self, firmware: MinerFirmware) -> &Self {
150        self.firmware = Some(firmware);
151        self
152    }
153
154    pub(crate) fn parse_model(&self, model_str: &str) -> Result<MinerModel, ModelSelectionError> {
155        match self.make {
156            Some(MinerMake::AntMiner) => {
157                let model = AntMinerModel::from_str(model_str)?;
158                Ok(MinerModel::AntMiner(model))
159            }
160            Some(MinerMake::WhatsMiner) => {
161                let model = WhatsMinerModel::from_str(model_str)?;
162                Ok(MinerModel::WhatsMiner(model))
163            }
164            Some(MinerMake::Bitaxe) => {
165                let model = BitaxeModel::from_str(model_str)?;
166                Ok(MinerModel::Bitaxe(model))
167            }
168            Some(MinerMake::AvalonMiner) => {
169                let model = AvalonMinerModel::from_str(model_str)?;
170                Ok(MinerModel::AvalonMiner(model))
171            }
172            None => match self.firmware {
173                Some(MinerFirmware::BraiinsOS) => {
174                    match (
175                        AntMinerModel::from_str(model_str),
176                        BraiinsModel::from_str(model_str),
177                    ) {
178                        (Ok(model), _) => Ok(MinerModel::AntMiner(model)),
179                        (_, Ok(model)) => Ok(MinerModel::Braiins(model)),
180                        // errors should all be the same with the same from_str implementation
181                        (Err(am_err), _) => Err(am_err),
182                    }
183                }
184                Some(MinerFirmware::EPic) => {
185                    match (
186                        AntMinerModel::from_str(model_str),
187                        WhatsMinerModel::from_str(model_str),
188                        EPicModel::from_str(model_str),
189                    ) {
190                        (Ok(model), _, _) => Ok(MinerModel::AntMiner(model)),
191                        (_, Ok(model), _) => Ok(MinerModel::WhatsMiner(model)),
192                        (_, _, Ok(model)) => Ok(MinerModel::EPic(model)),
193                        // errors should all be the same with the same from_str implementation
194                        (Err(am_err), _, _) => Err(am_err),
195                    }
196                }
197                Some(MinerFirmware::LuxOS) => match AntMinerModel::from_str(model_str) {
198                    Ok(model) => Ok(MinerModel::AntMiner(model)),
199                    Err(am_err) => Err(am_err),
200                },
201                Some(MinerFirmware::Marathon) => match AntMinerModel::from_str(model_str) {
202                    Ok(model) => Ok(MinerModel::AntMiner(model)),
203                    Err(am_err) => Err(am_err),
204                },
205                Some(MinerFirmware::VNish) => match AntMinerModel::from_str(model_str) {
206                    Ok(model) => Ok(MinerModel::AntMiner(model)),
207                    Err(am_err) => Err(am_err),
208                },
209                Some(MinerFirmware::HiveOS) => match AntMinerModel::from_str(model_str) {
210                    Ok(model) => Ok(MinerModel::AntMiner(model)),
211                    Err(am_err) => Err(am_err),
212                },
213                // Stock is checked by make
214                Some(MinerFirmware::Stock) => unreachable!(),
215                // (None, None) must be checked before this point
216                None => unreachable!(),
217            },
218            // Braiins and EPic must be found via the firmware model check
219            Some(MinerMake::Braiins) => unreachable!(),
220            Some(MinerMake::EPic) => unreachable!(),
221        }
222    }
223}