2023-12-07 19:51:19 +01:00
|
|
|
use std::sync::{Arc, RwLock};
|
|
|
|
|
|
|
|
use anyhow::Error;
|
|
|
|
use cozo::DbInstance;
|
|
|
|
use tracing::{error, debug};
|
|
|
|
|
|
|
|
use crate::comm::{Peer, CommHandle, messages::{Message, MessageContent}};
|
|
|
|
|
|
|
|
use self::types::{ElementContent, ElementId, Element, Tag};
|
|
|
|
|
|
|
|
pub mod types;
|
|
|
|
|
|
|
|
mod queries;
|
|
|
|
mod schema;
|
|
|
|
|
|
|
|
pub struct State {
|
|
|
|
db: DbInstance,
|
|
|
|
comm_handle: RwLock<Option<Arc<CommHandle>>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl State {
|
|
|
|
pub async fn new() -> anyhow::Result<Arc<State>> {
|
|
|
|
let db = DbInstance::new("mem", "", Default::default());
|
|
|
|
match db {
|
|
|
|
Ok(d) => {
|
|
|
|
schema::add_schema(&d)?;
|
|
|
|
Ok(Arc::new(State {db: d, comm_handle: RwLock::new(None)}))
|
|
|
|
},
|
|
|
|
Err(e) => Err(Error::msg(format!("{:?}", e))),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_comm_handle(&self, handle: Arc<CommHandle>) {
|
|
|
|
*self.comm_handle.write().as_deref_mut().expect("Could not set state's CommHandle") = Some(handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Create an element and add it to the database
|
|
|
|
pub fn create_element(&self, content: &ElementContent) -> anyhow::Result<ElementId> {
|
|
|
|
let id = ElementId::new();
|
|
|
|
queries::set_element(&self.db, &id, &content)?;
|
|
|
|
debug!("Created element with id {:?}: {:?}", &id, self.get_element(&id));
|
|
|
|
|
|
|
|
self.send_to_peers(MessageContent::CreateElement { id: id.clone(), content: content.clone() });
|
|
|
|
Ok(id)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Anyone updated an element, update it in the database
|
|
|
|
pub fn set_element(&self, element_id: &ElementId, content: &ElementContent) -> anyhow::Result<()> {
|
|
|
|
let res = queries::set_element(&self.db, element_id, content);
|
|
|
|
debug!("Set element with id {:?}: {:?}", element_id, self.get_element(element_id));
|
|
|
|
|
|
|
|
self.send_to_peers(MessageContent::SetElement { id: element_id.clone(), content: content.clone() });
|
|
|
|
res
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_element_content(&self, element_id: &ElementId, content: &ElementContent) -> anyhow::Result<()> {
|
|
|
|
let res = queries::set_element_content(&self.db, element_id, content);
|
|
|
|
debug!("Set element content with id {:?}: {:?}", element_id, self.get_element(element_id));
|
|
|
|
|
|
|
|
|
|
|
|
self.send_to_peers(MessageContent::SetElement { id: element_id.clone(), content: content.clone() });
|
|
|
|
res
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn remove_element(&self, element_id: &ElementId) -> anyhow::Result<()> {
|
|
|
|
let res = queries::remove_element(&self.db, element_id);
|
|
|
|
|
|
|
|
self.send_to_peers(MessageContent::RemoveElement { id: element_id.clone() });
|
|
|
|
res
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_element(&self, id: &ElementId) -> Option<Element> {
|
|
|
|
queries::get_element(&self.db, id).ok()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_elements_by_tag(&self, tag: &Tag) -> Vec<ElementId> {
|
|
|
|
queries::get_elements_by_tag(&self.db, tag)
|
|
|
|
.map_err(|e| {error!("{}", e); e})
|
|
|
|
.unwrap_or(vec![])
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_peer(&self, peer: &Peer) -> anyhow::Result<()> {
|
|
|
|
queries::add_peer(&self.db, &peer.id(), &peer.name())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_peers(&self) -> anyhow::Result<Vec<Peer>> {
|
|
|
|
queries::get_peers(&self.db)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn send_to_peers(&self, ct: MessageContent) {
|
|
|
|
match self.comm_handle.read() {
|
|
|
|
Ok(opt) => {
|
|
|
|
if opt.is_some() {
|
|
|
|
let arc = opt.as_ref().unwrap().clone();
|
|
|
|
tokio::spawn(async move {
|
|
|
|
let _ = arc.broadcast(Message::new(ct)).await;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Err(e) => debug!("{}", e),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-12-07 21:54:24 +01:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use crate::state::State;
|
|
|
|
use crate::state::types::ElementContent;
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
#[serial_test::serial]
|
|
|
|
async fn test_create() {
|
|
|
|
tracing_subscriber::fmt().pretty().init();
|
|
|
|
let state = State::new().await.unwrap();
|
|
|
|
let id = state.create_element(&ElementContent::Text("Test-text".to_string())).unwrap();
|
|
|
|
let el = state.get_element(&id).unwrap();
|
|
|
|
assert_eq!(
|
|
|
|
ElementContent::Text("Test-text".to_string()),
|
|
|
|
el.content().to_owned()
|
|
|
|
)
|
|
|
|
}
|
2023-12-07 19:51:19 +01:00
|
|
|
|
2023-12-07 21:54:24 +01:00
|
|
|
#[tokio::test]
|
|
|
|
#[serial_test::serial]
|
|
|
|
async fn test_update() {
|
|
|
|
tracing_subscriber::fmt().pretty().init();
|
|
|
|
let state = State::new().await.unwrap();
|
|
|
|
let id = state.create_element(&ElementContent::Text("Test-text".to_string())).unwrap();
|
|
|
|
state.set_element(&id,&ElementContent::Text("Test-text 2".to_string())).unwrap();
|
|
|
|
let el = state.get_element(&id).unwrap();
|
|
|
|
assert_eq!(
|
|
|
|
ElementContent::Text("Test-text 2".to_string()),
|
|
|
|
el.content().to_owned()
|
|
|
|
)
|
|
|
|
}
|
2023-12-07 19:51:19 +01:00
|
|
|
}
|