use super::Dbi;
use crate::{Error, Result};
use chrono::{DateTime, Utc};
use serde::{de, Deserialize, Serialize};
use std::{fmt, str::FromStr};
use super::Geocode;
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Hotspot {
pub address: String,
pub owner: String,
pub name: Option<String>,
pub added_height: Option<u64>,
pub lat: Option<f64>,
pub lng: Option<f64>,
pub location: Option<String>,
pub mode: HotspotStakingMode,
pub elevation: Option<i32>,
#[serde(deserialize_with = "Dbi::deserialize_option")]
pub gain: Option<Dbi>,
pub geocode: Geocode,
pub nonce: u64,
#[serde(default)]
pub speculative_nonce: u64,
pub reward_scale: Option<f64>,
pub status: Status,
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Status {
pub timestamp: Option<DateTime<Utc>>,
pub status: Option<String>,
pub listen_addrs: Option<Vec<String>>,
pub height: Option<u64>,
}
#[derive(Clone, Serialize, Debug)]
pub enum HotspotStakingMode {
Full,
Light,
DataOnly,
}
impl fmt::Display for HotspotStakingMode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::DataOnly => f.write_str("dataonly"),
Self::Full => f.write_str("full"),
Self::Light => f.write_str("light"),
}
}
}
impl<'de> Deserialize<'de> for HotspotStakingMode {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct HotspotStakingModeVisitor;
impl<'de> de::Visitor<'de> for HotspotStakingModeVisitor {
type Value = HotspotStakingMode;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("full, light, dataonly")
}
fn visit_str<E>(self, value: &str) -> std::result::Result<HotspotStakingMode, E>
where
E: de::Error,
{
match HotspotStakingMode::from_str(value) {
Ok(v) => Ok(v),
Err(_) => Err(de::Error::custom("invalid staking mode")),
}
}
}
deserializer.deserialize_str(HotspotStakingModeVisitor)
}
}
impl FromStr for HotspotStakingMode {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
match s.to_lowercase().as_ref() {
"light" => Ok(Self::Light),
"full" => Ok(Self::Full),
"dataonly" => Ok(Self::DataOnly),
_ => Err(Error::value(s.into())),
}
}
}