use std::fmt;
use std::time::Duration;
use http::StatusCode;
use serde::Deserialize;
use serde_json::Value;
use url::Url;
pub mod auth;
pub mod devices;
pub mod events;
pub mod ifttt;
pub mod ir;
pub mod linkages;
pub mod networking;
pub mod ota;
pub mod positions;
pub mod push;
pub mod resources;
pub mod scenes;
pub mod voice;
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct SecretString(String);
impl SecretString {
pub fn new(value: impl Into<String>) -> Self {
Self(value.into())
}
pub fn expose(&self) -> &str {
&self.0
}
}
impl fmt::Debug for SecretString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("[REDACTED]")
}
}
impl fmt::Display for SecretString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("[REDACTED]")
}
}
#[derive(Clone)]
pub struct Credentials {
app_id: String,
key_id: String,
app_key: SecretString,
}
impl Credentials {
pub fn new(
app_id: impl Into<String>,
key_id: impl Into<String>,
app_key: impl Into<String>,
) -> Self {
Self {
app_id: app_id.into(),
key_id: key_id.into(),
app_key: SecretString::new(app_key),
}
}
pub fn app_id(&self) -> &str {
&self.app_id
}
pub fn key_id(&self) -> &str {
&self.key_id
}
pub fn app_key(&self) -> &SecretString {
&self.app_key
}
}
impl fmt::Debug for Credentials {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Credentials")
.field("app_id", &self.app_id)
.field("key_id", &self.key_id)
.field("app_key", &self.app_key)
.finish()
}
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub enum Endpoint {
China,
Usa,
Europe,
Korea,
Russia,
Singapore,
Custom(Url),
}
impl Endpoint {
pub(crate) fn base_url_str(&self) -> Option<&'static str> {
match self {
Self::China => Some("https://open-cn.aqara.com/v3.0/open/api"),
Self::Usa => Some("https://open-usa.aqara.com/v3.0/open/api"),
Self::Europe => Some("https://open-ger.aqara.com/v3.0/open/api"),
Self::Korea => Some("https://open-kr.aqara.com/v3.0/open/api"),
Self::Russia => Some("https://open-ru.aqara.com/v3.0/open/api"),
Self::Singapore => Some("https://open-sg.aqara.com/v3.0/open/api"),
Self::Custom(_) => None,
}
}
pub(crate) fn custom_url(&self) -> Option<&Url> {
match self {
Self::Custom(url) => Some(url),
_ => None,
}
}
}
#[derive(Clone, Copy, Debug)]
#[non_exhaustive]
pub struct TimeoutConfig {
pub connect: Option<Duration>,
pub request: Option<Duration>,
pub read: Option<Duration>,
}
impl Default for TimeoutConfig {
fn default() -> Self {
Self {
connect: Some(Duration::from_secs(10)),
request: Some(Duration::from_secs(30)),
read: Some(Duration::from_secs(30)),
}
}
}
impl TimeoutConfig {
pub fn new(
connect: Option<Duration>,
request: Option<Duration>,
read: Option<Duration>,
) -> Self {
Self {
connect,
request,
read,
}
}
}
#[derive(Clone, Copy, Debug)]
#[non_exhaustive]
pub struct RetryConfig {
pub max_retries: u32,
pub base_delay: Duration,
pub max_delay: Duration,
}
impl Default for RetryConfig {
fn default() -> Self {
Self {
max_retries: 3,
base_delay: Duration::from_millis(200),
max_delay: Duration::from_secs(2),
}
}
}
impl RetryConfig {
pub fn new(max_retries: u32, base_delay: Duration, max_delay: Duration) -> Self {
Self {
max_retries,
base_delay,
max_delay,
}
}
}
#[derive(Clone, Copy, Debug)]
#[non_exhaustive]
pub struct BodySnippetConfig {
pub enabled: bool,
pub max_len: usize,
}
impl Default for BodySnippetConfig {
fn default() -> Self {
Self {
enabled: true,
max_len: 2048,
}
}
}
impl BodySnippetConfig {
pub fn new(enabled: bool, max_len: usize) -> Self {
Self { enabled, max_len }
}
}
#[derive(Clone, Copy, Debug)]
#[non_exhaustive]
pub struct CallOptions {
pub include_access_token: bool,
pub idempotent: bool,
}
impl CallOptions {
pub fn with_access_token() -> Self {
Self {
include_access_token: true,
idempotent: false,
}
}
pub fn without_access_token() -> Self {
Self {
include_access_token: false,
idempotent: false,
}
}
pub fn idempotent(mut self, idempotent: bool) -> Self {
self.idempotent = idempotent;
self
}
}
#[derive(Debug, Deserialize)]
#[non_exhaustive]
pub struct AqaraEnvelope<T> {
pub code: i64,
#[serde(rename = "requestId", alias = "request_id")]
pub request_id: String,
#[serde(alias = "msg")]
pub message: String,
#[serde(default)]
pub result: Option<T>,
}
#[derive(Debug)]
#[non_exhaustive]
pub struct AqaraResponse<T> {
pub status: StatusCode,
pub envelope: AqaraEnvelope<T>,
}
impl<T> AqaraResponse<T> {
pub fn request_id(&self) -> &str {
&self.envelope.request_id
}
pub fn message(&self) -> &str {
&self.envelope.message
}
pub fn result(&self) -> Option<&T> {
self.envelope.result.as_ref()
}
}
pub type AqaraValueResponse = AqaraResponse<Value>;