use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fmt;
use time::OffsetDateTime;
use tokio::sync::mpsc;
use tokio::sync::oneshot;
pub type ActorResult<T> = std::result::Result<T, ActorError>;
#[derive(Debug, Clone)]
pub struct ActorError {
pub reason: String,
}
impl fmt::Display for ActorError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "bad actor state: {}", self.reason)
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Observations {
pub datetime: String,
pub values: HashMap<i32, f64>,
pub path: String,
}
#[derive(Debug)]
pub struct Envelope {
pub message: Message,
pub respond_to: Option<oneshot::Sender<ActorResult<Message>>>,
pub datetime: OffsetDateTime,
pub stream_to: Option<mpsc::Sender<Message>>,
pub stream_from: Option<mpsc::Receiver<Message>>,
}
#[derive(Debug, Clone)]
pub enum Message {
Query {
path: String,
},
Update {
datetime: OffsetDateTime,
path: String,
values: HashMap<i32, f64>,
},
StateReport {
datetime: OffsetDateTime,
path: String,
values: HashMap<i32, f64>,
},
EndOfStream {},
InitCmd {},
LoadCmd {
path: String,
},
ReadAllCmd {},
PrintOneCmd {
text: String,
},
}
impl Default for Envelope {
fn default() -> Self {
Self {
message: Message::ReadAllCmd {},
respond_to: None,
datetime: OffsetDateTime::now_utc(),
stream_to: None,
stream_from: None,
}
}
}
struct LifeCycleBuilder {
load_from: Option<mpsc::Receiver<Message>>,
send_to: Option<mpsc::Sender<Message>>,
send_to_path: Option<String>,
respond_to: Option<oneshot::Sender<ActorResult<Message>>>,
}
impl LifeCycleBuilder {
const fn new() -> Self {
Self {
load_from: None,
send_to: None,
send_to_path: None,
respond_to: None,
}
}
fn with_respond_to(mut self, respond_to: oneshot::Sender<ActorResult<Message>>) -> Self {
self.respond_to = Some(respond_to);
self
}
fn with_load_from(mut self, load_from: mpsc::Receiver<Message>) -> Self {
self.load_from = Some(load_from);
self
}
fn with_send_to(mut self, send_to: mpsc::Sender<Message>, send_to_path: String) -> Self {
self.send_to = Some(send_to);
self.send_to_path = Some(send_to_path);
self
}
fn build(self) -> (Envelope, Envelope) {
(
Envelope {
datetime: OffsetDateTime::now_utc(),
respond_to: self.respond_to,
stream_from: self.load_from,
stream_to: None,
message: Message::InitCmd {},
},
Envelope {
datetime: OffsetDateTime::now_utc(),
respond_to: None,
stream_from: None,
stream_to: self.send_to,
message: Message::LoadCmd {
path: self.send_to_path.unwrap_or_default(),
},
},
)
}
}
#[must_use]
pub fn create_init_lifecycle(
path: String,
bufsz: usize,
respond_to: oneshot::Sender<ActorResult<Message>>,
) -> (Envelope, Envelope) {
let (tx, rx) = mpsc::channel(bufsz);
let builder = LifeCycleBuilder::new()
.with_load_from(rx)
.with_send_to(tx, path)
.with_respond_to(respond_to);
builder.build()
}