aiot 0.10.0

Rust Link SDK (Aliyun IoT) based on Alink Protocol.
Documentation
//! 工具类

pub mod auth;
pub mod error;

use crate::{Error, Result};
use lazy_static::lazy_static;
use rand::distributions::Alphanumeric;
use rand::rngs::StdRng;
use rand::Rng;
use rand::SeedableRng;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Mutex;

pub const VERSION: &'static str = std::env!("CARGO_PKG_VERSION");
lazy_static! {
    pub static ref CORE_SDK_VERSION: String = format!("sdk-rust-{}", VERSION);
    static ref RNG: Mutex<StdRng> = Mutex::new(StdRng::seed_from_u64(timestamp()));
    static ref ID_U64: AtomicU64 = AtomicU64::new(0);
}

pub fn hex2str(input: &[u8]) -> String {
    input.iter().map(|c| format!("{:02X}", c)).collect()
}

pub fn str2hex(input: &str) -> Vec<u8> {
    fn c2u(c: u8) -> u8 {
        match c {
            b'0'..=b'9' => c - b'0',
            b'A'..=b'F' => c - b'F' + 0x0A,
            b'a'..=b'f' => c - b'a' + 0x0A,
            _ => 0,
        }
    }
    let mut output = Vec::with_capacity(input.len() / 2);
    let mut iter = input.as_bytes().chunks(2);
    for chunk in iter {
        let a = c2u(chunk[0]);
        let b = c2u(chunk[1]);
        let c = (a << 4) + b;
        output.push(c);
    }
    output
}

pub fn timestamp() -> u64 {
    use std::time::SystemTime;
    if let Ok(t) = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
        t.as_secs()
    } else {
        0
    }
}

pub fn rand_string(len: usize) -> String {
    std::iter::repeat(())
        .map(|()| RNG.lock().unwrap().sample(Alphanumeric))
        .map(char::from)
        .take(len)
        .collect()
}

pub fn rand_u64() -> u64 {
    RNG.lock().unwrap().gen()
}

pub fn inc_u64() -> u64 {
    ID_U64.fetch_add(1, Ordering::SeqCst)
}

pub fn sha256(buffer: &[u8]) -> String {
    use sha2::{Digest, Sha256, Sha512};
    let mut hasher = Sha256::new();
    hasher.update(&buffer);
    let result = hasher.finalize();
    hex2str(&result)
}

pub fn md5(buffer: &[u8]) -> String {
    use md5::{Digest, Md5};
    let mut hasher = Md5::new();
    hasher.update(&buffer);
    let result = hasher.finalize();
    hex2str(&result)
}

pub fn validate(buffer: &[u8], sign_method: &str, sign: &str) -> Result<()> {
    let method = sign_method.to_ascii_lowercase();
    log::debug!("method={}, size={}", method, buffer.len());
    match method.as_str() {
        "sha256" => {
            let result = crate::util::sha256(&buffer);
            if result != sign.to_ascii_uppercase() {
                log::debug!("result:{} sign:{}", result, sign);
                return Err(Error::FileValidateFailed(method));
            }
        }
        "md5" => {
            let result = crate::util::md5(&buffer);
            if result != sign.to_ascii_uppercase() {
                log::debug!("result:{} sign:{}", result, sign);
                return Err(Error::FileValidateFailed(method));
            }
        }
        _ => {
            return Err(Error::FileValidateFailed(method));
        }
    }
    Ok(())
}

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

    #[test]
    fn 十六进制转字符串() {
        let v = vec![0x1, 0x2, 0x3];
        let s = hex2str(&v);
        println!("{}", s);
        let p = str2hex(&s);
        println!("{:x?}", p);
        assert_eq!(&v, &p);
    }
}