232 lines
7.9 KiB
Rust
232 lines
7.9 KiB
Rust
|
|
use std::net::ToSocketAddrs;
|
|
use std::{io, fmt::format, vec};
|
|
use surrealdb::kvs::{Datastore, Key, Val};
|
|
use itertools::Itertools;
|
|
use crate::error;
|
|
use crate::error::MizeError;
|
|
use crate::server::proto::{self};
|
|
use crate::server::Mutexes;
|
|
use crate::server::Peer;
|
|
|
|
use serde_json::Value as JsonValue;
|
|
use serde::{Serialize, Deserialize};
|
|
|
|
use super::proto::{Delta, MizeId};
|
|
|
|
// The struct to do the storage and updates to it
|
|
// is responsible, that no illegal states can occur in the storage, by using transactions
|
|
// currently it's just a surrealdb Datastore. should be replaced by a completely custom File-System in the future.
|
|
pub struct Itemstore {
|
|
db: Datastore,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct Item {
|
|
#[serde(flatten)]
|
|
pub json: JsonValue,
|
|
}
|
|
|
|
pub struct Array {
|
|
}
|
|
|
|
//later
|
|
//pub struct Map {
|
|
//}
|
|
|
|
//pub struct Table {
|
|
//}
|
|
|
|
impl Item {
|
|
pub fn get_id(&self) -> Result<String, MizeError> {
|
|
if let JsonValue::Object(ob) = &self.json{
|
|
if let Some(id_val) = ob.get("__item__") {
|
|
if let JsonValue::String(id) = id_val {
|
|
return Ok(id.to_string())
|
|
} else {
|
|
return Err(MizeError::new(11).extra_msg("mize-id field in an item was not a String"));
|
|
}
|
|
} else {
|
|
return Err(MizeError::new(11).extra_msg("There was no mize-id field in an item"));
|
|
}
|
|
} else {
|
|
return Err(MizeError::new(11).extra_msg("An Item was not a JsonValue::Object"));
|
|
}
|
|
}
|
|
|
|
pub fn apply_delta(&mut self, delta: Delta) -> Result<(), MizeError> {
|
|
//println!("DELTA: {:?}", delta);
|
|
for (path, value) in delta.delta {
|
|
let mut to_replace = &mut self.json;
|
|
let mut counter = path.len() as i32;
|
|
for name in path {
|
|
counter -= 1;
|
|
|
|
// if let Some(inner) = to_replace.get(&name) {
|
|
// to_replace = inner
|
|
|
|
// } else if let JsonValue::Object(ob) = to_replace {
|
|
//let mut new_map = JsonValue::Object(serde_json::Map::new());
|
|
//ob.insert(name, new_map);
|
|
//to_replace = &mut new_map;
|
|
// } else {
|
|
// return Err(MizeError::new(11)
|
|
// .extra_msg("Error applying a Delta to an Item. The path could not be followed."));
|
|
// }
|
|
|
|
|
|
//on last iteration
|
|
if counter == 0 {
|
|
if value.is_none() {
|
|
if to_replace.is_object() {
|
|
to_replace.as_object_mut().ok_or(MizeError::new(11))?.remove(&name);
|
|
return Ok(())
|
|
}
|
|
}
|
|
}
|
|
|
|
to_replace = if to_replace.get_mut(&name).is_some() {
|
|
to_replace.get_mut(&name).ok_or(MizeError::new(11))?
|
|
|
|
} else if to_replace.is_object() {
|
|
// when path does not exist
|
|
|
|
let mut new_map = JsonValue::Object(serde_json::Map::new());
|
|
to_replace.as_object_mut().ok_or(MizeError::new(11))?.insert(name.clone(), new_map);
|
|
to_replace.get_mut(&name).ok_or(MizeError::new(11))?
|
|
|
|
} else {
|
|
|
|
return Err(MizeError::new(11)
|
|
.extra_msg("Error applying a Delta to an Item. The path could not be followed."));
|
|
};
|
|
|
|
}
|
|
|
|
// replace with value from the delta
|
|
*to_replace = value.into();
|
|
}
|
|
|
|
//println!("After applying a Delta, {}", self.json);
|
|
return Ok(())
|
|
}
|
|
|
|
pub fn from_bytes(vec: Vec<u8>) -> Result<Item, MizeError> {
|
|
let string = String::from_utf8(vec)?;
|
|
let item = serde_json::from_str(&string)?;
|
|
return Ok(item);
|
|
}
|
|
}
|
|
|
|
impl Itemstore {
|
|
pub async fn new(path: String) -> Result<Itemstore, MizeError> {
|
|
//println!("PATH of DB: {}", path);
|
|
let ds = Datastore::new(&(String::from("file://") + &path[..])[..]).await
|
|
.map_err(|e| MizeError::new(30).extra_msg(format!("surrealdb Error: {}", e)).extra_msg(format!("Trying to create at Location: {}", path)))?;
|
|
|
|
let mut tr = ds.transaction(true, false).await?;
|
|
|
|
match tr.get(MizeId::zero().into_bytes()).await {
|
|
Ok(Some(val)) => println!("Item 0 already created"),
|
|
Ok(None) => {
|
|
let data = serde_json::json!({
|
|
"num_of_items": 1,
|
|
"next_free_id": 1,
|
|
"__commit__": 0,
|
|
"__type__": "mize-main",
|
|
"__item__": "0"
|
|
});
|
|
|
|
tr.set(MizeId::zero().into_bytes(), data.to_string()).await?;
|
|
tr.commit().await?;
|
|
},
|
|
|
|
Err(e) => {return Err(MizeError::from(e))},
|
|
};
|
|
return Ok(Itemstore {db:ds});
|
|
}
|
|
|
|
pub async fn create(&self, mut item: Item, mutexes: Mutexes, origin: Peer) -> Result<MizeId, MizeError> {
|
|
let mut tr = self.db.transaction(true, false).await?;
|
|
|
|
//get next_free_id
|
|
let json: JsonValue = serde_json::from_str(&String::from_utf8(tr.get(MizeId::zero().into_bytes()).await?.ok_or(MizeError::new(31))?)
|
|
.map_err(|_| MizeError::new(11))?)
|
|
.map_err(|_| MizeError::new(11))?;
|
|
|
|
let new_id_u64: u64 = json.get("next_free_id").ok_or(MizeError::new(11))?.as_u64().ok_or(MizeError::new(11))?;
|
|
let new_id = MizeId::new(format!("{}", new_id_u64));
|
|
|
|
let num_of_items: u64 = json.get("num_of_items").ok_or(MizeError::new(11))?.as_u64().ok_or(MizeError::new(11))?;
|
|
|
|
let new_next_id = new_id_u64 +1;
|
|
let new_num = num_of_items + 1;
|
|
|
|
//add mize-id field to item
|
|
//let delta: Delta = serde_json::from_str(&format!("[[[\"__item__\"], \"{}\"]]", new_id))?;
|
|
let mut delta = Delta::new();
|
|
delta.append(vec!["__item__"], serde_json::json!(new_id_u64));
|
|
item.apply_delta(delta)?;
|
|
|
|
tr.set(new_id.clone().into_bytes(), item.json.to_string()).await?;
|
|
|
|
tr.commit().await?;
|
|
|
|
//handle update to item0
|
|
let mut delta_item0: Delta = Delta::new();
|
|
delta_item0.append(vec!["num_of_items"], serde_json::json!(new_num));
|
|
delta_item0.append(vec!["next_free_id"], serde_json::json!(new_next_id));
|
|
|
|
proto::handle_update(vec![(proto::MizeId::new(format!("0")), delta_item0)], origin, mutexes.clone()).await?;
|
|
|
|
return Ok(new_id);
|
|
}
|
|
|
|
|
|
pub async fn update(&self, id: MizeId, delta: Delta) -> Result<(), MizeError>{
|
|
let mut tr = self.db.transaction(true, true).await?;
|
|
|
|
let item_bytes: Vec<u8> = tr.get(id.clone().into_bytes()).await?
|
|
.ok_or(MizeError::new(11)
|
|
.extra_msg("The Item an update should be applied to does not exist."))?;
|
|
|
|
let mut item = Item::from_bytes(item_bytes)?;
|
|
|
|
item.apply_delta(delta)?;
|
|
//println!("after applying delta: {:?}", item);
|
|
|
|
tr.set(id.into_bytes(), serde_json::to_string(&item)?).await?;
|
|
|
|
tr.commit().await?;
|
|
return Ok(());
|
|
}
|
|
|
|
|
|
|
|
pub async fn delete(&self, id: MizeId) -> Result<(), error::MizeError>{
|
|
let mut tr = self.db.transaction(true, true).await?;
|
|
|
|
tr.del(id.into_bytes()).await?;
|
|
|
|
tr.commit().await?;
|
|
|
|
return Ok(());
|
|
}
|
|
|
|
|
|
pub async fn get(&self, id: MizeId) -> Result<Item, MizeError> {
|
|
let mut tr = self.db.transaction(false, false).await?;
|
|
|
|
let item_res = tr.get(id.clone().into_bytes()).await?;
|
|
if let Some(item_vec) = item_res {
|
|
let item_str: String = String::from_utf8(item_vec).map_err(|_|MizeError::new(11))?;
|
|
let item: JsonValue = serde_json::from_str(&item_str).map_err(|_|MizeError::new(11))?;
|
|
return Ok(Item { json: item })
|
|
} else {
|
|
return Err(MizeError::new(32).format(vec![&format!("{:?}", id)]));
|
|
}
|
|
return Err(MizeError::new(11));
|
|
}
|
|
}
|
|
|