use json::JsonValue;
use std::thread;
use std::time::Duration;
use urbit_http_api::{default_cli_ship_interface_setup, Node, ShipInterface};
pub use urbit_http_api::{AuthoredMessage, Message};
pub struct Chatbot {
respond_to_message: fn(AuthoredMessage) -> Option<Message>,
ship: ShipInterface,
chat_ship: String,
chat_name: String,
}
impl Chatbot {
pub fn new(
respond_to_message: fn(AuthoredMessage) -> Option<Message>,
ship: ShipInterface,
chat_ship: &str,
chat_name: &str,
) -> Self {
Chatbot {
respond_to_message: respond_to_message,
ship: ship,
chat_ship: chat_ship.to_string(),
chat_name: chat_name.to_string(),
}
}
pub fn new_with_local_config(
respond_to_message: fn(AuthoredMessage) -> Option<Message>,
chat_ship: &str,
chat_name: &str,
) -> Self {
let ship = default_cli_ship_interface_setup();
Self::new(respond_to_message, ship, chat_ship, chat_name)
}
pub fn run(&self) -> Option<()> {
println!("=======================================\nPowered By The Urbit Chatbot Framework\n=======================================");
let channel = &mut self.ship.create_channel().ok()?;
channel
.create_new_subscription("graph-store", "/updates")
.ok()?;
loop {
channel.parse_event_messages();
let graph_updates = &mut channel.find_subscription("graph-store", "/updates")?;
let mut messages_to_send = vec![];
loop {
let pop_res = graph_updates.pop_message();
if let Some(mess) = &pop_res {
if let Ok(json) = json::parse(mess) {
if !self.check_resource_json(&json) {
continue;
}
if let Ok(node) = Node::from_graph_update_json(&json) {
if node.author == self.ship.ship_name {
continue;
}
let authored_message = AuthoredMessage::new(
&node.author,
&node.contents,
&node.time_sent_formatted(),
&node.index,
);
if let Some(message) = (self.respond_to_message)(authored_message) {
println!("Replied to message.");
messages_to_send.push(message)
} else {
println!("Message ignored.")
}
}
}
}
if let None = &pop_res {
break;
}
}
for message in messages_to_send {
channel
.chat()
.send_chat_message(&self.chat_ship, &self.chat_name, &message)
.ok();
}
thread::sleep(Duration::new(0, 500000000));
}
}
fn check_resource_json(&self, resource_json: &JsonValue) -> bool {
let resource = resource_json["graph-update"]["add-nodes"]["resource"].clone();
let chat_name = format!("{}", resource["name"]);
let chat_ship = format!("~{}", resource["ship"]);
if chat_name == self.chat_name && chat_ship == self.chat_ship {
return true;
}
false
}
}