don't use strings for paths
This commit is contained in:
		| @@ -1,4 +1,4 @@ | ||||
| use std::path::PathBuf; | ||||
| use std::path::{Path, PathBuf}; | ||||
| use std::sync::{Arc, OnceLock, Mutex, RwLock}; | ||||
| use std::collections::HashMap; | ||||
|  | ||||
| @@ -35,11 +35,11 @@ static DATA_STORAGES: OnceLock<RwLock<HashMap<u64, Arc<dyn StorageBackend>>>> = | ||||
| static DATA_INIT_LOCK: Mutex<()> = Mutex::new(()); | ||||
|  | ||||
| fn init_admin_storage( | ||||
|     base_dir: &str, | ||||
|     base_dir: &Path, | ||||
|     backend: options::BackendType, | ||||
|     admin_secret: &str, | ||||
| ) -> Result<Arc<dyn StorageBackend>, DBError> { | ||||
|     let db_file = PathBuf::from(base_dir).join("0.db"); | ||||
|     let db_file = base_dir.join("0.db"); | ||||
|     if let Some(parent_dir) = db_file.parent() { | ||||
|         std::fs::create_dir_all(parent_dir).map_err(|e| { | ||||
|             DBError(format!("Failed to create directory {}: {}", parent_dir.display(), e)) | ||||
| @@ -57,24 +57,25 @@ fn init_admin_storage( | ||||
|  | ||||
| // Get or initialize a cached handle to admin DB 0 per base_dir (thread-safe, no double-open race) | ||||
| pub fn open_admin_storage( | ||||
|     base_dir: &str, | ||||
|     base_dir: &Path, | ||||
|     backend: options::BackendType, | ||||
|     admin_secret: &str, | ||||
| ) -> Result<Arc<dyn StorageBackend>, DBError> { | ||||
|     let map = ADMIN_STORAGES.get_or_init(|| RwLock::new(HashMap::new())); | ||||
|     let key = base_dir.display().to_string(); | ||||
|     // Fast path | ||||
|     if let Some(st) = map.read().unwrap().get(base_dir) { | ||||
|     if let Some(st) = map.read().unwrap().get(&key) { | ||||
|         return Ok(st.clone()); | ||||
|     } | ||||
|     // Slow path with write lock | ||||
|     { | ||||
|         let mut w = map.write().unwrap(); | ||||
|         if let Some(st) = w.get(base_dir) { | ||||
|         if let Some(st) = w.get(&key) { | ||||
|             return Ok(st.clone()); | ||||
|         } | ||||
|  | ||||
|         // Detect existing 0.db backend by filesystem, if present. | ||||
|         let admin_path = PathBuf::from(base_dir).join("0.db"); | ||||
|         let admin_path = base_dir.join("0.db"); | ||||
|         let detected = if admin_path.exists() { | ||||
|             if admin_path.is_file() { | ||||
|                 Some(options::BackendType::Redb) | ||||
| @@ -102,14 +103,14 @@ pub fn open_admin_storage( | ||||
|         }; | ||||
|  | ||||
|         let st = init_admin_storage(base_dir, effective_backend, admin_secret)?; | ||||
|         w.insert(base_dir.to_string(), st.clone()); | ||||
|         w.insert(key, st.clone()); | ||||
|         Ok(st) | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Ensure admin structures exist in encrypted DB 0 | ||||
| pub fn ensure_bootstrap( | ||||
|     base_dir: &str, | ||||
|     base_dir: &Path, | ||||
|     backend: options::BackendType, | ||||
|     admin_secret: &str, | ||||
| ) -> Result<(), DBError> { | ||||
| @@ -125,7 +126,7 @@ pub fn ensure_bootstrap( | ||||
|  | ||||
| // Get or initialize a shared handle to a data DB (> 0), avoiding double-open across subsystems | ||||
| pub fn open_data_storage( | ||||
|     base_dir: &str, | ||||
|     base_dir: &Path, | ||||
|     backend: options::BackendType, | ||||
|     admin_secret: &str, | ||||
|     id: u64, | ||||
| @@ -159,7 +160,7 @@ pub fn open_data_storage( | ||||
|     // 2) If missing, sniff filesystem (file => Redb, dir => Sled), then persist into admin meta | ||||
|     // 3) Fallback to requested 'backend' (startup default) if nothing else is known | ||||
|     let meta_backend = get_database_backend(base_dir, backend.clone(), admin_secret, id).ok().flatten(); | ||||
|     let db_path = PathBuf::from(base_dir).join(format!("{}.db", id)); | ||||
|     let db_path = base_dir.join(format!("{}.db", id)); | ||||
|     let sniffed_backend = if db_path.exists() { | ||||
|         if db_path.is_file() { | ||||
|             Some(options::BackendType::Redb) | ||||
| @@ -214,7 +215,7 @@ pub fn open_data_storage( | ||||
|  | ||||
| // Allocate the next DB id and persist new pointer | ||||
| pub fn allocate_next_id( | ||||
|     base_dir: &str, | ||||
|     base_dir: &Path, | ||||
|     backend: options::BackendType, | ||||
|     admin_secret: &str, | ||||
| ) -> Result<u64, DBError> { | ||||
| @@ -238,7 +239,7 @@ pub fn allocate_next_id( | ||||
|  | ||||
| // Check existence of a db id in admin:dbs | ||||
| pub fn db_exists( | ||||
|     base_dir: &str, | ||||
|     base_dir: &Path, | ||||
|     backend: options::BackendType, | ||||
|     admin_secret: &str, | ||||
|     id: u64, | ||||
| @@ -249,7 +250,7 @@ pub fn db_exists( | ||||
|  | ||||
| // Get per-db encryption key, if any | ||||
| pub fn get_enc_key( | ||||
|     base_dir: &str, | ||||
|     base_dir: &Path, | ||||
|     backend: options::BackendType, | ||||
|     admin_secret: &str, | ||||
|     id: u64, | ||||
| @@ -260,7 +261,7 @@ pub fn get_enc_key( | ||||
|  | ||||
| // Set per-db encryption key (called during create) | ||||
| pub fn set_enc_key( | ||||
|     base_dir: &str, | ||||
|     base_dir: &Path, | ||||
|     backend: options::BackendType, | ||||
|     admin_secret: &str, | ||||
|     id: u64, | ||||
| @@ -272,7 +273,7 @@ pub fn set_enc_key( | ||||
|  | ||||
| // Set database public flag | ||||
| pub fn set_database_public( | ||||
|     base_dir: &str, | ||||
|     base_dir: &Path, | ||||
|     backend: options::BackendType, | ||||
|     admin_secret: &str, | ||||
|     id: u64, | ||||
| @@ -286,7 +287,7 @@ pub fn set_database_public( | ||||
|  | ||||
| // Persist per-db backend type in admin metadata (module-scope) | ||||
| pub fn set_database_backend( | ||||
|     base_dir: &str, | ||||
|     base_dir: &Path, | ||||
|     backend: options::BackendType, | ||||
|     admin_secret: &str, | ||||
|     id: u64, | ||||
| @@ -304,7 +305,7 @@ pub fn set_database_backend( | ||||
| } | ||||
|  | ||||
| pub fn get_database_backend( | ||||
|     base_dir: &str, | ||||
|     base_dir: &Path, | ||||
|     backend: options::BackendType, | ||||
|     admin_secret: &str, | ||||
|     id: u64, | ||||
| @@ -321,7 +322,7 @@ pub fn get_database_backend( | ||||
|  | ||||
| // Set database name | ||||
| pub fn set_database_name( | ||||
|     base_dir: &str, | ||||
|     base_dir: &Path, | ||||
|     backend: options::BackendType, | ||||
|     admin_secret: &str, | ||||
|     id: u64, | ||||
| @@ -335,7 +336,7 @@ pub fn set_database_name( | ||||
|  | ||||
| // Get database name | ||||
| pub fn get_database_name( | ||||
|     base_dir: &str, | ||||
|     base_dir: &Path, | ||||
|     backend: options::BackendType, | ||||
|     admin_secret: &str, | ||||
|     id: u64, | ||||
| @@ -359,7 +360,7 @@ fn load_public( | ||||
|  | ||||
| // Add access key for db (value format: "Read:ts" or "ReadWrite:ts") | ||||
| pub fn add_access_key( | ||||
|     base_dir: &str, | ||||
|     base_dir: &Path, | ||||
|     backend: options::BackendType, | ||||
|     admin_secret: &str, | ||||
|     id: u64, | ||||
| @@ -378,7 +379,7 @@ pub fn add_access_key( | ||||
|  | ||||
| // Delete access key by hash | ||||
| pub fn delete_access_key( | ||||
|     base_dir: &str, | ||||
|     base_dir: &Path, | ||||
|     backend: options::BackendType, | ||||
|     admin_secret: &str, | ||||
|     id: u64, | ||||
| @@ -391,7 +392,7 @@ pub fn delete_access_key( | ||||
|  | ||||
| // List access keys, returning (hash, perms, created_at_secs) | ||||
| pub fn list_access_keys( | ||||
|     base_dir: &str, | ||||
|     base_dir: &Path, | ||||
|     backend: options::BackendType, | ||||
|     admin_secret: &str, | ||||
|     id: u64, | ||||
| @@ -411,7 +412,7 @@ pub fn list_access_keys( | ||||
| // - Ok(Some(Permissions)) when access is allowed | ||||
| // - Ok(None) when not allowed or db missing (caller can distinguish by calling db_exists) | ||||
| pub fn verify_access( | ||||
|     base_dir: &str, | ||||
|     base_dir: &Path, | ||||
|     backend: options::BackendType, | ||||
|     admin_secret: &str, | ||||
|     id: u64, | ||||
| @@ -456,7 +457,7 @@ pub fn verify_access( | ||||
|  | ||||
| // Enumerate all db ids | ||||
| pub fn list_dbs( | ||||
|     base_dir: &str, | ||||
|     base_dir: &Path, | ||||
|     backend: options::BackendType, | ||||
|     admin_secret: &str, | ||||
| ) -> Result<Vec<u64>, DBError> { | ||||
|   | ||||
| @@ -1427,7 +1427,7 @@ async fn incr_cmd(server: &Server, key: &String) -> Result<Protocol, DBError> { | ||||
|  | ||||
| fn config_get_cmd(name: &String, server: &Server) -> Result<Protocol, DBError> { | ||||
|     let value = match name.as_str() { | ||||
|         "dir" => Some(server.option.dir.clone()), | ||||
|         "dir" => Some(server.option.dir.display().to_string()), | ||||
|         "dbfilename" => Some(format!("{}.db", server.selected_db)), | ||||
|         "databases" => Some("16".to_string()), // Hardcoded as per original logic | ||||
|         _ => None, | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| // #![allow(unused_imports)] | ||||
|  | ||||
| use std::path::PathBuf; | ||||
| use tokio::net::TcpListener; | ||||
|  | ||||
| use herodb::server; | ||||
| @@ -13,7 +14,7 @@ use clap::Parser; | ||||
| struct Args { | ||||
|     /// The directory of Redis DB file | ||||
|     #[arg(long)] | ||||
|     dir: String, | ||||
|     dir: PathBuf, | ||||
|  | ||||
|     /// The port of the Redis server, default is 6379 if not specified | ||||
|     #[arg(long)] | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| use std::path::PathBuf; | ||||
|  | ||||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||||
| pub enum BackendType { | ||||
|     Redb, | ||||
| @@ -7,7 +9,7 @@ pub enum BackendType { | ||||
|  | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct DBOption { | ||||
|     pub dir: String, | ||||
|     pub dir: PathBuf, | ||||
|     pub port: u16, | ||||
|     pub debug: bool, | ||||
|     // Deprecated for data DBs; retained for backward-compat on CLI parsing | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| use std::collections::HashMap; | ||||
| use std::path::PathBuf; | ||||
| use std::sync::Arc; | ||||
| use tokio::sync::RwLock; | ||||
| use jsonrpsee::{core::RpcResult, proc_macros::rpc}; | ||||
| @@ -165,7 +166,7 @@ pub trait Rpc { | ||||
| /// RPC Server implementation | ||||
| pub struct RpcServerImpl { | ||||
|     /// Base directory for database files | ||||
|     base_dir: String, | ||||
|     base_dir: PathBuf, | ||||
|     /// Managed database servers | ||||
|     servers: Arc<RwLock<HashMap<u64, Arc<Server>>>>, | ||||
|     /// Default backend type | ||||
| @@ -176,7 +177,7 @@ pub struct RpcServerImpl { | ||||
|  | ||||
| impl RpcServerImpl { | ||||
|     /// Create a new RPC server instance | ||||
|     pub fn new(base_dir: String, backend: crate::options::BackendType, admin_secret: String) -> Self { | ||||
|     pub fn new(base_dir: PathBuf, backend: crate::options::BackendType, admin_secret: String) -> Self { | ||||
|         Self { | ||||
|             base_dir, | ||||
|             servers: Arc::new(RwLock::new(HashMap::new())), | ||||
| @@ -351,7 +352,7 @@ impl RpcServerImpl { | ||||
|             backend, | ||||
|             encrypted, | ||||
|             redis_version: Some("7.0".to_string()), | ||||
|             storage_path: Some(server.option.dir.clone()), | ||||
|             storage_path: Some(server.option.dir.display().to_string()), | ||||
|             size_on_disk, | ||||
|             key_count, | ||||
|             created_at, | ||||
|   | ||||
| @@ -1,11 +1,12 @@ | ||||
| use std::net::SocketAddr; | ||||
| use std::path::PathBuf; | ||||
| use jsonrpsee::server::{ServerBuilder, ServerHandle}; | ||||
| use jsonrpsee::RpcModule; | ||||
|  | ||||
| use crate::rpc::{RpcServer, RpcServerImpl}; | ||||
|  | ||||
| /// Start the RPC server on the specified address | ||||
| pub async fn start_rpc_server(addr: SocketAddr, base_dir: String, backend: crate::options::BackendType, admin_secret: String) -> Result<ServerHandle, Box<dyn std::error::Error + Send + Sync>> { | ||||
| pub async fn start_rpc_server(addr: SocketAddr, base_dir: PathBuf, backend: crate::options::BackendType, admin_secret: String) -> Result<ServerHandle, Box<dyn std::error::Error + Send + Sync>> { | ||||
|     // Create the RPC server implementation | ||||
|     let rpc_impl = RpcServerImpl::new(base_dir, backend, admin_secret); | ||||
|  | ||||
| @@ -34,7 +35,7 @@ mod tests { | ||||
|     #[tokio::test] | ||||
|     async fn test_rpc_server_startup() { | ||||
|         let addr = "127.0.0.1:0".parse().unwrap(); // Use port 0 for auto-assignment | ||||
|         let base_dir = "/tmp/test_rpc".to_string(); | ||||
|         let base_dir = PathBuf::from("/tmp/test_rpc"); | ||||
|         let backend = crate::options::BackendType::Redb; // Default for test | ||||
|  | ||||
|         let handle = start_rpc_server(addr, base_dir, backend, "test-admin".to_string()).await.unwrap(); | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| use herodb::{server::Server, options::DBOption}; | ||||
| use std::path::PathBuf; | ||||
| use std::time::Duration; | ||||
| use tokio::io::{AsyncReadExt, AsyncWriteExt}; | ||||
| use tokio::net::TcpStream; | ||||
| @@ -22,7 +23,7 @@ async fn debug_hset_simple() { | ||||
|      | ||||
|     let port = 16500; | ||||
|     let option = DBOption { | ||||
|         dir: test_dir.to_string(), | ||||
|         dir: PathBuf::from(test_dir), | ||||
|         port, | ||||
|         debug: false, | ||||
|         encrypt: false, | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| use herodb::{server::Server, options::DBOption}; | ||||
| use std::path::PathBuf; | ||||
| use std::time::Duration; | ||||
| use tokio::io::{AsyncReadExt, AsyncWriteExt}; | ||||
| use tokio::net::TcpStream; | ||||
| @@ -13,7 +14,7 @@ async fn debug_hset_return_value() { | ||||
|     std::fs::create_dir_all(&test_dir).unwrap(); | ||||
|      | ||||
|     let option = DBOption { | ||||
|         dir: test_dir.to_string(), | ||||
|         dir: PathBuf::from(test_dir), | ||||
|         port: 16390, | ||||
|         debug: false, | ||||
|         encrypt: false, | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| use herodb::{server::Server, options::DBOption}; | ||||
| use std::path::PathBuf; | ||||
| use std::time::Duration; | ||||
| use tokio::io::{AsyncReadExt, AsyncWriteExt}; | ||||
| use tokio::net::TcpStream; | ||||
| @@ -17,7 +18,7 @@ async fn start_test_server(test_name: &str) -> (Server, u16) { | ||||
|     std::fs::create_dir_all(&test_dir).unwrap(); | ||||
|      | ||||
|     let option = DBOption { | ||||
|         dir: test_dir, | ||||
|         dir: PathBuf::from(test_dir), | ||||
|         port, | ||||
|         debug: true, | ||||
|         encrypt: false, | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| use herodb::rpc::{BackendType, DatabaseConfig}; | ||||
| use herodb::admin_meta; | ||||
| use herodb::options::BackendType as OptionsBackendType; | ||||
| use std::path::Path; | ||||
|  | ||||
| #[tokio::test] | ||||
| async fn test_rpc_server_basic() { | ||||
| @@ -70,11 +71,11 @@ async fn test_database_name_persistence() { | ||||
|     let _ = std::fs::remove_dir_all(base_dir); | ||||
|  | ||||
|     // Set the database name | ||||
|     admin_meta::set_database_name(base_dir, backend.clone(), admin_secret, db_id, test_name) | ||||
|     admin_meta::set_database_name(Path::new(base_dir), backend.clone(), admin_secret, db_id, test_name) | ||||
|         .expect("Failed to set database name"); | ||||
|  | ||||
|     // Retrieve the database name | ||||
|     let retrieved_name = admin_meta::get_database_name(base_dir, backend, admin_secret, db_id) | ||||
|     let retrieved_name = admin_meta::get_database_name(Path::new(base_dir), backend, admin_secret, db_id) | ||||
|         .expect("Failed to get database name"); | ||||
|  | ||||
|     // Verify the name matches | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| use herodb::{server::Server, options::DBOption}; | ||||
| use std::path::PathBuf; | ||||
| use std::time::Duration; | ||||
| use tokio::time::sleep; | ||||
| use tokio::io::{AsyncReadExt, AsyncWriteExt}; | ||||
| @@ -19,7 +20,7 @@ async fn start_test_server(test_name: &str) -> (Server, u16) { | ||||
|     std::fs::create_dir_all(&test_dir).unwrap(); | ||||
|      | ||||
|     let option = DBOption { | ||||
|         dir: test_dir, | ||||
|         dir: PathBuf::from(test_dir), | ||||
|         port, | ||||
|         debug: true, | ||||
|         encrypt: false, | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| use herodb::{server::Server, options::DBOption}; | ||||
| use std::path::PathBuf; | ||||
| use std::time::Duration; | ||||
| use tokio::io::{AsyncReadExt, AsyncWriteExt}; | ||||
| use tokio::net::TcpStream; | ||||
| @@ -17,7 +18,7 @@ async fn start_test_server(test_name: &str) -> (Server, u16) { | ||||
|     std::fs::create_dir_all(&test_dir).unwrap(); | ||||
|      | ||||
|     let option = DBOption { | ||||
|         dir: test_dir, | ||||
|         dir: PathBuf::from(test_dir), | ||||
|         port, | ||||
|         debug: false, | ||||
|         encrypt: false, | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| use herodb::{options::DBOption, server::Server}; | ||||
| use std::path::PathBuf; | ||||
| use tokio::io::{AsyncReadExt, AsyncWriteExt}; | ||||
| use tokio::net::TcpStream; | ||||
| use tokio::time::{sleep, Duration}; | ||||
| @@ -17,7 +18,7 @@ async fn start_test_server(test_name: &str) -> (Server, u16) { | ||||
|     std::fs::create_dir_all(&test_dir).unwrap(); | ||||
|  | ||||
|     let option = DBOption { | ||||
|         dir: test_dir, | ||||
|         dir: PathBuf::from(test_dir), | ||||
|         port, | ||||
|         debug: false, | ||||
|         encrypt: false, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user