use crate::{Actor, ActorBehavior, Message, Port};
use anyhow::{Error, Result};
use reflow_actor::{message::EncodableValue, ActorContext};
use reflow_actor_macro::actor;
use reflow_assets::get_or_create_db;
use serde_json::{json, Value};
use std::collections::HashMap;
#[actor(
ComponentNodeActor,
inports::<10>(entity, data),
outports::<1>(output, metadata),
state(MemoryState)
)]
pub async fn component_node_actor(ctx: ActorContext) -> Result<HashMap<String, Message>, Error> {
let payload = ctx.get_payload();
let config = ctx.get_config_hashmap();
let component_name = config
.get("$name")
.and_then(|v| v.as_str())
.unwrap_or("generic");
let db_path = config
.get("$db")
.and_then(|v| v.as_str())
.unwrap_or("./assets.db");
let mut component_data = serde_json::Map::new();
for (key, val) in &config {
if !key.starts_with('$') {
component_data.insert(key.clone(), val.clone());
}
}
if let Some(Message::Object(obj)) = payload.get("data") {
let v: Value = obj.as_ref().clone().into();
if let Value::Object(map) = v {
for (k, v) in map {
component_data.insert(k, v);
}
}
}
let data_value = Value::Object(component_data);
let entity = match payload.get("entity") {
Some(Message::String(s)) => Some(s.to_string()),
_ => config
.get("entity")
.and_then(|v| v.as_str())
.map(|s| s.to_string()),
};
if let Some(ref entity_name) = entity {
let db = get_or_create_db(db_path)?;
db.set_component_json(entity_name, component_name, data_value.clone(), json!({}))?;
}
let mut out = HashMap::new();
out.insert(
"output".to_string(),
Message::object(EncodableValue::from(json!({
"name": component_name,
"data": data_value,
}))),
);
out.insert(
"metadata".to_string(),
Message::object(EncodableValue::from(json!({
"component": component_name,
"entity": entity,
}))),
);
Ok(out)
}