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 MessageEnvelope {
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 MessageEnvelope {
fn default() -> Self {
MessageEnvelope {
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 {
fn new() -> LifeCycleBuilder {
LifeCycleBuilder {
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>>,
) -> LifeCycleBuilder {
self.respond_to = Some(respond_to);
self
}
fn with_load_from(mut self, load_from: mpsc::Receiver<Message>) -> LifeCycleBuilder {
self.load_from = Some(load_from);
self
}
fn with_send_to(
mut self,
send_to: mpsc::Sender<Message>,
send_to_path: String,
) -> LifeCycleBuilder {
self.send_to = Some(send_to);
self.send_to_path = Some(send_to_path);
self
}
fn build(self) -> (MessageEnvelope, MessageEnvelope) {
(
MessageEnvelope {
datetime: OffsetDateTime::now_utc(),
respond_to: self.respond_to,
stream_from: self.load_from,
stream_to: None,
message: Message::InitCmd {},
},
MessageEnvelope {
datetime: OffsetDateTime::now_utc(),
respond_to: None,
stream_from: None,
stream_to: self.send_to,
message: Message::LoadCmd {
path: self.send_to_path.unwrap(),
},
},
)
}
}
pub fn create_init_lifecycle(
path: String,
bufsz: usize,
respond_to: oneshot::Sender<ActorResult<Message>>,
) -> (MessageEnvelope, MessageEnvelope) {
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()
}