use std::path::PathBuf;
use anyhow::{Context, Result};
use crate::config;
use crate::db::DEFAULT_SPACE;
pub struct Space {
pub root: PathBuf,
}
impl Space {
pub fn open() -> Result<Self> {
let root = config::project_dirs()?.data_dir().to_path_buf();
let space = Self { root };
space.migrate_legacy_layout()?;
std::fs::create_dir_all(space.root.join("spaces"))
.with_context(|| format!("creating {}", space.root.join("spaces").display()))?;
Ok(space)
}
fn migrate_legacy_layout(&self) -> Result<()> {
let legacy_dir = self.root.join("spaces").join("global");
let legacy_db = legacy_dir.join("nexus.db");
let new_db = self.root.join("nexus.db");
if legacy_db.exists() && !new_db.exists() {
std::fs::create_dir_all(&self.root)
.with_context(|| format!("creating {}", self.root.display()))?;
std::fs::rename(&legacy_db, &new_db).with_context(|| {
format!("moving {} to {}", legacy_db.display(), new_db.display())
})?;
}
let default_dir = self.root.join("spaces").join(DEFAULT_SPACE);
if legacy_dir.exists() && !default_dir.exists() {
std::fs::rename(&legacy_dir, &default_dir).with_context(|| {
format!(
"moving {} to {}",
legacy_dir.display(),
default_dir.display()
)
})?;
}
Ok(())
}
pub fn db_path(&self) -> PathBuf {
self.root.join("nexus.db")
}
pub fn ensure_space_dir(&self, name: &str) -> Result<()> {
let dir = self.space_dir(name);
std::fs::create_dir_all(&dir).with_context(|| format!("creating {}", dir.display()))
}
pub(crate) fn space_dir(&self, name: &str) -> PathBuf {
self.root.join("spaces").join(name)
}
pub fn memory_path(&self, name: &str) -> PathBuf {
self.space_dir(name).join("memory.md")
}
pub fn instructions_path(&self, name: &str) -> PathBuf {
self.space_dir(name).join("instructions.md")
}
pub fn blocked_domains_path(&self, name: &str) -> PathBuf {
self.space_dir(name).join("blocked_domains.txt")
}
pub fn files_dir(&self, name: &str) -> PathBuf {
self.space_dir(name).join("files")
}
pub fn apps_dir(&self, name: &str) -> PathBuf {
self.space_dir(name).join("apps")
}
pub fn scripts_dir(&self, name: &str) -> PathBuf {
self.space_dir(name).join("scripts")
}
pub fn spaces_root(&self) -> PathBuf {
self.root.join("spaces")
}
pub fn rename_space_dir(&self, old: &str, new: &str) -> Result<()> {
let from = self.space_dir(old);
let to = self.space_dir(new);
if from.exists() {
std::fs::rename(&from, &to)
.with_context(|| format!("renaming {} to {}", from.display(), to.display()))?;
}
Ok(())
}
pub fn remove_space_dir(&self, name: &str) -> Result<()> {
let dir = self.space_dir(name);
if dir.exists() {
std::fs::remove_dir_all(&dir).with_context(|| format!("removing {}", dir.display()))?;
}
Ok(())
}
}