use crate::graph::NodeContents;
use crate::{Channel, Node, Result, UrbitAPIError};
use crossbeam::channel::{unbounded, Receiver};
use json::JsonValue;
use std::thread;
use std::time::Duration;
pub struct Chat<'a> {
pub channel: &'a mut Channel,
}
pub type Message = NodeContents;
#[derive(Clone, Debug)]
pub struct AuthoredMessage {
pub author: String,
pub message: Message,
}
impl AuthoredMessage {
pub fn new(author: String, message: Message) -> Self {
AuthoredMessage {
author: author,
message: message,
}
}
}
impl<'a> Chat<'a> {
pub fn send_message(
&mut self,
chat_ship: &str,
chat_name: &str,
message: &Message,
) -> Result<String> {
let node = self.channel.graph_store().new_node(message);
if let Ok(_) = self
.channel
.graph_store()
.add_node(chat_ship, chat_name, &node)
{
Ok(node.index)
} else {
Err(UrbitAPIError::FailedToSendChatMessage(
message.to_json().dump(),
))
}
}
pub fn export_chat_log(&mut self, chat_ship: &str, chat_name: &str) -> Result<Vec<String>> {
let chat_graph = &self.channel.graph_store().get_graph(chat_ship, chat_name)?;
let mut export_log = vec![];
let mut nodes = chat_graph.clone().nodes;
nodes.sort_by(|a, b| a.time_sent.cmp(&b.time_sent));
for node in nodes {
if !node.contents.is_empty() {
export_log.push(node.to_formatted_string());
}
}
Ok(export_log)
}
pub fn subscribe_to_chat(
&mut self,
chat_ship: &str,
chat_name: &str,
) -> Result<Receiver<AuthoredMessage>> {
let chat_ship = chat_ship.to_string();
let chat_name = chat_name.to_string();
let (s, r) = unbounded();
let mut new_channel = self.channel.ship_interface.create_channel()?;
thread::spawn(move || {
let channel = &mut new_channel;
channel
.create_new_subscription("graph-store", "/updates")
.ok();
loop {
channel.parse_event_messages();
let res_graph_updates = &mut channel.find_subscription("graph-store", "/updates");
if let Some(graph_updates) = res_graph_updates {
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(&chat_ship, &chat_name, &json) {
continue;
}
if let Ok(node) = Node::from_graph_update_json(&json) {
let authored_message =
AuthoredMessage::new(node.author, node.contents);
let _ = s.send(authored_message);
}
}
}
if let None = &pop_res {
break;
}
}
}
thread::sleep(Duration::new(0, 500000000));
}
});
Ok(r)
}
fn check_resource_json(chat_ship: &str, chat_name: &str, resource_json: &JsonValue) -> bool {
let resource = resource_json["graph-update"]["add-nodes"]["resource"].clone();
let json_chat_name = format!("{}", resource["name"]);
let json_chat_ship = format!("~{}", resource["ship"]);
if json_chat_name == chat_name && json_chat_ship == chat_ship {
return true;
}
false
}
}