use std::fmt;
use busylib::model::account::{AccountBackend, AccountInfo, ClientCertType, MqttStatus};
use serde::Serialize;
use crate::reporter::events::CliEvent;
use crate::reporter::events::fields::{Field, field, write_fields};
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct AccountInfoEvent(AccountInfo);
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct AccountStatusEvent {
status: MqttStatus,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct AccountBackendEvent(AccountBackend);
impl AccountInfoEvent {
pub fn new(info: AccountInfo) -> Self {
Self(info)
}
}
impl AccountStatusEvent {
pub fn new(status: MqttStatus) -> Self {
Self { status }
}
}
impl AccountBackendEvent {
pub fn new(backend: AccountBackend) -> Self {
Self(backend)
}
}
impl From<AccountInfoEvent> for CliEvent {
fn from(event: AccountInfoEvent) -> Self {
CliEvent::AccountInfo(event)
}
}
impl From<AccountStatusEvent> for CliEvent {
fn from(event: AccountStatusEvent) -> Self {
CliEvent::AccountStatus(event)
}
}
impl From<AccountBackendEvent> for CliEvent {
fn from(event: AccountBackendEvent) -> Self {
CliEvent::AccountBackend(event)
}
}
impl fmt::Display for AccountInfoEvent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let info = &self.0;
let mut fields = Vec::new();
if let Some(linked) = info.linked {
fields.push(field("linked", linked));
}
if let Some(id) = &info.id {
fields.push(field("id", id));
}
if let Some(email) = &info.email {
fields.push(field("email", email));
}
if let Some(user_id) = &info.user_id {
fields.push(field("user id", user_id));
}
write_fields(f, &fields)
}
}
impl fmt::Display for AccountStatusEvent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(mqtt_status_label(&self.status))
}
}
impl fmt::Display for AccountBackendEvent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let backend = &self.0;
let fields: Vec<Field> = vec![
field("server url", &backend.server_url),
field(
"client cert type",
client_cert_type_label(&backend.client_cert_type),
),
field("ignore server cert", backend.ignore_server_cert),
];
write_fields(f, &fields)
}
}
fn mqtt_status_label(status: &MqttStatus) -> &str {
match status {
MqttStatus::Error => "error",
MqttStatus::Disconnected => "disconnected",
MqttStatus::Connected => "connected",
MqttStatus::Unknown(status) => status,
}
}
fn client_cert_type_label(cert: &ClientCertType) -> &str {
match cert {
ClientCertType::Default => "default",
ClientCertType::Custom => "custom",
ClientCertType::None => "none",
ClientCertType::Unknown(cert) => cert,
}
}
#[cfg(test)]
mod tests {
use serde_json::json;
use super::*;
#[test]
fn leaves_out_account_fields_the_device_does_not_report() {
let event = AccountInfoEvent::new(AccountInfo {
linked: Some(true),
id: Some("ee7857a2".to_string()),
email: None,
user_id: None,
});
assert_eq!(event.to_string(), "linked: true\nid: ee7857a2");
}
#[test]
fn renders_the_cloud_connection_state_bare() {
assert_eq!(
AccountStatusEvent::new(MqttStatus::Connected).to_string(),
"connected"
);
assert_eq!(
AccountStatusEvent::new(MqttStatus::Unknown("reconnecting".to_string())).to_string(),
"reconnecting"
);
}
#[test]
fn renders_the_backend_configuration() {
let event = AccountBackendEvent::new(AccountBackend {
server_url: "default".to_string(),
client_cert_type: ClientCertType::Default,
ignore_server_cert: false,
});
assert_eq!(
event.to_string(),
"server url: default\nclient cert type: default\nignore server cert: false"
);
assert_eq!(
serde_json::to_value(CliEvent::from(event)).unwrap(),
json!({
"event": "account_backend",
"server_url": "default",
"client_cert_type": "default",
"ignore_server_cert": false
})
);
}
}