use std::collections::HashSet;
use myko_rs::item::Eventable;
use myko_rs::message::MykoMessage;
use rship_entities::{
action::Action,
target::Target,
target_status::{Status, TargetStatus},
};
use schemars::JsonSchema;
use serde::{de::DeserializeOwned, Serialize};
use tokio_stream::StreamExt;
use crate::{
action::{ActionArgs, ActionProxy},
client::SdkClient,
emitter::{EmitterArgs, EmitterProxy},
instance::InstanceProxy,
types::SdkCommands,
};
#[derive(Clone)]
pub struct TargetArgs {
pub name: String,
pub short_id: String,
pub category: String,
pub parent_targets: Option<Vec<TargetProxy>>,
}
#[derive(Clone)]
pub struct TargetProxy {
pub(crate) instance: InstanceProxy,
pub(crate) args: TargetArgs,
pub(crate) client: SdkClient,
pub(crate) emitters: HashSet<String>,
pub(crate) actions: HashSet<String>,
}
impl TargetProxy {
pub async fn add_emitter<T: JsonSchema + Serialize + Clone>(
&mut self,
args: EmitterArgs<T>,
) -> EmitterProxy<T> {
let p = EmitterProxy {
target: self.clone(),
args,
client: self.client.clone(),
};
p.save().await;
self.emitters.insert(p.id().clone());
self.save(Status::Online).await;
p
}
pub async fn rename(&mut self, name: String) {
if name == self.args.name {
return;
}
self.args.name = name.clone();
self.save(Status::Online).await;
}
pub async fn add_action<T: DeserializeOwned + JsonSchema>(
&mut self,
args: ActionArgs<T>,
handler: impl (Fn(&Action, T)) + Send + 'static,
) -> ActionProxy<T> {
let p = ActionProxy {
args,
client: self.client.clone(),
target: self.clone(),
};
let mut rcv = self.client.client.get_messages();
let handler_id = p.id().clone();
tokio::spawn(async move {
println!("Action handler started");
while let Some(msg) = rcv.next().await {
let command = serde_json::from_value::<MykoMessage<SdkCommands>>(msg.clone());
match command {
Ok(MykoMessage::Command(SdkCommands::ExecTargetAction(exec_target_action))) => {
if exec_target_action.action.id() != handler_id {
continue;
}
match serde_json::from_value::<T>(exec_target_action.data) {
Ok(data) => {
handler(&exec_target_action.action, data);
}
Err(e) => {
println!("Could not parse data: {:?}", e);
}
}
}
Err(_e) => {
}
_ => {}
}
}
println!("Action handler exited");
});
p.save().await;
self.actions.insert(p.id().clone());
self.save(Status::Online).await;
p
}
pub async fn save(&self, status: Status) {
let parent_ids: Vec<String> = match &self.args.parent_targets {
Some(ids) => ids.clone(),
None => vec![],
}
.iter()
.map(|x| x.id())
.collect();
let target = Target {
name: self.args.name.clone(),
id: self.id(),
category: self.args.category.clone(),
action_ids: self.actions.iter().cloned().collect(),
emitter_ids: self.emitters.iter().cloned().collect(),
bg_color: self.instance.args.color.clone(),
fg_color: self.instance.args.color.clone(),
hash: uuid::Uuid::new_v4().to_string(),
parent_targets: parent_ids.clone(),
root_level: parent_ids.is_empty(),
service_id: self.instance.args.service_id.clone(),
sub_targets: vec![],
};
let status = TargetStatus {
id: format!("{}:{}", self.instance.args.short_id, self.args.short_id),
target_id: self.id(),
status,
instance_id: self.instance.args.short_id.clone(),
hash: uuid::Uuid::new_v4().to_string(),
};
if let Err(err) = self.client.save_item(&target).await {
println!("Could not save target: {}", err);
}
if let Err(err) = self.client.save_item(&status).await {
println!("Could not save target status: {}", err);
}
}
pub(crate) fn id(&self) -> String {
format!("{}:{}", self.instance.args.service_id, self.args.short_id)
}
pub async fn set_status(&self, status: Status) {
self.save(status).await;
}
}