use super::config::Config;
use malwaredb_server::State;
use std::process::ExitCode;
use clap::{Parser, Subcommand};
#[derive(Parser, Debug)]
pub struct Run {
#[clap(subcommand)]
pub cmd: Option<Subcommands>,
}
impl Run {
pub async fn into_state(self) -> anyhow::Result<State> {
match self.cmd {
Some(Subcommands::Load(loader)) => loader.config()?,
Some(Subcommands::Config(config)) => config,
None => Config::from_found_files()?,
}
.into_state()
.await
}
pub async fn execute(self) -> anyhow::Result<ExitCode> {
let state = self.into_state().await?;
#[cfg(feature = "admin")]
{
let groups = state.db_type.list_groups().await?;
if groups.len() < 2 {
println!("First time? Create a group and source to get started loading samples into MalwareDB.");
if let Ok(current_exe) = std::env::current_exe() {
let current_exe = current_exe.to_str().unwrap();
println!("Run `{current_exe} admin --help` for more information.");
}
}
}
state
.serve(
#[cfg(target_family = "windows")]
None,
)
.await?;
Ok(ExitCode::SUCCESS)
}
}
#[derive(Clone, Parser, Debug, PartialEq)]
pub struct Load {
#[arg(value_name = "FILE", value_hint = clap::ValueHint::FilePath)]
file: std::path::PathBuf,
}
impl Load {
pub fn config(&self) -> anyhow::Result<Config> {
Config::from_file(&self.file)
}
}
#[derive(Subcommand, Debug)]
pub enum Subcommands {
Load(Load),
Config(Config),
}
#[cfg(test)]
mod tests {
use malwaredb_server::StateBuilder;
use anyhow::Context;
const DB_FILE: &str = "testing_sqlite.db";
#[tokio::test]
async fn state_info() {
let builder = StateBuilder::new(&format!("file:{DB_FILE}"), None)
.await
.unwrap();
let state = builder.into_state().await.unwrap();
let info = state.get_info().await.unwrap();
eprintln!("State info(): {info:?}");
std::fs::remove_file(DB_FILE)
.context(format!("failed to delete SQLite file {DB_FILE}"))
.unwrap();
}
}