use crate::{
data::{ConversationInfo, Database, EngineError, DEBUG},
db_connectors::state::delete_state_key,
send::send_to_callback_url,
CsmlBot, CsmlFlow,
};
use chrono::{prelude::Utc, SecondsFormat};
use csml_interpreter::data::{Client, Event, Memory, Message};
use serde_json::{json, map::Map, Value};
use std::env;
pub fn update_current_context(data: &mut ConversationInfo, mem: &[Memory]) {
for elem in mem.iter() {
if let Value::Object(ref mut obj) = data.context.current {
obj.insert(elem.key.to_owned(), elem.value.clone());
}
}
}
pub fn get_event_content(content_type: &str, metadata: &Value) -> Result<String, EngineError> {
match content_type {
file if ["file", "audio", "video", "image", "url"].contains(&file) => {
if let Some(val) = metadata["url"].as_str() {
Ok(val.to_string())
} else {
Err(EngineError::Interpreter(
"no url content in event".to_owned(),
))
}
}
payload if payload == "payload" => {
if let Some(val) = metadata["payload"].as_str() {
Ok(val.to_string())
} else {
Err(EngineError::Interpreter(
"no payload content in event".to_owned(),
))
}
}
text if text == "text" => {
if let Some(val) = metadata["text"].as_str() {
Ok(val.to_string())
} else {
Err(EngineError::Interpreter(
"no text content in event".to_owned(),
))
}
}
flow_trigger if flow_trigger == "flow_trigger" => {
if let Some(val) = metadata["flow_id"].as_str() {
Ok(val.to_string())
} else {
Err(EngineError::Interpreter(
"no flow_id content in event".to_owned(),
))
}
}
content_type => Err(EngineError::Interpreter(format!(
"{} is not a valid content_type",
content_type
))),
}
}
pub fn format_event(json_event: serde_json::Value) -> Result<Event, EngineError> {
let content_type = match json_event["payload"]["content_type"].as_str() {
Some(content_type) => content_type.to_string(),
None => {
return Err(EngineError::Interpreter(
"no content_type in event".to_owned(),
))
}
};
let content = json_event["payload"]["content"].to_owned();
let content_value = get_event_content(&content_type, &content)?;
Ok(Event {
content_type,
content_value,
content,
})
}
pub fn send_msg_to_callback_url(
data: &mut ConversationInfo,
msg: Vec<Message>,
interaction_order: i32,
end: bool,
) {
let messages = messages_formater(data, msg, interaction_order, end);
match env::var(DEBUG) {
Ok(ref var) if var == "true" => {
println!("conversation_end => {}", messages["conversation_end"]);
}
_ => (),
};
match serde_json::to_string(&messages) {
Ok(string) => send_to_callback_url(data, string.as_bytes()),
Err(_err) => (),
};
}
fn add_info_to_message(data: &ConversationInfo, mut msg: Message, interaction_order: i32) -> Value {
let payload = msg.message_to_json();
let mut map_msg: Map<String, Value> = Map::new();
map_msg.insert("payload".to_owned(), payload);
map_msg.insert("interaction_order".to_owned(), json!(interaction_order));
map_msg.insert("conversation_id".to_owned(), json!(data.conversation_id));
map_msg.insert("direction".to_owned(), json!("SEND"));
Value::Object(map_msg)
}
pub fn messages_formater(
data: &mut ConversationInfo,
vec_msg: Vec<Message>,
interaction_order: i32,
end: bool,
) -> Map<String, Value> {
let msgs = vec_msg
.into_iter()
.map(|msg| add_info_to_message(data, msg, interaction_order))
.collect();
let mut map: Map<String, Value> = Map::new();
map.insert("messages".to_owned(), Value::Array(msgs));
map.insert("conversation_end".to_owned(), Value::Bool(end));
map.insert("request_id".to_owned(), json!(data.request_id));
map.insert(
"received_at".to_owned(),
json!(Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true)),
);
map.insert("interaction_id".to_owned(), json!(data.interaction_id));
let mut map_client: Map<String, Value> = Map::new();
map_client.insert("bot_id".to_owned(), json!(data.client.bot_id));
map_client.insert("user_id".to_owned(), json!(data.client.user_id));
map_client.insert("channel_id".to_owned(), json!(data.client.channel_id));
map.insert("client".to_owned(), Value::Object(map_client));
map
}
pub fn get_flow_by_id<'a>(f_id: &str, flows: &'a [CsmlFlow]) -> Result<&'a CsmlFlow, EngineError> {
let id = f_id.to_ascii_lowercase();
match flows
.iter()
.find(|&val| val.id.to_ascii_lowercase() == id || val.name.to_ascii_lowercase() == id)
{
Some(ref f) => Ok(f),
None => Err(EngineError::Interpreter(format!(
"Flow '{}' does not exist",
f_id
))),
}
}
pub fn get_default_flow<'a>(bot: &'a CsmlBot) -> Result<&'a CsmlFlow, EngineError> {
match bot
.flows
.iter()
.find(|&flow| flow.id == bot.default_flow || flow.name == bot.default_flow)
{
Some(flow) => Ok(flow),
None => Err(EngineError::Interpreter(
"The bot's default_flow does not exist".to_owned(),
)),
}
}
pub fn search_flow<'a>(
event: &Event,
bot: &'a CsmlBot,
client: &Client,
db: &mut Database,
) -> Result<&'a CsmlFlow, EngineError> {
match event {
event if event.content_type == "flow_trigger" => {
delete_state_key(&client, "hold", "position", db)?;
get_flow_by_id(&event.content_value, &bot.flows)
}
event => {
for flow in bot.flows.iter() {
for command in flow.commands.iter() {
if &command.to_lowercase() == &event.content_value.to_lowercase() {
delete_state_key(&client, "hold", "position", db)?;
return Ok(flow);
}
}
}
Err(EngineError::Interpreter(format!(
"Flow '{}' does not exist",
event.content_value
)))
}
}
}