cyberstorm/src/registry/directory.rs

106 lines
3.1 KiB
Rust

use std::path::PathBuf;
use std::sync::Arc;
use anyhow::Context;
use async_trait::async_trait;
use tokio::fs;
use crate::document::Document;
use crate::domains::common::*;
use crate::registry::{Registry, RegistryConfig, RegistryError};
#[derive(Debug)]
pub struct DirectoryRegistry {
path: PathBuf,
}
impl DirectoryRegistry {
pub fn new<P: Into<PathBuf>>(path: P) -> Self {
Self { path: path.into() }
}
fn domain_model_kind_path(&self, kind: DomainModelKind) -> PathBuf {
let (domain, model) = kind.parts();
self.path.join(format!("{}/{}", domain, model))
}
fn domain_id_path(&self, id: DomainId) -> PathBuf {
let (domain, model) = id.kind.parts();
self.path
.join(format!("{}/{}/{}.md", domain, model, id.model_id))
}
}
#[async_trait]
impl Registry for DirectoryRegistry {
async fn get_config(&self) -> Result<Arc<RegistryConfig>, RegistryError> {
let config_str = fs::read_to_string(self.path.join("config.toml")).await?;
toml::from_str(&config_str)
.context("failed to read registry `config.toml`")
.map(Arc::new)
.map_err(Into::into)
}
async fn get_document<M>(&self, model_id: ModelId) -> Result<Document<M>, RegistryError>
where
M: DomainModel,
{
let id = DomainId::new(M::kind(), model_id);
let path = self.domain_id_path(id);
if !path.is_file() {
return Err(RegistryError::NotFound(id));
}
let s = fs::read_to_string(path).await?;
s.parse().map_err(|err| RegistryError::Document(id, err))
}
async fn get_documents<M>(&self) -> Result<Vec<(DomainId, Document<M>)>, RegistryError>
where
M: DomainModel,
{
let ids = self.get_document_ids(M::kind()).await?;
let mut docs = Vec::with_capacity(ids.len());
for id in ids {
docs.push((id, self.get_document(id.model_id).await?));
}
Ok(docs)
}
async fn get_document_ids(
&self,
kind: DomainModelKind,
) -> Result<Vec<DomainId>, RegistryError> {
let mut ids = Vec::new();
let path = self.domain_model_kind_path(kind);
if !path.is_dir() {
return Ok(vec![]);
}
let mut dirs = fs::read_dir(path).await?;
while let Some(entry) = dirs.next_entry().await? {
let path = entry.path();
if path.is_file() {
let filestem = path.file_stem().unwrap().to_string_lossy();
let model_id: ModelId = filestem.as_ref().parse().unwrap();
if !model_id.is_example() {
ids.push(DomainId::new(kind, model_id))
}
}
}
Ok(ids)
}
async fn put_document<M>(
&self,
model_id: ModelId,
document: Document<M>,
) -> Result<(), RegistryError>
where
M: DomainModel,
{
let path = self.domain_id_path(DomainId::new(M::kind(), model_id));
let document = document.to_string();
fs::write(path, document.as_str()).await?;
Ok(())
}
}