refactor: optimize item service creation by creating it once per connection

Co-authored-by: aider (openai/andrew/openrouter/qwen/qwen3-coder) <aider@aider.chat>
This commit is contained in:
Andrew Phillips
2025-08-25 20:27:21 -03:00
parent 7eefb64d15
commit 1f11351d9b
4 changed files with 24 additions and 22 deletions

View File

@@ -13,6 +13,7 @@ use tower_http::cors::CorsLayer;
use tower::ServiceBuilder;
use tower_http::trace::TraceLayer;
use crate::config;
use crate::services::item_service::ItemService;
pub mod common;
mod api;
@@ -53,17 +54,21 @@ pub fn mode_server(
password_hash: settings.server_password_hash(),
};
// Create ItemService once
let item_service = ItemService::new(data_path.clone());
// We need to move the connection into the async runtime
let rt = tokio::runtime::Runtime::new()?;
// Take ownership of the connection and move it into the async runtime
let owned_conn = std::mem::replace(conn, rusqlite::Connection::open_in_memory()?);
rt.block_on(run_server(server_config, owned_conn, data_path))
rt.block_on(run_server(server_config, owned_conn, data_path, item_service))
}
async fn run_server(
config: common::ServerConfig,
conn: rusqlite::Connection,
data_dir: PathBuf,
item_service: ItemService,
) -> Result<()> {
// Construct address with port
let bind_address = if let Some(port) = config.port {
@@ -80,6 +85,7 @@ async fn run_server(
let state = AppState {
db: db_conn,
data_dir: data_dir.clone(),
item_service: Arc::new(item_service),
};
// Create MCP router

View File

@@ -43,7 +43,7 @@ pub async fn handle_list_items(
.map(|s| s.split(',').map(|t| t.trim().to_string()).collect())
.unwrap_or_default();
let item_service = AsyncItemService::new(state.data_dir.clone(), state.db.clone());
let item_service = AsyncItemService::new(state.data_dir.clone(), state.db.clone(), state.item_service.clone());
let mut items_with_meta = item_service
.list_items(tags, HashMap::new())
.await
@@ -166,7 +166,7 @@ pub async fn handle_get_item_latest_content(
.map(|s| s.split(',').map(|t| t.trim().to_string()).collect())
.unwrap_or_default();
let item_service = AsyncItemService::new(state.data_dir.clone(), state.db.clone());
let item_service = AsyncItemService::new(state.data_dir.clone(), state.db.clone(), state.item_service.clone());
// First get the item metadata to check if it's binary and get MIME type
let item_with_meta = item_service
@@ -220,7 +220,7 @@ pub async fn handle_get_item_content(
return Err(StatusCode::BAD_REQUEST);
}
let item_service = AsyncItemService::new(state.data_dir.clone(), state.db.clone());
let item_service = AsyncItemService::new(state.data_dir.clone(), state.db.clone(), state.item_service.clone());
stream_item_content_response(&item_service, item_id, params.allow_binary, params.offset, params.length).await
}
@@ -314,7 +314,7 @@ pub async fn handle_get_item_latest_meta(
.map(|s| s.split(',').map(|t| t.trim().to_string()).collect())
.unwrap_or_default();
let item_service = AsyncItemService::new(state.data_dir.clone(), state.db.clone());
let item_service = AsyncItemService::new(state.data_dir.clone(), state.db.clone(), state.item_service.clone());
match item_service.find_item(vec![], tags, HashMap::new()).await {
Ok(item_with_meta) => {
@@ -361,7 +361,7 @@ pub async fn handle_get_item_meta(
State(state): State<AppState>,
Path(item_id): Path<i64>,
) -> Result<Json<ApiResponse<HashMap<String, String>>>, StatusCode> {
let item_service = AsyncItemService::new(state.data_dir.clone(), state.db.clone());
let item_service = AsyncItemService::new(state.data_dir.clone(), state.db.clone(), state.item_service.clone());
match item_service.get_item(item_id).await {
Ok(item_with_meta) => {

View File

@@ -15,6 +15,7 @@ use std::sync::Arc;
use std::time::Instant;
use tokio::sync::Mutex;
use utoipa::ToSchema;
use crate::services::item_service::ItemService;
#[derive(Debug, Clone)]
pub struct ServerConfig {
@@ -28,6 +29,7 @@ pub struct ServerConfig {
pub struct AppState {
pub db: Arc<Mutex<rusqlite::Connection>>,
pub data_dir: PathBuf,
pub item_service: Arc<ItemService>,
}
#[derive(Serialize, Deserialize, ToSchema)]