use std::collections::HashMap;
use std::fs;
use std::path::Path;
use std::path::PathBuf;
use std::sync::{Arc, RwLock, Weak};
use std::time::SystemTime;
use crate::config::AppConfig;
use crate::error::{AxiomError, Result};
use crate::fs::LocalContextFs;
use crate::index::InMemoryIndex;
use crate::ontology::CompiledOntologySchema;
use crate::parse::ParserRegistry;
use crate::retrieval::{DrrConfig, DrrEngine};
use crate::state::SqliteStateStore;
use crate::uri::AxiomUri;
mod benchmark;
mod eval;
mod indexing;
mod markdown_editor;
mod mirror_outbox;
mod om_bridge;
mod ontology;
mod queue_reconcile;
mod relation;
mod release;
mod request_log;
mod resource;
mod runtime;
mod search;
mod trace;
pub use benchmark::BenchmarkFixtureCreateOptions;
type DocumentEditGate = Arc<RwLock<()>>;
type WeakDocumentEditGate = Weak<RwLock<()>>;
const MARKDOWN_EDIT_GATE_SWEEP_THRESHOLD: usize = 1024;
const STATE_DB_FILE_NAME: &str = "context.db";
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct OntologySchemaFingerprint {
modified: Option<SystemTime>,
len: u64,
}
#[derive(Debug, Clone)]
struct OntologySchemaCacheEntry {
fingerprint: OntologySchemaFingerprint,
compiled: Arc<CompiledOntologySchema>,
}
#[derive(Debug, Default)]
struct MarkdownEditGates {
by_uri: RwLock<HashMap<String, WeakDocumentEditGate>>,
}
impl MarkdownEditGates {
fn gate_for(&self, uri: &AxiomUri) -> Result<DocumentEditGate> {
let key = uri.to_string();
if let Some(existing) = self
.by_uri
.read()
.map_err(|_| AxiomError::lock_poisoned("markdown gate registry"))?
.get(&key)
.and_then(Weak::upgrade)
{
return Ok(existing);
}
let mut by_uri = self
.by_uri
.write()
.map_err(|_| AxiomError::lock_poisoned("markdown gate registry"))?;
if let Some(existing) = by_uri.get(&key).and_then(Weak::upgrade) {
return Ok(existing);
}
if by_uri.len() >= MARKDOWN_EDIT_GATE_SWEEP_THRESHOLD {
by_uri.retain(|_, gate| gate.strong_count() > 0);
}
let created = Arc::new(RwLock::new(()));
by_uri.insert(key, Arc::downgrade(&created));
Ok(created)
}
}
#[derive(Clone)]
pub struct AxiomSync {
pub fs: LocalContextFs,
pub state: SqliteStateStore,
pub index: Arc<RwLock<InMemoryIndex>>,
config: Arc<AppConfig>,
markdown_edit_gates: Arc<MarkdownEditGates>,
ontology_schema_cache: Arc<RwLock<Option<OntologySchemaCacheEntry>>>,
parser_registry: ParserRegistry,
drr: DrrEngine,
}
impl std::fmt::Debug for AxiomSync {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AxiomSync").finish_non_exhaustive()
}
}
impl AxiomSync {
pub fn new(root_dir: impl Into<PathBuf>) -> Result<Self> {
let root = root_dir.into();
fs::create_dir_all(&root)?;
let config = Arc::new(AppConfig::from_env()?);
crate::embedding::configure_runtime(config.embedding.clone())?;
let fs = LocalContextFs::new(&root);
let state = SqliteStateStore::open(resolve_state_store_path(&root)?)?;
let index = Arc::new(RwLock::new(InMemoryIndex::new()));
Ok(Self {
fs,
state,
index,
config,
markdown_edit_gates: Arc::new(MarkdownEditGates::default()),
ontology_schema_cache: Arc::new(RwLock::new(None)),
parser_registry: ParserRegistry::new(),
drr: DrrEngine::new(DrrConfig::default()),
})
}
pub fn bootstrap(&self) -> Result<()> {
self.fs.initialize()?;
self.ensure_default_ontology_schema()?;
Ok(())
}
pub fn prepare_runtime(&self) -> Result<()> {
self.bootstrap()?;
self.ensure_scope_tiers()?;
self.initialize_runtime_index()?;
Ok(())
}
pub fn initialize(&self) -> Result<()> {
self.prepare_runtime()
}
fn markdown_gate_for_uri(&self, uri: &AxiomUri) -> Result<DocumentEditGate> {
self.markdown_edit_gates.gate_for(uri)
}
fn ensure_default_ontology_schema(&self) -> Result<()> {
let schema_uri =
AxiomUri::parse(crate::ontology::ONTOLOGY_SCHEMA_URI_V1).map_err(|err| {
AxiomError::Internal(format!("invalid ontology schema URI constant: {err}"))
})?;
if self.fs.exists(&schema_uri) {
return Ok(());
}
self.fs.write(
&schema_uri,
crate::ontology::DEFAULT_ONTOLOGY_SCHEMA_V1_JSON,
true,
)
}
}
fn resolve_state_store_path(root: &Path) -> Result<PathBuf> {
Ok(root.join(STATE_DB_FILE_NAME))
}
#[cfg(test)]
mod tests;