use std::sync::{Arc, Mutex}; use anyhow::{bail, Result}; use midea::*; use crate::db::DataBase; enum LoginInfo { Cloud { mail: String, password: String }, Token { token: String, key: String }, } impl LoginInfo { const MIDEA_KEY_EMAIL: &'static str = "midea_cloud_mail"; const MIDEA_KEY_PW: &'static str = "midea_cloud_pw"; const MIDEA_KEY_TOKEN: &'static str = "midea_token"; const MIDEA_KEY_KEY: &'static str = "midea_key"; fn new(db: &Arc>, device_id: u64) -> Result { let db_lock = db.lock().unwrap(); let token = db_lock.read_credential(Self::MIDEA_KEY_TOKEN, device_id)?; let key = db_lock.read_credential(Self::MIDEA_KEY_KEY, device_id)?; if token.is_none() || key.is_none() { let mail = db_lock.read_credential(Self::MIDEA_KEY_EMAIL, device_id)?; let pw = db_lock.read_credential(Self::MIDEA_KEY_PW, device_id)?; if mail.is_none() || pw.is_none() { bail!("missing credentials"); } Ok(LoginInfo::Cloud { mail: mail.unwrap(), password: pw.unwrap(), }) } else { Ok(LoginInfo::Token { token: token.unwrap(), key: key.unwrap(), }) } } } pub struct MideaDiscovery { infos: Vec, } impl MideaDiscovery { pub async fn discover() -> Result { Ok(Self { infos: Startup::discover().await?, }) } } pub struct MideaDishwasher { device_info: DeviceInfo, device: Device, } impl MideaDishwasher { pub async fn create(discovery: MideaDiscovery, db: Arc>) -> Result> { let mut v = Vec::new(); for device_info in discovery .infos .into_iter() .filter(|device_info| device_info.device_type == 0xE1) { if let Ok(res) = LoginInfo::new(&db, device_info.id) { let (token, key) = match res { LoginInfo::Cloud { mail, password } => { let mut cloud = Cloud::new(mail, password)?; cloud.login().await?; cloud.keys(device_info.id).await? } LoginInfo::Token { token, key } => (token, key), }; let device = Device::connect(device_info.clone(), &token, &key).await?; v.push(Self { device_info, device, }); } } Ok(v) } }