scatterbrain 0.0.1

API for controlling a Scatterbrain Router android application from desktop apps
Documentation
use std::{collections::HashMap, fmt};

use chrono::Utc;
use serde::{ser::Error, Deserialize, Serialize};
use uuid::Uuid;

pub use crate::{
    api::proto::{ApiMessage, IdentityResponse, MessageResponse, RespCode},
    error::{Error as CrateError, SbResult},
    serialize::ToUuid,
};

pub trait PrettyPrint {
    fn print_output(&self) -> SbResult<String>;
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Identity {
    pub fingerprint: Option<Uuid>,
    pub name: String,
    pub public_key: Vec<u8>,
    pub is_owned: bool,
    pub extra: HashMap<String, Vec<u8>>,
    pub sig: Vec<u8>,
}

impl PrettyPrint for Vec<Identity> {
    fn print_output(&self) -> SbResult<String> {
        let s = serde_json::to_string_pretty(self)?;

        Ok(s)
    }
}

impl fmt::Display for Identity {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let s =
            serde_json::to_string_pretty(self).map_err(|e| fmt::Error::custom(e.to_string()))?;
        f.write_str(&s)
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Message {
    pub from_fingerprint: Option<Uuid>,
    pub to_fingerprint: Option<Uuid>,
    pub application: String,
    pub extension: String,
    pub mime: String,
    pub send_date: i64,
    pub receive_date: i64,
    pub is_file: bool,
    pub id: Option<Uuid>,
    pub body: Vec<u8>,
    pub file_name: String,
}

impl Message {
    pub fn from_vec(body: Vec<u8>, application: String) -> Message {
        Message {
            from_fingerprint: None,
            to_fingerprint: None,
            application,
            extension: "".to_owned(),
            mime: "application/octet-stream".to_owned(),
            send_date: Utc::now().timestamp(),
            receive_date: Utc::now().timestamp(),
            is_file: false,
            id: None,
            body,
            file_name: "".to_owned(),
        }
    }
}

impl fmt::Display for Message {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let s =
            serde_json::to_string_pretty(self).map_err(|e| fmt::Error::custom(e.to_string()))?;
        f.write_str(&s)
    }
}

impl PrettyPrint for Vec<Message> {
    fn print_output(&self) -> SbResult<String> {
        let s = serde_json::to_string_pretty(self)?;

        Ok(s)
    }
}

impl TryFrom<IdentityResponse> for Vec<Identity> {
    type Error = CrateError;
    fn try_from(value: IdentityResponse) -> std::result::Result<Self, Self::Error> {
        if let RespCode::Ok = value.code.try_into()? {
            Ok(value
                .identity
                .into_iter()
                .map(|v| Identity {
                    fingerprint: v.fingerprint.map(|v| v.as_uuid()),
                    name: v.name,
                    public_key: v.public_key,
                    is_owned: v.is_owned,
                    extra: v.extra,
                    sig: v.sig,
                })
                .collect())
        } else {
            Err(CrateError::RemoteError(value.code.to_string()))
        }
    }
}

impl TryFrom<MessageResponse> for Vec<Message> {
    type Error = CrateError;
    fn try_from(value: MessageResponse) -> std::result::Result<Self, Self::Error> {
        if let RespCode::Ok = value.code.try_into()? {
            Ok(value
                .messsage
                .into_iter()
                .map(|v| Message {
                    from_fingerprint: v.from_fingerprint.map(|v| v.as_uuid()),
                    to_fingerprint: v.to_fingerprint.map(|v| v.as_uuid()),
                    application: v.application,
                    mime: v.mime,
                    extension: v.extension,
                    send_date: v.send_date,
                    receive_date: v.receive_date,
                    is_file: v.is_file,
                    id: v.id.map(|v| v.as_uuid()),
                    body: v.body,
                    file_name: v.file_name,
                })
                .collect())
        } else {
            Err(CrateError::RemoteError(value.code.to_string()))
        }
    }
}

impl From<Message> for ApiMessage {
    fn from(v: Message) -> Self {
        ApiMessage {
            from_fingerprint: v.from_fingerprint.map(|v| v.as_proto()),
            to_fingerprint: v.to_fingerprint.map(|v| v.as_proto()),
            application: v.application,
            mime: v.mime,
            extension: v.extension,
            send_date: v.send_date,
            receive_date: v.receive_date,
            is_file: v.is_file,
            id: v.id.map(|v| v.as_proto()),
            body: v.body,
            file_name: v.file_name,
        }
    }
}

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

    #[test]
    fn from_vec() {
        let v = vec![1, 2, 3];
        let m = Message::from_vec(v, "newsnet".to_owned());
    }
}