asic_rs/miners/backends/epic/
web.rs1use crate::miners::{
2 api::{APIClient, WebAPIClient},
3 commands::MinerCommand,
4};
5use anyhow::{Result, anyhow};
6use async_trait::async_trait;
7use reqwest::{Client, Method, Response};
8use serde_json::{Value, json};
9use std::{net::IpAddr, time::Duration};
10
11#[derive(Debug)]
14pub struct PowerPlayWebAPI {
15 client: Client,
16 pub ip: IpAddr,
17 port: u16,
18 timeout: Duration,
19 password: Option<String>,
20}
21
22#[async_trait]
23impl APIClient for PowerPlayWebAPI {
24 async fn get_api_result(&self, command: &MinerCommand) -> Result<Value> {
25 match command {
26 MinerCommand::WebAPI {
27 command,
28 parameters,
29 } => self
30 .send_command(command, false, parameters.clone(), Method::GET)
31 .await
32 .map_err(|e| anyhow!(e.to_string())),
33 _ => Err(anyhow!("Cannot send non web command to web API")),
34 }
35 }
36}
37
38#[async_trait]
39impl WebAPIClient for PowerPlayWebAPI {
40 async fn send_command(
42 &self,
43 command: &str,
44 _privileged: bool,
45 parameters: Option<Value>,
46 method: Method,
47 ) -> Result<Value> {
48 let url = format!("http://{}:{}/{}", self.ip, self.port, command);
49
50 let response = self
51 .execute_request(&url, &method, parameters.clone())
52 .await?;
53
54 let status = response.status();
55 if status.is_success() {
56 let json_data = response
57 .json()
58 .await
59 .map_err(|e| PowerPlayError::ParseError(e.to_string()))?;
60 Ok(json_data)
61 } else {
62 Err(PowerPlayError::HttpError(status.as_u16()))?
63 }
64 }
65}
66
67impl PowerPlayWebAPI {
68 pub fn new(ip: IpAddr, port: u16) -> Self {
70 let client = Client::builder()
71 .timeout(Duration::from_secs(10))
72 .build()
73 .expect("Failed to create HTTP client");
74
75 Self {
76 client,
77 ip,
78 port,
79 timeout: Duration::from_secs(5),
80 password: Some("letmein".to_string()), }
82 }
83
84 async fn execute_request(
86 &self,
87 url: &str,
88 method: &Method,
89 parameters: Option<Value>,
90 ) -> Result<Response, PowerPlayError> {
91 let request_builder = match *method {
92 Method::GET => self.client.get(url),
93 Method::POST => self.client.post(url).json(&{
94 let mut p = parameters.unwrap_or_else(|| json!({}));
95 p.as_object_mut().map(|m| {
96 m.insert(
97 "password".into(),
98 Value::String(self.password.clone().unwrap_or_else(|| "letmein".into())),
99 )
100 });
101 p
102 }),
103 _ => return Err(PowerPlayError::UnsupportedMethod(method.to_string())),
104 };
105
106 let request_builder = request_builder.timeout(self.timeout);
107
108 let request = request_builder
109 .build()
110 .map_err(|e| PowerPlayError::RequestError(e.to_string()))?;
111
112 let response = self
113 .client
114 .execute(request)
115 .await
116 .map_err(|e| PowerPlayError::NetworkError(e.to_string()))?;
117
118 Ok(response)
119 }
120}
121
122#[derive(Debug, Clone)]
124pub enum PowerPlayError {
125 NetworkError(String),
127 HttpError(u16),
129 ParseError(String),
131 RequestError(String),
133 Timeout,
135 UnsupportedMethod(String),
137 MaxRetriesExceeded,
139 AuthenticationFailed,
141 Unauthorized,
143}
144
145impl std::fmt::Display for PowerPlayError {
146 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
147 match self {
148 PowerPlayError::NetworkError(msg) => write!(f, "Network error: {msg}"),
149 PowerPlayError::HttpError(code) => write!(f, "HTTP error: {code}"),
150 PowerPlayError::ParseError(msg) => write!(f, "Parse error: {msg}"),
151 PowerPlayError::RequestError(msg) => write!(f, "Request error: {msg}"),
152 PowerPlayError::Timeout => write!(f, "Request timeout"),
153 PowerPlayError::UnsupportedMethod(method) => write!(f, "Unsupported method: {method}"),
154 PowerPlayError::MaxRetriesExceeded => write!(f, "Maximum retries exceeded"),
155 PowerPlayError::AuthenticationFailed => write!(f, "Authentication failed"),
156 PowerPlayError::Unauthorized => write!(f, "Unauthorized access"),
157 }
158 }
159}
160
161impl std::error::Error for PowerPlayError {}