use std::sync::Arc;
use super::daemon::Broker;
use super::protocol::CommsResponse;
impl Broker {
pub(super) async fn on_resolved_refs(
&self,
root: std::path::PathBuf,
query: crate::comms::resolved_proto::ResolvedRefQuery,
) -> CommsResponse {
self.mark_active().await;
let pool = Arc::clone(&self.workspaces);
match tokio::task::spawn_blocking(move || {
pool.with_workspace(&root, |store| resolve_refs_against(store, &query))
})
.await
{
Ok(Ok(result)) => CommsResponse::ResolvedRefs(result),
Ok(Err(error)) => CommsResponse::Error {
code: "resolved_refs_failed".to_string(),
message: error.to_string(),
},
Err(join) => CommsResponse::Error {
code: "resolved_refs_panicked".to_string(),
message: join.to_string(),
},
}
}
#[cfg(not(feature = "code-search"))]
pub(super) async fn on_code_search_lanes(
&self,
_root: std::path::PathBuf,
_query: crate::comms::code_search_proto::CodeSearchLaneQuery,
) -> CommsResponse {
CommsResponse::Error {
code: "code_search_unavailable".to_string(),
message: "this daemon was built without the `code-search` feature, so it holds no BM25 \
index and cannot answer the keyword or exact lane"
.to_string(),
}
}
#[cfg(feature = "code-search")]
pub(super) async fn on_code_search_lanes(
&self,
root: std::path::PathBuf,
query: crate::comms::code_search_proto::CodeSearchLaneQuery,
) -> CommsResponse {
self.mark_active().await;
let pool = Arc::clone(&self.workspaces);
match tokio::task::spawn_blocking(move || {
pool.with_workspace(&root, |store| code_search_lanes_against(store, &query))
})
.await
{
Ok(Ok(Ok(result))) => CommsResponse::CodeSearchLanes(result),
Ok(Ok(Err(unavailable))) => CommsResponse::Error {
code: "code_search_index_unavailable".to_string(),
message: unavailable,
},
Ok(Err(error)) => CommsResponse::Error {
code: "code_search_lanes_failed".to_string(),
message: error.to_string(),
},
Err(join) => CommsResponse::Error {
code: "code_search_lanes_panicked".to_string(),
message: join.to_string(),
},
}
}
#[cfg(feature = "memory")]
pub(super) async fn on_memory(
&self,
root: std::path::PathBuf,
scope: String,
op: super::memory_proto::MemoryOp,
) -> CommsResponse {
self.mark_active().await;
let pool = Arc::clone(&self.workspaces);
let outcome = tokio::task::spawn_blocking(move || {
pool.with_workspace_mut(&root, |store| {
let idx = store
.index_db
.as_ref()
.ok_or(crate::mcp::memory_ops::MemoryOpError::IndexUnavailable)?;
crate::mcp::memory_ops::run_memory_op(idx, &scope, &op)
})
})
.await;
match outcome {
Ok(Ok(Ok(outcome))) => CommsResponse::Memory(outcome),
Ok(Ok(Err(error))) => CommsResponse::Error {
code: "memory_op_failed".to_string(),
message: error.to_string(),
},
Ok(Err(error)) => CommsResponse::Error {
code: "memory_workspace_failed".to_string(),
message: error.to_string(),
},
Err(join) => CommsResponse::Error {
code: "memory_panicked".to_string(),
message: join.to_string(),
},
}
}
#[cfg(feature = "memory")]
pub(super) async fn on_governance(
&self,
root: std::path::PathBuf,
scope: String,
op: super::proposals_proto::GovernanceOp,
) -> CommsResponse {
self.mark_active().await;
let pool = Arc::clone(&self.workspaces);
let outcome = tokio::task::spawn_blocking(move || {
pool.with_workspace_mut(&root, |store| {
let idx = store
.index_db
.as_ref()
.ok_or(crate::mcp::memory_ops::MemoryOpError::IndexUnavailable)?;
crate::mcp::proposals_ops::run_governance_op(idx, &scope, &op)
})
})
.await;
match outcome {
Ok(Ok(Ok(outcome))) => CommsResponse::Governance(outcome),
Ok(Ok(Err(error))) => CommsResponse::Error {
code: "governance_op_failed".to_string(),
message: error.to_string(),
},
Ok(Err(error)) => CommsResponse::Error {
code: "governance_workspace_failed".to_string(),
message: error.to_string(),
},
Err(join) => CommsResponse::Error {
code: "governance_panicked".to_string(),
message: join.to_string(),
},
}
}
}
pub(crate) fn resolve_refs_against(
store: &crate::store::Store,
query: &crate::comms::resolved_proto::ResolvedRefQuery,
) -> crate::comms::resolved_proto::ResolvedRefResult {
use crate::comms::resolved_proto::{ResolvedRefQuery, ResolvedRefResult};
match query {
ResolvedRefQuery::ReferencesTo { def_path, def_start } => {
ResolvedRefResult::References(crate::query::resolved_references(store, def_path, *def_start))
}
ResolvedRefQuery::DefinitionOf { use_path, use_start } => {
ResolvedRefResult::Definition(crate::query::definition_of(store, use_path, *use_start))
}
}
}
#[cfg(feature = "code-search")]
pub(crate) fn code_search_lanes_against(
store: &crate::store::Store,
query: &crate::comms::code_search_proto::CodeSearchLaneQuery,
) -> Result<crate::comms::code_search_proto::CodeSearchLaneResult, String> {
use crate::comms::code_search_proto::CodeSearchLaneResult;
let limit = (query.limit as usize).min(MAX_FORWARDED_LANE_LIMIT);
let Some(db) = store.index_db.as_ref() else {
return Err(
"the daemon holds this workspace without a fjall index, so neither the keyword nor the \
exact lane can be read"
.to_string(),
);
};
let keyword = crate::search::bm25::bm25_search(db, &query.query, limit)
.into_iter()
.map(|hit| (hit.chunk_id, hit.score))
.collect();
let exact = if query.want_exact {
crate::search::exact::exact_lane_chunk_ids(store, db, &query.query, limit)
} else {
Vec::new()
};
Ok(CodeSearchLaneResult { keyword, exact })
}
#[cfg(feature = "code-search")]
pub(crate) const MAX_FORWARDED_LANE_LIMIT: usize = 200;