use crate::internal::domain::{AuditEventId, LocalUserId};
use serde::{Deserialize, Serialize};
use time::OffsetDateTime;
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum KillSwitchState {
Open,
Closed,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct KillSwitch {
pub state: KillSwitchState,
pub changed_by: LocalUserId,
#[serde(with = "time::serde::rfc3339")]
pub changed_at: OffsetDateTime,
pub reason: String,
pub audit_event_id: Option<AuditEventId>,
}
impl KillSwitch {
#[must_use]
pub fn closed(changed_by: LocalUserId, reason: impl Into<String>) -> Self {
Self {
state: KillSwitchState::Closed,
changed_by,
changed_at: OffsetDateTime::now_utc(),
reason: reason.into(),
audit_event_id: None,
}
}
#[must_use]
pub fn open(changed_by: LocalUserId, reason: impl Into<String>) -> Self {
Self {
state: KillSwitchState::Open,
changed_by,
changed_at: OffsetDateTime::now_utc(),
reason: reason.into(),
audit_event_id: None,
}
}
#[must_use]
pub const fn is_open(&self) -> bool {
matches!(self.state, KillSwitchState::Open)
}
#[must_use]
pub fn with_audit_event_id(mut self, audit_event_id: AuditEventId) -> Self {
self.audit_event_id = Some(audit_event_id);
self
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct KillSwitchStore {
current: KillSwitch,
}
impl KillSwitchStore {
#[must_use]
pub fn new_closed(changed_by: LocalUserId, reason: impl Into<String>) -> Self {
Self {
current: KillSwitch::closed(changed_by, reason),
}
}
#[must_use]
pub const fn current(&self) -> &KillSwitch {
&self.current
}
pub fn set(&mut self, next: KillSwitch) {
self.current = next;
}
pub fn open(&mut self, changed_by: LocalUserId, reason: impl Into<String>) {
self.set(KillSwitch::open(changed_by, reason));
}
pub fn close(&mut self, changed_by: LocalUserId, reason: impl Into<String>) {
self.set(KillSwitch::closed(changed_by, reason));
}
pub fn emergency_disable(&mut self, changed_by: LocalUserId, reason: impl Into<String>) {
self.close(changed_by, reason);
}
}