refactor: apply rust best practices and fix memory optimizations

- Optimized memory allocation in router.rs by offloading JSON serialization to spawn_blocking and using references.
- Prevented full graph duplication on startup in state.rs index rebuild.
- Eliminated massive String allocations in QueryGraphPathHandler BFS loops.
- Avoided temporary Strings in VisualizeGraphHandler via inline writing.
- Fixed O(N) full-graph deduplication in MergeEntitiesHandler to scale efficiently.
This commit is contained in:
Riz Ashraf committed 2026-09-22 22:01:38 +01:00
1 parent 251757f8fc
commit 37003be620
17 files changed
+399 -198

No files matched your search

+30 -22
View File
@@ -195,30 +195,39 @@ impl MemoryHandler {
}
"resources/read" => {
let params = req.get("params").unwrap_or(&serde_json::Value::Null);
let uri = params.get("uri").and_then(|u| u.as_str()).unwrap_or("");
let text = match uri {
let uri = params
.get("uri")
.and_then(|u| u.as_str())
.unwrap_or("")
.to_string();
let state_clone = Arc::clone(&self.state);
let uri_clone = uri.clone();
let text = match tokio::task::spawn_blocking(move || match uri_clone.as_str() {
"memory://graph/entities" => {
let graph = self.state.graph.cache.read().unwrap();
let data: Vec<_> = graph.entities.values().cloned().collect();
serde_json::to_string_pretty(&data).unwrap_or_default()
let graph = state_clone.graph.cache.read().unwrap();
let data: Vec<_> = graph.entities.values().collect();
Some(serde_json::to_string_pretty(&data).unwrap_or_default())
}
"memory://graph/relations" => {
let graph = self.state.graph.cache.read().unwrap();
let data = graph.relations.clone();
serde_json::to_string_pretty(&data).unwrap_or_default()
let graph = state_clone.graph.cache.read().unwrap();
let data = &graph.relations;
Some(serde_json::to_string_pretty(&data).unwrap_or_default())
}
"memory://tasks/active" => {
let tasks = self.state.tasks.cache.read().unwrap();
let data: Vec<_> = tasks.iter()
let tasks = state_clone.tasks.cache.read().unwrap();
let data: Vec<_> = tasks
.iter()
.filter(|t| t.status != "completed" && t.status != "done")
.cloned()
.collect();
serde_json::to_string_pretty(&data).unwrap_or_default()
}
_ => {
return Some(crate::mcp::error(id, -32602, "Resource not found"));
Some(serde_json::to_string_pretty(&data).unwrap_or_default())
}
_ => None,
})
.await
{
Ok(Some(text)) => text,
_ => return Some(crate::mcp::error(id, -32602, "Resource not found")),
};
let payload = serde_json::json!({
@@ -245,7 +254,7 @@ impl MemoryHandler {
"prompts/get" => {
let params = req.get("params").unwrap_or(&serde_json::Value::Null);
let name = params.get("name").and_then(|n| n.as_str()).unwrap_or("");
if name == "analyze_tech_debt" {
let payload = serde_json::json!({
"messages": [
@@ -318,19 +327,19 @@ impl MemoryHandler {
#[cfg(test)]
mod tests {
use super::*;
use tempfile::tempdir;
use serde_json::json;
use tempfile::tempdir;
#[tokio::test]
async fn test_memory_handler_tools_registration() {
let dir = tempdir().unwrap();
let state = Arc::new(MemoryState::new(dir.path().to_str().unwrap()));
let handler = MemoryHandler::new(state);
// Assert some known tools are registered
assert!(handler.tools.contains_key("create_entities"));
assert!(handler.tools.contains_key("add_task"));
// Ensure we can fetch list of tools
let list_tools_req = json!({
"jsonrpc": "2.0",
@@ -338,11 +347,10 @@ mod tests {
"method": "tools/list",
"params": {}
});
let res_list = handler.handle_request(list_tools_req).await.unwrap();
assert_eq!(res_list["jsonrpc"], "2.0");
assert_eq!(res_list["id"], 1);
assert!(res_list["result"]["tools"].as_array().unwrap().len() > 10);
}
}