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:
@@ -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
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -17,21 +17,21 @@ use tokio_util::io::ReaderStream;
|
||||
pub struct AsyncItemService {
|
||||
pub data_dir: PathBuf,
|
||||
db: Arc<Mutex<Connection>>,
|
||||
item_service: Arc<ItemService>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl AsyncItemService {
|
||||
pub fn new(data_dir: PathBuf, db: Arc<Mutex<Connection>>) -> Self {
|
||||
Self { data_dir, db }
|
||||
pub fn new(data_dir: PathBuf, db: Arc<Mutex<Connection>>, item_service: Arc<ItemService>) -> Self {
|
||||
Self { data_dir, db, item_service }
|
||||
}
|
||||
|
||||
pub async fn get_item(&self, id: i64) -> Result<ItemWithMeta, CoreError> {
|
||||
let data_dir = self.data_dir.clone();
|
||||
let db = self.db.clone();
|
||||
let item_service = self.item_service.clone();
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let conn = db.blocking_lock();
|
||||
let item_service = ItemService::new(data_dir);
|
||||
item_service.get_item(&conn, id)
|
||||
})
|
||||
.await
|
||||
@@ -39,12 +39,11 @@ impl AsyncItemService {
|
||||
}
|
||||
|
||||
pub async fn get_item_content(&self, id: i64) -> Result<ItemWithContent, CoreError> {
|
||||
let data_dir = self.data_dir.clone();
|
||||
let db = self.db.clone();
|
||||
let item_service = self.item_service.clone();
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let conn = db.blocking_lock();
|
||||
let item_service = ItemService::new(data_dir);
|
||||
item_service.get_item_content(&conn, id)
|
||||
})
|
||||
.await
|
||||
@@ -59,13 +58,12 @@ impl AsyncItemService {
|
||||
offset: u64,
|
||||
length: u64,
|
||||
) -> Result<(std::pin::Pin<Box<dyn tokio_stream::Stream<Item = Result<tokio_util::bytes::Bytes, std::io::Error>> + Send>>, String), CoreError> {
|
||||
let data_dir = self.data_dir.clone();
|
||||
let db = self.db.clone();
|
||||
let item_service = self.item_service.clone();
|
||||
|
||||
// Get item metadata first to check binary status and get MIME type
|
||||
let item_with_content = tokio::task::spawn_blocking(move || {
|
||||
let conn = db.blocking_lock();
|
||||
let item_service = ItemService::new(data_dir);
|
||||
item_service.get_item_content(&conn, item_id)
|
||||
})
|
||||
.await
|
||||
@@ -120,12 +118,11 @@ impl AsyncItemService {
|
||||
tags: Vec<String>,
|
||||
meta: HashMap<String, String>,
|
||||
) -> Result<ItemWithMeta, CoreError> {
|
||||
let data_dir = self.data_dir.clone();
|
||||
let db = self.db.clone();
|
||||
let item_service = self.item_service.clone();
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let conn = db.blocking_lock();
|
||||
let item_service = ItemService::new(data_dir);
|
||||
item_service.find_item(&conn, &ids, &tags, &meta)
|
||||
})
|
||||
.await
|
||||
@@ -137,12 +134,11 @@ impl AsyncItemService {
|
||||
tags: Vec<String>,
|
||||
meta: HashMap<String, String>,
|
||||
) -> Result<Vec<ItemWithMeta>, CoreError> {
|
||||
let data_dir = self.data_dir.clone();
|
||||
let db = self.db.clone();
|
||||
let item_service = self.item_service.clone();
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let conn = db.blocking_lock();
|
||||
let item_service = ItemService::new(data_dir);
|
||||
item_service.list_items(&conn, &tags, &meta)
|
||||
})
|
||||
.await
|
||||
@@ -150,12 +146,11 @@ impl AsyncItemService {
|
||||
}
|
||||
|
||||
pub async fn delete_item(&self, id: i64) -> Result<(), CoreError> {
|
||||
let data_dir = self.data_dir.clone();
|
||||
let db = self.db.clone();
|
||||
let item_service = self.item_service.clone();
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let mut conn = db.blocking_lock();
|
||||
let item_service = ItemService::new(data_dir);
|
||||
item_service.delete_item(&mut conn, id)
|
||||
})
|
||||
.await
|
||||
@@ -168,12 +163,11 @@ impl AsyncItemService {
|
||||
tags: Vec<String>,
|
||||
metadata: HashMap<String, String>,
|
||||
) -> Result<ItemWithMeta, CoreError> {
|
||||
let data_dir = self.data_dir.clone();
|
||||
let db = self.db.clone();
|
||||
let item_service = self.item_service.clone();
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let mut conn = db.blocking_lock();
|
||||
let item_service = ItemService::new(data_dir);
|
||||
item_service.save_item_from_mcp(&content, &tags, &metadata, &mut conn)
|
||||
})
|
||||
.await
|
||||
|
||||
Reference in New Issue
Block a user