use std::path::Path;
use std::sync::Arc;
use anyhow::{Context, Result};
use super::{BasemindServer, ServerOptions};
use crate::store::{LockHolder, Store};
const DUPLEX_BUFFER: usize = 1 << 20;
const GIT_CACHE_MEM: usize = 1024;
fn spawn_over_duplex(server: BasemindServer) -> tokio::io::DuplexStream {
use rmcp::ServiceExt;
let (client_end, server_end) = tokio::io::duplex(DUPLEX_BUFFER);
tokio::spawn(async move {
match server.serve(server_end).await {
Ok(running) => {
if let Err(error) = running.waiting().await {
tracing::debug!(%error, "in-memory serve: session ended with error");
}
}
Err(error) => tracing::debug!(%error, "in-memory serve: handshake failed"),
}
});
client_end
}
type SupportBits = (
Arc<crate::config::Config>,
Option<Arc<crate::git::Repo>>,
Arc<crate::git_cache::GitCache>,
);
fn build_support_bits(root: &Path) -> Result<SupportBits> {
let basemind_dir = crate::store::workspace_cache_dir(root);
let config = Arc::new(crate::config::load(root).unwrap_or_else(|_| crate::config::default_for_root(root)));
let repo = crate::git::Repo::discover(root).ok().map(Arc::new);
let git_cache =
Arc::new(crate::git_cache::GitCache::open(&basemind_dir, GIT_CACHE_MEM, false).context("open git cache")?);
Ok((config, repo, git_cache))
}
pub async fn serve_in_memory(root: &Path, view: &str) -> Result<tokio::io::DuplexStream> {
serve_in_memory_inner(root, view, None).await
}
pub async fn serve_in_memory_lean(root: &Path, view: &str, lean: bool) -> Result<tokio::io::DuplexStream> {
serve_in_memory_inner(root, view, Some(lean)).await
}
async fn serve_in_memory_inner(root: &Path, view: &str, lean: Option<bool>) -> Result<tokio::io::DuplexStream> {
let (store, read_only) = match Store::open_with_holder(root, view, LockHolder::Serve) {
Ok(store) => (store, false),
Err(error) if error.is_lock_contention() => (Store::open_read_only(root, view)?, true),
Err(error) => return Err(anyhow::Error::new(error).context("open store")),
};
let (config, repo, git_cache) = build_support_bits(root)?;
let options = ServerOptions {
read_only,
..ServerOptions::default()
};
let server = BasemindServer::new_with_options(store, root.to_path_buf(), config, repo, git_cache, options);
if let Some(lean) = lean {
server.state.lean.store(lean, std::sync::atomic::Ordering::Relaxed);
}
Ok(spawn_over_duplex(server))
}
#[cfg(all(feature = "comms", any(unix, windows)))]
pub async fn serve_in_memory_daemon_writer(root: &Path, view: &str) -> Result<tokio::io::DuplexStream> {
let store = Store::open_read_only_no_index(root, view).context("open store blobs-only")?;
let (config, repo, git_cache) = build_support_bits(root)?;
let options = ServerOptions {
read_only: true,
daemon_writer: true,
..ServerOptions::default()
};
let server = BasemindServer::new_with_options(store, root.to_path_buf(), config, repo, git_cache, options);
Ok(spawn_over_duplex(server))
}