use crate::{Actor, ActorBehavior, Message, Port};
use anyhow::{Error, Result};
use reflow_actor::{message::EncodableValue, ActorContext};
use reflow_actor_macro::actor;
use serde_json::json;
use std::collections::HashMap;
#[actor(
ServerRequestActor,
inports::<1>(),
outports::<50>(body, headers, params, method, url),
state(MemoryState)
)]
pub async fn server_request_actor(ctx: ActorContext) -> Result<HashMap<String, Message>, Error> {
let config = ctx.get_config_hashmap();
let mut out = HashMap::new();
if let Some(body) = config.get("body") {
out.insert(
"body".to_string(),
Message::object(EncodableValue::from(body.clone())),
);
} else {
out.insert(
"body".to_string(),
Message::object(EncodableValue::from(json!({}))),
);
}
if let Some(headers) = config.get("headers") {
out.insert(
"headers".to_string(),
Message::object(EncodableValue::from(headers.clone())),
);
}
if let Some(params) = config.get("query").or(config.get("params")) {
out.insert(
"params".to_string(),
Message::object(EncodableValue::from(params.clone())),
);
}
let method = config
.get("method")
.and_then(|v| v.as_str())
.unwrap_or("POST");
out.insert(
"method".to_string(),
Message::String(method.to_string().into()),
);
let path = config
.get("path")
.and_then(|v| v.as_str())
.unwrap_or("/webhook");
out.insert("url".to_string(), Message::String(path.to_string().into()));
Ok(out)
}
#[actor(
ServerResponseActor,
inports::<10>(body, status, headers),
outports::<1>(response),
state(MemoryState)
)]
pub async fn server_response_actor(ctx: ActorContext) -> Result<HashMap<String, Message>, Error> {
let payload = ctx.get_payload();
let config = ctx.get_config_hashmap();
let status = match payload.get("status") {
Some(Message::Integer(v)) => *v as u16,
_ => config
.get("statusCode")
.and_then(|v| v.as_u64())
.unwrap_or(200) as u16,
};
let content_type = config
.get("contentType")
.and_then(|v| v.as_str())
.unwrap_or("application/json");
let body = payload
.get("body")
.cloned()
.unwrap_or(Message::object(EncodableValue::from(json!({}))));
let body_json = match &body {
Message::String(s) => json!(s.as_ref()),
Message::Object(o) => {
let v: serde_json::Value = o.as_ref().clone().into();
v
}
Message::Integer(i) => json!(i),
Message::Float(f) => json!(f),
Message::Boolean(b) => json!(b),
_ => json!(null),
};
let response = json!({
"statusCode": status,
"contentType": content_type,
"body": body_json,
});
Ok([(
"response".to_string(),
Message::object(EncodableValue::from(response)),
)]
.into())
}