use crate::graph::{Graph, Node, NodeContents};
use crate::helper::{get_current_da_time, get_current_time, index_dec_to_ud};
use crate::{Channel, Result, UrbitAPIError};
use json::{object, JsonValue};
pub enum Module {
Chat,
Notebook,
Collection,
Null,
}
pub struct GraphStore<'a> {
pub channel: &'a mut Channel,
}
impl<'a> GraphStore<'a> {
pub fn new_node(&self, contents: &NodeContents) -> Node {
let ship = format!("~{}", self.channel.ship_interface.ship_name);
let index = format!("/{}", get_current_da_time());
let unix_time = get_current_time();
Node::new(
index,
ship.clone(),
unix_time,
vec![],
contents.clone(),
None,
)
}
pub fn new_node_specified(
&self,
node_index: &str,
unix_time: u64,
contents: &NodeContents,
) -> Node {
let ship = format!("~{}", self.channel.ship_interface.ship_name);
Node::new(
node_index.to_string(),
ship.clone(),
unix_time,
vec![],
contents.clone(),
None,
)
}
pub fn add_node(
&mut self,
resource_ship: &str,
resource_name: &str,
node: &Node,
) -> Result<()> {
let prepped_json = object! {
"add-nodes": {
"resource": {
"ship": resource_ship,
"name": resource_name
},
"nodes": node.to_json()
}
};
let resp = (&mut self.channel).poke("graph-push-hook", "graph-update-1", &prepped_json)?;
if resp.status().as_u16() == 204 {
Ok(())
} else {
return Err(UrbitAPIError::FailedToAddNodesToGraphStore(
resource_name.to_string(),
));
}
}
pub fn add_node_spider(
&mut self,
resource_ship: &str,
resource_name: &str,
node: &Node,
) -> Result<()> {
let prepped_json = object! {
"add-nodes": {
"resource": {
"ship": resource_ship,
"name": resource_name
},
"nodes": node.to_json()
}
};
let resp = self.channel.ship_interface.spider(
"graph-update",
"graph-view-action",
"graph-add-nodes",
&prepped_json,
)?;
if resp.status().as_u16() == 200 {
Ok(())
} else {
return Err(UrbitAPIError::FailedToAddNodesToGraphStore(
resource_name.to_string(),
));
}
}
pub fn remove_nodes(
&mut self,
resource_ship: &str,
resource_name: &str,
indices: Vec<&str>,
) -> Result<()> {
let prepped_json = object! {
"remove-nodes": {
"resource": {
"ship": resource_ship,
"name": resource_name
},
"indices": indices
}
};
let resp = (&mut self.channel).poke("graph-push-hook", "graph-update-1", &prepped_json)?;
if resp.status().as_u16() == 204 {
Ok(())
} else {
return Err(UrbitAPIError::FailedToRemoveNodesFromGraphStore(
resource_name.to_string(),
));
}
}
pub fn get_node(
&mut self,
resource_ship: &str,
resource_name: &str,
node_index: &str,
) -> Result<Node> {
let path_nodes = index_dec_to_ud(node_index);
let path = format!("/node/{}/{}{}", resource_ship, resource_name, &path_nodes);
let res = self
.channel
.ship_interface
.scry("graph-store", &path, "json")?;
if res.status().as_u16() == 200 {
if let Ok(body) = res.text() {
if let Ok(node_json) = json::parse(&body) {
return Node::from_graph_update_json(&node_json);
}
}
}
Err(UrbitAPIError::FailedToGetGraphNode(format!(
"/{}/{}/{}",
resource_ship, resource_name, node_index
)))
}
pub fn get_node_subset(
&mut self,
resource_ship: &str,
resource_name: &str,
node_index: &str,
start_index: &str,
end_index: &str,
) -> Result<Graph> {
let path = format!(
"/node-children-subset/{}/{}/{}/{}/{}",
resource_ship, resource_name, node_index, end_index, start_index
);
let res = self
.channel
.ship_interface
.scry("graph-store", &path, "json")?;
if res.status().as_u16() == 200 {
if let Ok(body) = res.text() {
if let Ok(graph_json) = json::parse(&body) {
return Graph::from_json(graph_json);
}
}
}
Err(UrbitAPIError::FailedToGetGraph(resource_name.to_string()))
}
pub fn create_managed_graph(
&mut self,
graph_resource_name: &str,
graph_title: &str,
graph_description: &str,
graph_module: Module,
managed_group_ship: &str,
managed_group_name: &str,
) -> Result<()> {
let create_req = object! {
"create": {
"resource": {
"ship": format!("~{}", &self.channel.ship_interface.ship_name),
"name": graph_resource_name
},
"title": graph_title,
"description": graph_description,
"associated": {
"group": {
"ship": managed_group_ship,
"name": managed_group_name,
},
},
"module": module_to_validator_string(&graph_module),
"mark": module_to_mark(&graph_module)
}
};
let resp = self
.channel
.ship_interface
.spider("graph-view-action", "json", "graph-create", &create_req)
.unwrap();
if resp.status().as_u16() == 200 {
Ok(())
} else {
Err(UrbitAPIError::FailedToCreateGraphInShip(
graph_resource_name.to_string(),
))
}
}
pub fn create_unmanaged_graph(
&mut self,
graph_resource_name: &str,
graph_title: &str,
graph_description: &str,
graph_module: Module,
) -> Result<()> {
let create_req = object! {
"create": {
"resource": {
"ship": self.channel.ship_interface.ship_name_with_sig(),
"name": graph_resource_name
},
"title": graph_title,
"description": graph_description,
"associated": {
"policy": {
"invite": {
"pending": []
}
}
},
"module": module_to_validator_string(&graph_module),
"mark": module_to_mark(&graph_module)
}
};
let resp = self
.channel
.ship_interface
.spider("graph-view-action", "json", "graph-create", &create_req)
.unwrap();
if resp.status().as_u16() == 200 {
Ok(())
} else {
Err(UrbitAPIError::FailedToCreateGraphInShip(
graph_resource_name.to_string(),
))
}
}
pub fn get_graph(&mut self, resource_ship: &str, resource_name: &str) -> Result<Graph> {
let path = format!("/graph/{}/{}", resource_ship, resource_name);
let res = self
.channel
.ship_interface
.scry("graph-store", &path, "json")?;
if res.status().as_u16() == 200 {
if let Ok(body) = res.text() {
if let Ok(graph_json) = json::parse(&body) {
return Graph::from_json(graph_json);
}
}
}
Err(UrbitAPIError::FailedToGetGraph(resource_name.to_string()))
}
pub fn get_graph_subset(
&mut self,
resource_ship: &str,
resource_name: &str,
start_index: &str,
end_index: &str,
) -> Result<Graph> {
let path = format!(
"/graph-subset/{}/{}/{}/{}",
resource_ship, resource_name, end_index, start_index
);
let res = self
.channel
.ship_interface
.scry("graph-store", &path, "json")?;
if res.status().as_u16() == 200 {
if let Ok(body) = res.text() {
if let Ok(graph_json) = json::parse(&body) {
return Graph::from_json(graph_json);
}
}
}
Err(UrbitAPIError::FailedToGetGraph(resource_name.to_string()))
}
pub fn delete_graph(&mut self, resource_ship: &str, resource_name: &str) -> Result<()> {
let prepped_json = object! {
"delete": {
"resource": {
"ship": resource_ship,
"name": resource_name
}
}
};
let resp =
(&mut self.channel).poke("graph-view-action", "graph-update-1", &prepped_json)?;
if resp.status().as_u16() == 204 {
Ok(())
} else {
return Err(UrbitAPIError::FailedToRemoveGraphFromGraphStore(
resource_name.to_string(),
));
}
}
pub fn leave_graph(&mut self, resource_ship: &str, resource_name: &str) -> Result<()> {
let prepped_json = object! {
"leave": {
"resource": {
"ship": resource_ship,
"name": resource_name
}
}
};
let resp =
(&mut self.channel).poke("graph-view-action", "graph-update-1", &prepped_json)?;
if resp.status().as_u16() == 204 {
Ok(())
} else {
return Err(UrbitAPIError::FailedToRemoveGraphFromGraphStore(
resource_name.to_string(),
));
}
}
pub fn archive_graph(&mut self, resource_ship: &str, resource_name: &str) -> Result<String> {
let path = format!("/archive/{}/{}", resource_ship, resource_name);
let res = self
.channel
.ship_interface
.scry("graph-store", &path, "json")?;
if res.status().as_u16() == 200 {
if let Ok(body) = res.text() {
return Ok(body);
}
}
return Err(UrbitAPIError::FailedToArchiveGraph(
resource_name.to_string(),
));
}
pub fn unarchive_graph(&mut self, resource_ship: &str, resource_name: &str) -> Result<String> {
let path = format!("/unarchive/{}/{}", resource_ship, resource_name);
let res = self
.channel
.ship_interface
.scry("graph-store", &path, "json")?;
if res.status().as_u16() == 200 {
if let Ok(body) = res.text() {
return Ok(body);
}
}
return Err(UrbitAPIError::FailedToArchiveGraph(
resource_name.to_string(),
));
}
pub fn add_tag(&mut self, resource_ship: &str, resource_name: &str, tag: &str) -> Result<()> {
let prepped_json = object! {
"add-tag": {
"resource": {
"ship": resource_ship,
"name": resource_name
},
"term": tag
}
};
let resp = (&mut self.channel).poke("graph-push-hook", "graph-update-1", &prepped_json)?;
if resp.status().as_u16() == 204 {
Ok(())
} else {
return Err(UrbitAPIError::FailedToAddTag(resource_name.to_string()));
}
}
pub fn remove_tag(
&mut self,
resource_ship: &str,
resource_name: &str,
tag: &str,
) -> Result<()> {
let prepped_json = object! {
"remove-tag": {
"resource": {
"ship": resource_ship,
"name": resource_name
},
"term": tag
}
};
let resp = (&mut self.channel).poke("graph-push-hook", "graph-update-1", &prepped_json)?;
if resp.status().as_u16() == 204 {
Ok(())
} else {
return Err(UrbitAPIError::FailedToRemoveTag(resource_name.to_string()));
}
}
pub fn get_keys(&mut self) -> Result<Vec<JsonValue>> {
let resp = self
.channel
.ship_interface
.scry("graph-store", "/keys", "json")?;
if resp.status().as_u16() == 200 {
let json_text = resp.text()?;
if let Ok(json) = json::parse(&json_text) {
let keys = json["graph-update"]["keys"].clone();
let mut keys_list = vec![];
for key in keys.members() {
keys_list.push(key.clone())
}
return Ok(keys_list);
}
}
return Err(UrbitAPIError::FailedToFetchKeys);
}
pub fn get_tags(&mut self) -> Result<Vec<JsonValue>> {
let resp = self
.channel
.ship_interface
.scry("graph-store", "/tags", "json")?;
if resp.status().as_u16() == 200 {
let json_text = resp.text()?;
if let Ok(json) = json::parse(&json_text) {
let tags = json["graph-update"]["tags"].clone();
let mut tags_list = vec![];
for tag in tags.members() {
tags_list.push(tag.clone())
}
return Ok(tags_list);
}
}
return Err(UrbitAPIError::FailedToFetchTags);
}
pub fn get_tag_queries(&mut self) -> Result<Vec<JsonValue>> {
let resp = self
.channel
.ship_interface
.scry("graph-store", "/tag-queries", "json")?;
if resp.status().as_u16() == 200 {
let json_text = resp.text()?;
if let Ok(json) = json::parse(&json_text) {
let tags = json["graph-update"]["tag-queries"].clone();
let mut tags_list = vec![];
for tag in tags.members() {
tags_list.push(tag.clone())
}
return Ok(tags_list);
}
}
return Err(UrbitAPIError::FailedToFetchTags);
}
pub fn peek_update_log(&mut self, resource_ship: &str, resource_name: &str) -> Result<String> {
let path = format!("/peek-update-log/{}/{}", resource_ship, resource_name);
let res = self
.channel
.ship_interface
.scry("graph-store", &path, "json")?;
if res.status().as_u16() == 200 {
if let Ok(body) = res.text() {
return Ok(body);
}
}
Err(UrbitAPIError::FailedToGetGraph(resource_name.to_string()))
}
pub fn get_update_log(&mut self, resource_ship: &str, resource_name: &str) -> Result<String> {
let path = format!("/update-log/{}/{}", resource_ship, resource_name);
let res = self
.channel
.ship_interface
.scry("graph-store", &path, "json")?;
if res.status().as_u16() == 200 {
if let Ok(body) = res.text() {
return Ok(body);
}
}
Err(UrbitAPIError::FailedToGetGraph(resource_name.to_string()))
}
pub fn get_update_log_subset(
&mut self,
resource_ship: &str,
resource_name: &str,
start_index: &str,
end_index: &str,
) -> Result<String> {
let path = format!(
"/update-log-subset/{}/{}/{}/{}",
resource_ship, resource_name, end_index, start_index
);
let res = self
.channel
.ship_interface
.scry("graph-store", &path, "json")?;
if res.status().as_u16() == 200 {
if let Ok(body) = res.text() {
return Ok(body);
}
}
Err(UrbitAPIError::FailedToGetUpdateLog(
resource_name.to_string(),
))
}
}
pub fn module_to_validator_string(module: &Module) -> String {
match module {
Module::Chat => "graph-validator-chat".to_string(),
Module::Notebook => "graph-validator-publish".to_string(),
Module::Collection => "graph-validator-link".to_string(),
Module::Null => "".to_string(),
}
}
pub fn module_to_mark(module: &Module) -> String {
match module {
Module::Chat => "chat".to_string(),
Module::Notebook => "publish".to_string(),
Module::Collection => "link".to_string(),
Module::Null => "".to_string(),
}
}