matroskin 0.1.0

whatsminer api client lib
Documentation
//! Implement `get.miner.setting` command
//!
//! This command is used to get the miner settings summary.
//!
//! - Command: [GetMinerSettings]
//! - ApiDoc: <https://apidoc.whatsminer.com/#api-Miner-btminer_get_settings>
use core::str;

use serde::{Deserialize, Serialize};
use zeroize::Zeroize;

use crate::{
    command::{Command, CommandLevel},
    error::Result,
    permission::PermissionLevel,
};

/// This command represents the `get.miner.setting` operation.
///
/// It is used to get the miner settings summary.
///
/// - ApiDoc: <https://apidoc.whatsminer.com/#api-Miner-btminer_get_settings>
///
/// # Example
/// ```rust,no_run
/// use matroskin::actor::Actor;
/// use matroskin::command::get_miner_setting::GetMinerSettings;
/// use matroskin::account::Account;
/// use matroskin::password::Password;
///
/// #[tokio::main]
/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
///     let addr = "10.10.10.10:4433";
///     let username = Account::Super;
///     let password = Password::Super;
///
///     let actor = Actor::new(addr, username, password);
///     actor.connect()?;
///
///     let cmd = GetMinerSettings::default();
///     let response = actor.send(cmd).await?;
///     println!("Response: {:#?}", response);
///
///     Ok(())
/// }
/// ```
#[derive(Debug, Default)]
pub struct GetMinerSettings;

/// Represents the power mode of the miner.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize, Default)]
#[serde(rename_all = "lowercase")]
pub enum PowerMode {
    Low,
    #[default]
    Normal,
    High,
    /// Fallback for unknown modes
    #[serde(untagged)]
    Unknown(String),
}

/// [GetMinerSettings] Response
#[derive(Debug, Default, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct GetMinerSettingsResponse {
    pub power_limit: i64,
    pub upfreq_speed: i64,
    pub power_mode: PowerMode,
    #[serde(deserialize_with = "crate::response::deserialize_bool_from_string")]
    pub fast_boot: bool,
    pub target_freq: i64,
    // since 3.0.3v
    #[serde(
        default,
        deserialize_with = "crate::response::deserialize_opt_bool_from_string"
    )]
    pub fast_mining: Option<bool>,
    // since 3.0.3v
    pub power: Option<i64>,
    // since 3.0.3v
    pub power_percent: Option<i64>,
}

impl Command for GetMinerSettings {
    type Response = GetMinerSettingsResponse;
    const CMD_NAME: &'static str = "get.miner.setting";
    const LEVEL: CommandLevel = CommandLevel::Public;
    const MINIMAL_PERMISSIONS: PermissionLevel = PermissionLevel::ReadOnly;

    fn params(&self) -> Result<Option<impl serde::Serialize>> {
        Ok(None::<()>)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    const RESPONSE_JSON: &str = r#"{"code":0,"when":1692858102,"msg":{"power-limit":3500,"upfreq-speed":0,"power-mode":"normal","fast-boot":"disable","target-freq":0,"fast-mining":"disable","power":3500,"power-percent":0},"desc":"get.miner.setting"}"#;

    #[test]
    fn request_no_params_no_auth() {
        let cmd = GetMinerSettings;
        let encoded = cmd.encode(None).unwrap();
        let json: serde_json::Value = serde_json::from_slice(&encoded.0).unwrap();
        assert_eq!(json["cmd"], "get.miner.setting");
        assert!(json.get("param").is_none());
        assert!(json.get("token").is_none());
    }

    #[test]
    fn deserialize_response_fixture() {
        let response = GetMinerSettings::parse_response(RESPONSE_JSON.as_bytes()).unwrap();
        assert!(response.code.is_success());
        assert_eq!(response.desc, "get.miner.setting");
        assert_eq!(response.when, 1692858102);
        assert_eq!(response.msg.power_limit, 3500);
        assert_eq!(response.msg.power_mode, PowerMode::Normal);
        assert!(!response.msg.fast_boot);
        assert_eq!(response.msg.target_freq, 0);
        assert_eq!(response.msg.fast_mining, Some(false));
        assert_eq!(response.msg.power, Some(3500));
        assert_eq!(response.msg.power_percent, Some(0));
    }
}