refactor: replace native_db with memdb and add tests

This commit is contained in:
rustmailer
2026-05-14 02:29:23 +08:00
parent 0abaa66a40
commit 5406c4322c
102 changed files with 7225 additions and 2735 deletions
+8 -1
View File
@@ -328,7 +328,14 @@ pub struct Settings {
impl Settings {
pub fn init() -> Self {
let s = Self::parse();
// `cargo test` passes test-filter names and flags (e.g. --nocapture)
// as extra positional arguments. Try the full argv first; if clap
// rejects it, fall back to parsing with only the binary name so that
// the settings come entirely from environment variables.
let args: Vec<String> = std::env::args().collect();
let s = Self::try_parse_from(&args).unwrap_or_else(|_| {
Self::parse_from(std::iter::once(args[0].clone()))
});
if s.bichon_encrypt_password.is_none() && s.bichon_encrypt_password_file.is_none() {
panic!(
"One of --bichon_encrypt_password or --bichon_encrypt_password_file has to be set"
+3 -6
View File
@@ -25,8 +25,7 @@ use crate::{
use std::path::PathBuf;
use std::sync::LazyLock;
pub const META_FILE: &str = "meta.db";
pub const MAILBOX_FILE: &str = "mailbox.db";
const MEMDB_DIR: &str = "memdb";
const INDICES: &str = "bichon-indices";
const MAIL_METADATA: &str = "mail_metadata";
const ATTACHMENT_METADATA: &str = "attachment_metadata";
@@ -43,8 +42,7 @@ pub static DATA_DIR_MANAGER: LazyLock<DataDirManager> =
#[derive(Debug)]
pub struct DataDirManager {
pub root_dir: PathBuf,
pub meta_db: PathBuf,
pub mailbox_db: PathBuf,
pub memdb_dir: PathBuf,
pub temp_dir: PathBuf,
pub tls_cert: PathBuf,
pub tls_key: PathBuf,
@@ -84,8 +82,7 @@ impl DataDirManager {
Self {
root_dir: root_dir.clone(),
meta_db: root_dir.join(META_FILE),
mailbox_db: root_dir.join(MAILBOX_FILE),
memdb_dir: root_dir.join(MEMDB_DIR),
tls_key: root_dir.join(TLS_KEY),
tls_cert: root_dir.join(TLS_CERT),
log_dir: root_dir.join(LOG_DIR),
+39 -60
View File
@@ -16,31 +16,23 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
use native_db::*;
use native_model::{native_model, Model};
//use poem_openapi::Object;
use serde::{Deserialize, Serialize};
use crate::{
id,
{
database::{
async_find_impl, delete_impl, insert_impl, list_all_impl, manager::DB_MANAGER,
update_impl,
},
error::{code::ErrorCode, BichonResult},
utils::net::parse_proxy_addr,
database::{
delete_impl, find_impl, insert_impl, list_all_impl, manager::DB_MANAGER, update_impl,
MemDbModel,
},
raise_error, utc_now,
error::{code::ErrorCode, BichonResult},
id, raise_error, utc_now,
utils::net::parse_proxy_addr,
};
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "web-api", derive(poem_openapi::Object))]
#[native_model(id = 8, version = 1)]
#[native_db]
pub struct Proxy {
/// The unique identifier for this proxy configuration.
#[primary_key]
pub id: u64,
/// The proxy URL (e.g., socks5://127.0.0.1:1080) used to route network requests.
@@ -53,6 +45,15 @@ pub struct Proxy {
pub updated_at: i64,
}
impl MemDbModel for Proxy {
fn collection() -> &'static str {
"proxies"
}
fn key(&self) -> String {
self.id.to_string()
}
}
impl Proxy {
/// Create a new Proxy instance with the given URL and timestamps.
pub fn new(url: String) -> Self {
@@ -64,59 +65,37 @@ impl Proxy {
}
}
pub async fn get(id: u64) -> BichonResult<Proxy> {
async_find_impl(DB_MANAGER.meta_db(), id)
.await?
.ok_or_else(|| {
raise_error!(
format!("Proxy with id={} not found", id),
ErrorCode::ResourceNotFound
)
})
}
pub async fn list_all() -> BichonResult<Vec<Proxy>> {
list_all_impl(DB_MANAGER.meta_db()).await
}
pub async fn delete(id: u64) -> BichonResult<()> {
delete_impl(DB_MANAGER.meta_db(), move |rw| {
rw.get()
.primary::<Proxy>(id)
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?
.ok_or_else(|| raise_error!("proxy missing".into(), ErrorCode::InternalError))
pub fn get(id: u64) -> BichonResult<Proxy> {
let key = id.to_string();
find_impl::<Proxy>(DB_MANAGER.db(), &key)?.ok_or_else(|| {
raise_error!(
format!("Proxy with id={} not found", id),
ErrorCode::ResourceNotFound
)
})
.await
}
pub async fn update(id: u64, url: String) -> BichonResult<()> {
update_impl(
DB_MANAGER.meta_db(),
move |rw| {
rw.get()
.primary::<Proxy>(id)
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?
.ok_or_else(|| {
raise_error!(
format!("Proxy with id={} not found", id),
ErrorCode::ResourceNotFound
)
})
},
move |current| {
let mut updated = current.clone();
updated.url = url;
updated.updated_at = utc_now!();
Ok(updated)
},
)
.await?;
pub fn list_all() -> BichonResult<Vec<Proxy>> {
list_all_impl::<Proxy>(DB_MANAGER.db())
}
pub fn delete(id: u64) -> BichonResult<()> {
delete_impl::<Proxy>(DB_MANAGER.db(), &id.to_string())
}
pub fn update(id: u64, url: String) -> BichonResult<()> {
update_impl(DB_MANAGER.db(), &id.to_string(), move |current: Proxy| {
let mut updated = current.clone();
updated.url = url;
updated.updated_at = utc_now!();
Ok(updated)
})?;
Ok(())
}
pub async fn save(&self) -> BichonResult<()> {
pub fn save(&self) -> BichonResult<()> {
self.validate()?;
insert_impl(DB_MANAGER.meta_db(), self.to_owned()).await
insert_impl(DB_MANAGER.db(), self.to_owned())
}
/// Validate that the URL is a valid SOCKS5 proxy URL.
-5
View File
@@ -16,15 +16,10 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
use native_db::*;
use native_model::{native_model, Model};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
#[native_model(id = 2, version = 1)]
#[native_db]
pub struct SystemSetting {
#[primary_key]
pub key: String,
pub value: String,
pub created_at: i64,