use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use offline_protocol::{
DataValue, OfflineProtocol, ProtocolConfig, ProtocolStateResult, ProtocolStateStorage,
};
use offline_protocol_mls::storage::InMemoryStorage;
#[derive(Default)]
struct MemoryStateStorage {
records: Mutex<HashMap<(String, String), Vec<u8>>>,
}
impl ProtocolStateStorage for MemoryStateStorage {
fn store(&self, key_type: &str, key_id: &str, data: &[u8]) -> ProtocolStateResult<()> {
let mut records = self.records.lock().expect("storage mutex");
records.insert((key_type.to_string(), key_id.to_string()), data.to_vec());
Ok(())
}
fn load(&self, key_type: &str, key_id: &str) -> ProtocolStateResult<Option<Vec<u8>>> {
let records = self.records.lock().expect("storage mutex");
Ok(records
.get(&(key_type.to_string(), key_id.to_string()))
.cloned())
}
fn delete(&self, key_type: &str, key_id: &str) -> ProtocolStateResult<()> {
let mut records = self.records.lock().expect("storage mutex");
records.remove(&(key_type.to_string(), key_id.to_string()));
Ok(())
}
fn list_keys(&self, key_type: &str) -> ProtocolStateResult<Vec<String>> {
let records = self.records.lock().expect("storage mutex");
Ok(records
.keys()
.filter(|(stored_type, _)| stored_type == key_type)
.map(|(_, key_id)| key_id.clone())
.collect())
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let secure = Arc::new(InMemoryStorage::default());
let records = Arc::new(MemoryStateStorage::default());
let config = ProtocolConfig::builder("com.example.notes", "default").build()?;
let mut protocol = OfflineProtocol::new(config)?;
protocol.initialize_mls(secure.clone(), records.clone())?;
let space = "demo-space";
protocol.data_create_doc(space, "trip")?;
protocol.data_map_set(
space,
"trip",
"meta",
"title",
DataValue::Text {
value: "Coast road".to_string(),
},
)?;
for item in ["water", "map", "torch"] {
protocol.data_list_push(
space,
"trip",
"packing",
DataValue::Text {
value: item.to_string(),
},
)?;
}
protocol.data_text_insert(space, "trip", "notes", 0, "Meet at the bridge")?;
protocol.data_counter_increment(space, "trip", "opened", 1.0)?;
protocol.data_flush(space, "trip")?;
println!("spaces: {:?}", protocol.data_list_spaces()?);
println!("documents: {:?}", protocol.data_list_docs(space)?);
println!(
"compacted: {} bytes",
protocol.data_doc_size(space, "trip")?
);
println!(
"history: {} bytes",
protocol.data_export_raw(space, "trip")?.len()
);
println!("json: {}", protocol.data_doc_json(space, "trip")?);
drop(protocol);
let config = ProtocolConfig::builder("com.example.notes", "default").build()?;
let mut reopened = OfflineProtocol::new(config)?;
reopened.initialize_mls(secure, records)?;
println!("after reopen");
println!(
" title: {:?}",
reopened.data_map_get(space, "trip", "meta", "title")?
);
println!(
" packing: {}",
reopened.data_list_len(space, "trip", "packing")?
);
println!(
" notes: {:?}",
reopened.data_text_value(space, "trip", "notes")?
);
println!(
" opened: {}",
reopened.data_counter_value(space, "trip", "opened")?
);
Ok(())
}