use serde::{Deserialize, Serialize};
use crate::ocpi_enum;
use crate::types::validate_fields;
use crate::types::{CountryCode, DateTime, Extensions, PartyId, PartyRef, Validate, Validator};
use super::types::Role;
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
pub struct ClientInfo {
pub party_id: PartyId,
pub country_code: CountryCode,
pub role: Role,
pub status: ConnectionStatus,
pub last_updated: DateTime,
#[serde(flatten, default, skip_serializing_if = "Extensions::is_empty")]
pub extensions: Extensions,
}
impl ClientInfo {
#[must_use]
pub fn new(party: PartyRef, role: Role, status: ConnectionStatus, last_updated: DateTime) -> Self {
Self {
party_id: party.party_id,
country_code: party.country_code,
role,
status,
last_updated,
extensions: Extensions::new(),
}
}
#[must_use]
pub fn party(&self) -> PartyRef {
PartyRef { country_code: self.country_code.clone(), party_id: self.party_id.clone() }
}
#[must_use]
pub fn is_reachable(&self) -> bool {
self.status == ConnectionStatus::Connected
}
}
impl Validate for ClientInfo {
fn validate_in(&self, v: &mut Validator) {
validate_fields!(self, v, party_id, country_code, role, status, last_updated);
}
}
ocpi_enum! {
pub enum ConnectionStatus {
Connected = "CONNECTED",
Offline = "OFFLINE",
Planned = "PLANNED",
Suspended = "SUSPENDED",
}
}
impl ConnectionStatus {
#[must_use]
pub const fn should_poll(self) -> bool {
matches!(self, Self::Connected | Self::Offline)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn only_connected_parties_are_reachable() {
let info = ClientInfo::new(
PartyRef::new("NL", "TNM").unwrap(),
Role::Cpo,
ConnectionStatus::Offline,
"2019-06-24T12:39:09Z".parse().unwrap(),
);
assert!(!info.is_reachable());
assert!(info.status.should_poll(), "an offline party may come back");
assert!(!ConnectionStatus::Suspended.should_poll());
assert!(!ConnectionStatus::Planned.should_poll());
}
#[test]
fn round_trips_the_spec_shape() {
let json = r#"{"party_id":"TNM","country_code":"NL","role":"CPO","status":"CONNECTED","last_updated":"2019-06-24T12:39:09Z"}"#;
let info: ClientInfo = serde_json::from_str(json).unwrap();
assert_eq!(info.party(), PartyRef::new("NL", "TNM").unwrap());
assert_eq!(serde_json::to_string(&info).unwrap(), json);
}
}