2023-05-29 15:42:32 -04:00
|
|
|
mod cache;
|
2023-06-22 11:08:40 -04:00
|
|
|
mod database;
|
2023-05-29 15:42:32 -04:00
|
|
|
mod error;
|
2023-05-30 00:18:13 -04:00
|
|
|
mod store;
|
2023-05-29 15:42:32 -04:00
|
|
|
|
2023-04-04 09:59:29 -04:00
|
|
|
use async_std::{
|
2023-05-29 15:42:32 -04:00
|
|
|
channel::{unbounded, Sender},
|
2023-04-04 09:59:29 -04:00
|
|
|
path::PathBuf,
|
|
|
|
task::spawn,
|
|
|
|
};
|
2023-05-29 15:42:32 -04:00
|
|
|
use cache::Cache;
|
2023-06-22 11:08:40 -04:00
|
|
|
use database::Database;
|
2023-05-29 15:42:32 -04:00
|
|
|
use error::{ErrorCode, MTTError};
|
2023-05-30 00:18:13 -04:00
|
|
|
use store::Store;
|
2023-04-23 13:13:38 -04:00
|
|
|
|
2023-06-03 15:27:26 -04:00
|
|
|
const ENTRY: &str = "EntryPoint";
|
|
|
|
|
2023-06-20 11:51:32 -04:00
|
|
|
#[derive(Debug)]
|
2023-06-29 00:17:49 -04:00
|
|
|
pub struct ToCacheMsg<D> {
|
|
|
|
data: D,
|
2023-06-20 11:51:32 -04:00
|
|
|
result: Sender<FromCache>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum ToCache {
|
2023-06-29 00:17:49 -04:00
|
|
|
Get(ToCacheMsg<String>),
|
|
|
|
Commit(ToCacheMsg<Store>),
|
2023-06-20 11:51:32 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum FromCache {
|
2023-06-29 00:17:49 -04:00
|
|
|
Ok,
|
2023-06-20 11:51:32 -04:00
|
|
|
Str(Store),
|
|
|
|
Error(MTTError),
|
|
|
|
}
|
|
|
|
|
2023-04-23 13:13:38 -04:00
|
|
|
#[derive(Clone, Debug)]
|
2023-06-23 08:30:49 -04:00
|
|
|
pub struct Data<D> {
|
2023-06-03 15:27:26 -04:00
|
|
|
id: Option<String>,
|
|
|
|
data: Option<D>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<D> Data<D> {
|
|
|
|
fn from_id<S>(id: S) -> Self
|
|
|
|
where
|
|
|
|
S: Into<String>,
|
|
|
|
{
|
|
|
|
Self {
|
|
|
|
id: Some(id.into()),
|
|
|
|
data: None,
|
|
|
|
}
|
|
|
|
}
|
2023-06-23 08:30:49 -04:00
|
|
|
|
|
|
|
fn from_data(data: D) -> Self {
|
|
|
|
Self {
|
|
|
|
id: None,
|
|
|
|
data: Some(data),
|
|
|
|
}
|
|
|
|
}
|
2023-04-08 15:04:04 -04:00
|
|
|
}
|
|
|
|
|
2023-04-04 09:59:29 -04:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct MoreThanText {
|
2023-06-20 11:51:32 -04:00
|
|
|
to_cache: Sender<ToCache>,
|
2023-06-03 15:27:26 -04:00
|
|
|
entry: Data<Store>,
|
2023-04-04 09:59:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl MoreThanText {
|
2023-06-20 11:51:32 -04:00
|
|
|
fn new(to_cache: Sender<ToCache>) -> Self {
|
2023-06-03 15:27:26 -04:00
|
|
|
Self {
|
|
|
|
to_cache: to_cache,
|
|
|
|
entry: Data::from_id(ENTRY),
|
|
|
|
}
|
2023-04-12 18:33:39 -04:00
|
|
|
}
|
|
|
|
|
2023-06-20 11:51:32 -04:00
|
|
|
async fn session(&self) -> Result<Store, MTTError> {
|
|
|
|
let (s, r) = unbounded();
|
2023-06-29 00:17:49 -04:00
|
|
|
let msg = ToCacheMsg {
|
|
|
|
data: ENTRY.to_string(),
|
2023-06-20 11:51:32 -04:00
|
|
|
result: s,
|
|
|
|
};
|
|
|
|
self.to_cache.send(ToCache::Get(msg)).await.unwrap();
|
|
|
|
match r.recv().await.unwrap() {
|
|
|
|
FromCache::Str(store) => Ok(store),
|
|
|
|
FromCache::Error(err) => Err(err),
|
2023-06-29 00:17:49 -04:00
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn commit(&self, store: Store) -> Result<(), MTTError> {
|
|
|
|
let (s, r) = unbounded();
|
|
|
|
let msg = ToCacheMsg {
|
|
|
|
data: store,
|
|
|
|
result: s,
|
|
|
|
};
|
|
|
|
self.to_cache.send(ToCache::Commit(msg)).await.unwrap();
|
|
|
|
match r.recv().await.unwrap() {
|
|
|
|
FromCache::Ok => Ok(()),
|
|
|
|
FromCache::Error(err) => Err(err),
|
|
|
|
_ => unreachable!(),
|
2023-06-20 11:51:32 -04:00
|
|
|
}
|
2023-04-08 15:04:04 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
2023-05-29 15:42:32 -04:00
|
|
|
mod mtt {
|
2023-04-08 15:04:04 -04:00
|
|
|
use super::*;
|
|
|
|
use tempfile::tempdir;
|
|
|
|
|
2023-04-18 09:02:18 -04:00
|
|
|
#[async_std::test]
|
2023-05-29 15:42:32 -04:00
|
|
|
async fn create_new() {
|
2023-04-18 09:02:18 -04:00
|
|
|
let dir = tempdir().unwrap();
|
2023-05-29 15:42:32 -04:00
|
|
|
let mtt = start_db(dir.path()).await.unwrap();
|
2023-06-03 15:27:26 -04:00
|
|
|
assert_eq!(mtt.entry.id, Some(ENTRY.to_string()));
|
|
|
|
assert!(mtt.entry.data.is_none());
|
2023-06-20 11:51:32 -04:00
|
|
|
let store = mtt.session().await.unwrap();
|
2023-06-03 15:27:26 -04:00
|
|
|
let expected: Vec<String> = Vec::new();
|
|
|
|
assert_eq!(store.list(), expected);
|
2023-04-12 18:33:39 -04:00
|
|
|
}
|
2023-06-29 00:17:49 -04:00
|
|
|
|
|
|
|
#[async_std::test]
|
|
|
|
async fn commit_db() {
|
|
|
|
let dir = tempdir().unwrap();
|
|
|
|
let db = "fred";
|
|
|
|
let mtt = start_db(dir.path()).await.unwrap();
|
|
|
|
let mut store = mtt.session().await.unwrap();
|
|
|
|
store.add(db).unwrap();
|
|
|
|
mtt.commit(store).await.unwrap();
|
|
|
|
let store2 = mtt.session().await.unwrap();
|
|
|
|
assert_eq!(store2.list(), [db]);
|
|
|
|
}
|
2023-06-30 12:23:28 -04:00
|
|
|
|
|
|
|
#[async_std::test]
|
|
|
|
async fn commit_from_multiple_sources() {
|
|
|
|
let dir = tempdir().unwrap();
|
|
|
|
let mtt1 = start_db(dir.path()).await.unwrap();
|
|
|
|
let mtt2 = mtt1.clone();
|
|
|
|
let db1 = "first";
|
|
|
|
let db2 = "second";
|
|
|
|
let mut store1 = mtt1.session().await.unwrap();
|
|
|
|
let mut store2 = mtt2.session().await.unwrap();
|
|
|
|
store1.add(db1).unwrap();
|
|
|
|
store2.add(db2).unwrap();
|
|
|
|
mtt1.commit(store1).await.unwrap();
|
|
|
|
mtt2.commit(store2).await.unwrap();
|
|
|
|
let output = mtt1.session().await.unwrap();
|
|
|
|
assert_eq!(output.list(), [db1, db2]);
|
|
|
|
}
|
2023-06-30 22:38:18 -04:00
|
|
|
|
|
|
|
#[async_std::test]
|
|
|
|
async fn fail_on_duplicates() {
|
|
|
|
let dir = tempdir().unwrap();
|
|
|
|
let mtt1 = start_db(dir.path()).await.unwrap();
|
|
|
|
let mtt2 = mtt1.clone();
|
|
|
|
let name = "unique_only";
|
|
|
|
let mut store1 = mtt1.session().await.unwrap();
|
|
|
|
let mut store2 = mtt2.session().await.unwrap();
|
|
|
|
store1.add(name).unwrap();
|
|
|
|
store2.add(name).unwrap();
|
|
|
|
mtt1.commit(store1).await.unwrap();
|
|
|
|
let output = mtt2.commit(store2).await;
|
|
|
|
match output {
|
|
|
|
Ok(_) => assert!(false, "Should have returned an error"),
|
|
|
|
Err(_) => (),
|
|
|
|
}
|
|
|
|
}
|
2023-04-04 12:36:10 -04:00
|
|
|
}
|
|
|
|
|
2023-05-29 15:42:32 -04:00
|
|
|
pub async fn start_db<P>(dir: P) -> Result<MoreThanText, MTTError>
|
2023-04-04 09:59:29 -04:00
|
|
|
where
|
|
|
|
P: Into<PathBuf>,
|
|
|
|
{
|
2023-05-29 15:42:32 -04:00
|
|
|
let path = dir.into();
|
2023-04-04 09:59:29 -04:00
|
|
|
let (s, r) = unbounded();
|
|
|
|
spawn(async move {
|
2023-06-29 00:17:49 -04:00
|
|
|
let mut cache = Cache::new(path).await;
|
2023-05-29 15:42:32 -04:00
|
|
|
cache.listen(r).await;
|
2023-04-04 09:59:29 -04:00
|
|
|
});
|
2023-05-29 15:42:32 -04:00
|
|
|
Ok(MoreThanText::new(s))
|
2023-04-04 09:59:29 -04:00
|
|
|
}
|