mirror of
https://github.com/stalwartlabs/mail-server.git
synced 2025-09-14 16:04:48 +08:00
Support specifying which data types to export (closes #497)
This commit is contained in:
parent
39d0a168d4
commit
58351bdcad
2 changed files with 111 additions and 22 deletions
|
@ -42,7 +42,7 @@ pub(super) enum Op {
|
|||
KeyValue((Vec<u8>, Vec<u8>)),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||
pub(super) enum Family {
|
||||
Property = 0,
|
||||
FtsIndex = 1,
|
||||
|
@ -61,30 +61,61 @@ pub(super) enum Family {
|
|||
|
||||
type TaskHandle = (tokio::task::JoinHandle<()>, std::thread::JoinHandle<()>);
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Eq)]
|
||||
pub struct BackupParams {
|
||||
dest: PathBuf,
|
||||
families: AHashSet<Family>,
|
||||
}
|
||||
|
||||
impl Core {
|
||||
pub async fn backup(&self, dest: PathBuf) {
|
||||
if !dest.exists() {
|
||||
std::fs::create_dir_all(&dest).failed("Failed to create backup directory");
|
||||
} else if !dest.is_dir() {
|
||||
eprintln!("Backup destination {dest:?} is not a directory.");
|
||||
pub async fn backup(&self, params: BackupParams) {
|
||||
if !params.dest.exists() {
|
||||
std::fs::create_dir_all(¶ms.dest).failed("Failed to create backup directory");
|
||||
} else if !params.dest.is_dir() {
|
||||
eprintln!("Backup destination {:?} is not a directory.", params.dest);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
let mut sync_handles = Vec::new();
|
||||
|
||||
for (async_handle, sync_handle) in [
|
||||
self.backup_properties(&dest),
|
||||
self.backup_fts_index(&dest),
|
||||
self.backup_acl(&dest),
|
||||
self.backup_blob(&dest),
|
||||
self.backup_config(&dest),
|
||||
self.backup_lookup(&dest),
|
||||
self.backup_directory(&dest),
|
||||
self.backup_queue(&dest),
|
||||
self.backup_index(&dest),
|
||||
self.backup_bitmaps(&dest),
|
||||
self.backup_logs(&dest),
|
||||
] {
|
||||
params
|
||||
.has_family(Family::Property)
|
||||
.then(|| self.backup_properties(¶ms.dest)),
|
||||
params
|
||||
.has_family(Family::FtsIndex)
|
||||
.then(|| self.backup_fts_index(¶ms.dest)),
|
||||
params
|
||||
.has_family(Family::Acl)
|
||||
.then(|| self.backup_acl(¶ms.dest)),
|
||||
params
|
||||
.has_family(Family::Blob)
|
||||
.then(|| self.backup_blob(¶ms.dest)),
|
||||
params
|
||||
.has_family(Family::Config)
|
||||
.then(|| self.backup_config(¶ms.dest)),
|
||||
params
|
||||
.has_family(Family::LookupValue)
|
||||
.then(|| self.backup_lookup(¶ms.dest)),
|
||||
params
|
||||
.has_family(Family::Directory)
|
||||
.then(|| self.backup_directory(¶ms.dest)),
|
||||
params
|
||||
.has_family(Family::Queue)
|
||||
.then(|| self.backup_queue(¶ms.dest)),
|
||||
params
|
||||
.has_family(Family::Index)
|
||||
.then(|| self.backup_index(¶ms.dest)),
|
||||
params
|
||||
.has_family(Family::Bitmap)
|
||||
.then(|| self.backup_bitmaps(¶ms.dest)),
|
||||
params
|
||||
.has_family(Family::Log)
|
||||
.then(|| self.backup_logs(¶ms.dest)),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
{
|
||||
async_handle.await.failed("Task failed");
|
||||
sync_handles.push(sync_handle);
|
||||
}
|
||||
|
@ -1133,6 +1164,59 @@ impl DeserializeBytes for &[u8] {
|
|||
}
|
||||
}
|
||||
|
||||
impl BackupParams {
|
||||
pub fn new(dest: PathBuf) -> Self {
|
||||
let mut params = Self {
|
||||
dest,
|
||||
families: AHashSet::new(),
|
||||
};
|
||||
|
||||
if let Ok(families) = std::env::var("EXPORT_TYPES") {
|
||||
params.parse_families(&families);
|
||||
}
|
||||
|
||||
params
|
||||
}
|
||||
|
||||
fn parse_families(&mut self, families: &str) {
|
||||
for family in families.split(',') {
|
||||
let family = family.trim();
|
||||
match Family::parse(family) {
|
||||
Ok(family) => {
|
||||
self.families.insert(family);
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("Backup failed: {err}.");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn has_family(&self, family: Family) -> bool {
|
||||
self.families.is_empty() || self.families.contains(&family)
|
||||
}
|
||||
}
|
||||
|
||||
impl Family {
|
||||
pub fn parse(family: &str) -> Result<Self, String> {
|
||||
match family {
|
||||
"property" => Ok(Family::Property),
|
||||
"fts_index" => Ok(Family::FtsIndex),
|
||||
"acl" => Ok(Family::Acl),
|
||||
"blob" => Ok(Family::Blob),
|
||||
"config" => Ok(Family::Config),
|
||||
"lookup" => Ok(Family::LookupValue),
|
||||
"directory" => Ok(Family::Directory),
|
||||
"queue" => Ok(Family::Queue),
|
||||
"index" => Ok(Family::Index),
|
||||
"bitmap" => Ok(Family::Bitmap),
|
||||
"log" => Ok(Family::Log),
|
||||
_ => Err(format!("Unknown family {}", family)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct RawBytes(Vec<u8>);
|
||||
|
||||
impl Deserialize for RawBytes {
|
||||
|
|
|
@ -23,6 +23,7 @@ use crate::{
|
|||
};
|
||||
|
||||
use super::{
|
||||
backup::BackupParams,
|
||||
config::{ConfigManager, Patterns},
|
||||
WEBADMIN_KEY,
|
||||
};
|
||||
|
@ -33,7 +34,10 @@ pub struct BootManager {
|
|||
pub servers: Servers,
|
||||
}
|
||||
|
||||
const HELP: &str = r#"Stalwart Mail Server
|
||||
const HELP: &str = concat!(
|
||||
"Stalwart Mail Server v",
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
r#"
|
||||
|
||||
Usage: stalwart-mail [OPTIONS]
|
||||
|
||||
|
@ -44,11 +48,12 @@ Options:
|
|||
-I, --init <PATH> Initialize a new server at a specific path
|
||||
-h, --help Print help
|
||||
-V, --version Print version
|
||||
"#;
|
||||
"#
|
||||
);
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
enum ImportExport {
|
||||
Export(PathBuf),
|
||||
Export(BackupParams),
|
||||
Import(PathBuf),
|
||||
None,
|
||||
}
|
||||
|
@ -89,7 +94,7 @@ impl BootManager {
|
|||
std::process::exit(0);
|
||||
}
|
||||
("export" | "e", Some(value)) => {
|
||||
import_export = ImportExport::Export(value.into());
|
||||
import_export = ImportExport::Export(BackupParams::new(value.into()));
|
||||
}
|
||||
("import" | "i", Some(value)) => {
|
||||
import_export = ImportExport::Import(value.into());
|
||||
|
|
Loading…
Add table
Reference in a new issue