use std::sync::Arc;
use aurora_core::{
Command, CommandCategory, Pipeline, Engine, AuroraResult,
};
use aurora_locale::Localizer;
use crate::{
media, dev, fs, sys, net, archive, docker, unix,
crypto, calc, qr, color, timer, note, clip, text,
};
pub struct ModulesEngine {
localizer: Arc<Localizer>,
}
impl ModulesEngine {
pub fn new(localizer: Arc<Localizer>) -> Self {
Self { localizer }
}
}
impl Engine for ModulesEngine {
fn name(&self) -> &'static str {
"modules"
}
fn can_handle(&self, cmd: &Command) -> bool {
matches!(
cmd.category,
CommandCategory::Media
| CommandCategory::Dev
| CommandCategory::Fs
| CommandCategory::Sys
| CommandCategory::Net
| CommandCategory::Archive
| CommandCategory::Docker
| CommandCategory::Unix
| CommandCategory::Crypto
| CommandCategory::Calc
| CommandCategory::Qr
| CommandCategory::Color
| CommandCategory::Timer
| CommandCategory::Note
| CommandCategory::Clipboard
| CommandCategory::Text
)
}
fn execute(&self, cmd: &Command, _input: &Pipeline) -> AuroraResult<Pipeline> {
match cmd.category {
CommandCategory::Media => execute_media(cmd),
CommandCategory::Dev => execute_dev(cmd, &self.localizer),
CommandCategory::Fs => execute_fs(cmd),
CommandCategory::Sys => execute_sys(cmd),
CommandCategory::Net => execute_net(cmd),
CommandCategory::Archive => execute_archive(cmd),
CommandCategory::Docker => execute_docker(cmd),
CommandCategory::Unix => execute_unix(cmd),
CommandCategory::Crypto => execute_crypto(cmd),
CommandCategory::Calc => execute_calc(cmd),
CommandCategory::Qr => execute_qr(cmd),
CommandCategory::Color => execute_color(cmd),
CommandCategory::Timer => execute_timer(cmd),
CommandCategory::Note => execute_note(cmd),
CommandCategory::Clipboard => execute_clip(cmd),
CommandCategory::Text => execute_text(cmd),
_ => Err(aurora_core::AuroraError::ModuleError(
format!("unsupported category: {:?}", cmd.category)
)),
}
}
}
fn execute_media(cmd: &Command) -> AuroraResult<Pipeline> {
match cmd.action.as_str() {
"info" | "probe" => {
let input = cmd.args.first().ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing input file".into())
})?;
media::media_info(input)
}
"convert" => {
let input = cmd.args.first().ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing input file".into())
})?;
let output = cmd.args.get(1).ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing output file".into())
})?;
media::media_convert(input, output)
}
"stream" => {
let input = cmd.args.first().ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing input file".into())
})?;
media::media_stream(input)
}
"extract" => {
let input = cmd.args.first().ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing input file".into())
})?;
let output = cmd.args.get(1).ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing output file".into())
})?;
media::media_extract(input, output)
}
_ => Err(aurora_core::AuroraError::CommandNotFound(
format!("media.{}", cmd.action)
)),
}
}
fn execute_dev(cmd: &Command, localizer: &Arc<Localizer>) -> AuroraResult<Pipeline> {
match cmd.action.as_str() {
"log" => {
let oneline = cmd.switches.contains(&"oneline".into());
let graph = cmd.switches.contains(&"graph".into());
let n = cmd.flags.get("n")
.and_then(|v| v.parse::<usize>().ok());
dev::dev_log(oneline, graph, n, localizer)
}
"status" => dev::dev_status(),
"diff" => {
let stat = cmd.switches.contains(&"stat".into());
dev::dev_diff(stat, localizer)
}
"commit" => {
let msg = cmd.args.first().map(|s| s.as_str()).unwrap_or("");
dev::dev_commit(msg, localizer)
}
"branch" => {
let delete = cmd.switches.contains(&"delete".into());
let rename = cmd.switches.contains(&"rename".into());
let name = cmd.args.first().map(|s| s.as_str());
dev::dev_branch(delete, rename, name, localizer)
}
"push" => {
let remote = cmd.args.first().map(|s| s.as_str());
let branch = cmd.args.get(1).map(|s| s.as_str());
let upstream = cmd.switches.contains(&"upstream".into());
let force = cmd.switches.contains(&"force".into());
dev::dev_push(remote, branch, upstream, force, localizer)
}
"fetch" => {
let remote = cmd.args.first().map(|s| s.as_str());
let branch = cmd.args.get(1).map(|s| s.as_str());
dev::dev_fetch(remote, branch, localizer)
}
"pull" => {
let remote = cmd.args.first().map(|s| s.as_str());
let branch = cmd.args.get(1).map(|s| s.as_str());
dev::dev_pull(remote, branch, localizer)
}
"clone" => {
let url = cmd.args.first().ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing repository URL".into())
})?;
let target = cmd.args.get(1).map(|s| s.as_str());
dev::dev_clone(url, target, localizer)
}
"init" => dev::dev_init(localizer),
"add" => {
let files = cmd.args.clone();
dev::dev_add(&files, localizer)
}
"checkout" => {
let target = cmd.args.first().map(|s| s.as_str());
let create = cmd.switches.contains(&"create".into());
let orphan = cmd.switches.contains(&"orphan".into());
dev::dev_checkout(target, create, orphan, localizer)
}
"stash" => {
let sub = cmd.args.first().map(|s| s.as_str()).unwrap_or("push");
match sub {
"push" => dev::dev_stash_push(localizer),
"list" | "ls" => dev::dev_stash_list(localizer),
"pop" => dev::dev_stash_pop(localizer),
_ => Err(aurora_core::AuroraError::CommandNotFound(
format!("stash.{sub}")
)),
}
}
"reset" => {
let files = cmd.args.clone();
let hard = cmd.switches.contains(&"hard".into());
dev::dev_reset(&files, hard, localizer)
}
"config" => {
let key = cmd.args.first().map(|s| s.as_str());
let value = cmd.args.get(1).map(|s| s.as_str());
dev::dev_config(key, value, localizer)
}
"remote" => {
let sub = cmd.args.first().map(|s| s.as_str()).unwrap_or("");
match sub {
"add" => {
let name = cmd.args.get(1).map(|s| s.as_str());
let url = cmd.args.get(2).map(|s| s.as_str());
dev::dev_remote_add(name, url, localizer)
}
"list" | "ls" => dev::dev_remote_list(localizer),
"remove" | "rm" => {
let name = cmd.args.get(1).ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing remote name".into())
})?;
dev::dev_remote_remove(name, localizer)
}
_ => Err(aurora_core::AuroraError::CommandNotFound(
"remote.unknown".into()
)),
}
}
_ => Err(aurora_core::AuroraError::CommandNotFound(
format!("dev.{}", cmd.action)
)),
}
}
fn execute_fs(cmd: &Command) -> AuroraResult<Pipeline> {
match cmd.action.as_str() {
"ls" => {
let path = cmd.args.first().map(|s| s.as_str()).unwrap_or(".");
let long = cmd.switches.contains(&"long".into());
fs::fs_ls(path, long)
}
"tree" => {
let path = cmd.args.first().map(|s| s.as_str()).unwrap_or(".");
let depth = cmd.flags.get("depth")
.and_then(|v| v.parse::<usize>().ok());
fs::fs_tree(path, depth)
}
"find" => {
let pattern = cmd.args.first().ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing search pattern".into())
})?;
let path = cmd.args.get(1).map(|s| s.as_str()).unwrap_or(".");
fs::fs_find(pattern, path)
}
"info" => {
let path = cmd.args.first().map(|s| s.as_str()).unwrap_or(".");
fs::fs_info(path)
}
"du" => {
let path = cmd.args.first().map(|s| s.as_str()).unwrap_or(".");
fs::fs_du(path)
}
_ => Err(aurora_core::AuroraError::CommandNotFound(
format!("fs.{}", cmd.action)
)),
}
}
fn execute_sys(cmd: &Command) -> AuroraResult<Pipeline> {
match cmd.action.as_str() {
"info" => sys::sys_info(),
"process" | "ps" => sys::sys_process(),
"disk" | "df" => sys::sys_disk(),
"memory" | "mem" => sys::sys_memory(),
"service" => {
let name = cmd.args.first().ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing service name".into())
})?;
sys::sys_service(name)
}
_ => Err(aurora_core::AuroraError::CommandNotFound(
format!("sys.{}", cmd.action)
)),
}
}
fn execute_net(cmd: &Command) -> AuroraResult<Pipeline> {
match cmd.action.as_str() {
"ping" => {
let host = cmd.args.first().ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing host".into())
})?;
net::net_ping(host)
}
"dns" => {
let domain = cmd.args.first().ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing domain".into())
})?;
net::net_dns(domain)
}
"http" | "curl" => {
let url = cmd.args.first().ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing URL".into())
})?;
net::net_http(url)
}
"ip" => net::net_ip(),
"scan" => {
let host = cmd.args.first().ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing host".into())
})?;
net::net_scan(host)
}
_ => Err(aurora_core::AuroraError::CommandNotFound(
format!("net.{}", cmd.action)
)),
}
}
fn execute_archive(cmd: &Command) -> AuroraResult<Pipeline> {
match cmd.action.as_str() {
"list" => {
let file = cmd.args.first().ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing archive file".into())
})?;
archive::archive_list(file)
}
"extract" => {
let file = cmd.args.first().ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing archive file".into())
})?;
let output = cmd.args.get(1).map(|s| s.as_str());
archive::archive_extract(file, output)
}
"compress" => {
let input = cmd.args.first().ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing input".into())
})?;
let output = cmd.args.get(1).ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing output file".into())
})?;
archive::archive_compress(input, output)
}
_ => Err(aurora_core::AuroraError::CommandNotFound(
format!("archive.{}", cmd.action)
)),
}
}
fn execute_docker(cmd: &Command) -> AuroraResult<Pipeline> {
match cmd.action.as_str() {
"ps" => docker::docker_ps(),
"logs" => {
let container = cmd.args.first().ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing container id".into())
})?;
let tail = cmd.flags.get("tail")
.and_then(|v| v.parse::<usize>().ok());
docker::docker_logs(container, tail)
}
"exec" => {
let container = cmd.args.first().ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing container id".into())
})?;
let command = cmd.args[1..].to_vec();
docker::docker_exec(container, &command)
}
"images" => docker::docker_images(),
_ => Err(aurora_core::AuroraError::CommandNotFound(
format!("docker.{}", cmd.action)
)),
}
}
fn execute_unix(cmd: &Command) -> AuroraResult<Pipeline> {
match cmd.action.as_str() {
"ps" => unix::unix_ps(),
"df" => {
let human = cmd.switches.contains(&"human".into());
unix::unix_df(human)
}
"du" => {
let path = cmd.args.first().map(|s| s.as_str()).unwrap_or(".");
unix::unix_du(path)
}
"uptime" => unix::unix_uptime(),
"env" => unix::unix_env(),
"uname" => unix::unix_uname(),
_ => Err(aurora_core::AuroraError::CommandNotFound(
format!("unix.{}", cmd.action)
)),
}
}
fn execute_crypto(cmd: &Command) -> AuroraResult<Pipeline> {
match cmd.action.as_str() {
"hash" => {
let input = cmd.args.first().ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing input".into())
})?;
let algo = cmd.flags.get("algo").map(|s| s.as_str());
crypto::crypto_hash(input, algo)
}
"genkey" | "keygen" => {
let algo = cmd.flags.get("algo").map(|s| s.as_str());
crypto::crypto_genkey(algo)
}
_ => Err(aurora_core::AuroraError::CommandNotFound(
format!("crypto.{}", cmd.action)
)),
}
}
fn execute_calc(cmd: &Command) -> AuroraResult<Pipeline> {
match cmd.action.as_str() {
"eval" | "calc" => {
let expr = cmd.args.clone();
if expr.is_empty() {
return Err(aurora_core::AuroraError::InvalidInput(
"missing expression".into()
));
}
calc::calc_eval(&expr)
}
_ => Err(aurora_core::AuroraError::CommandNotFound(
format!("calc.{}", cmd.action)
)),
}
}
fn execute_qr(cmd: &Command) -> AuroraResult<Pipeline> {
match cmd.action.as_str() {
"encode" => {
let text = cmd.args.first().ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing text".into())
})?;
let output = cmd.args.get(1).map(|s| s.as_str());
qr::qr_encode(text, output)
}
"decode" => {
let input = cmd.args.first().ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing input file".into())
})?;
qr::qr_decode(input)
}
_ => Err(aurora_core::AuroraError::CommandNotFound(
format!("qr.{}", cmd.action)
)),
}
}
fn execute_color(cmd: &Command) -> AuroraResult<Pipeline> {
match cmd.action.as_str() {
"palette" => color::color_palette(),
"hex" => {
let hex = cmd.args.first().ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing hex color".into())
})?;
color::color_hex(hex)
}
"rgb" => {
let r = cmd.args.first()
.and_then(|v| v.parse::<u8>().ok())
.ok_or_else(|| aurora_core::AuroraError::InvalidInput("missing or invalid r".into()))?;
let g = cmd.args.get(1)
.and_then(|v| v.parse::<u8>().ok())
.ok_or_else(|| aurora_core::AuroraError::InvalidInput("missing or invalid g".into()))?;
let b = cmd.args.get(2)
.and_then(|v| v.parse::<u8>().ok())
.ok_or_else(|| aurora_core::AuroraError::InvalidInput("missing or invalid b".into()))?;
color::color_rgb(r, g, b)
}
_ => Err(aurora_core::AuroraError::CommandNotFound(
format!("color.{}", cmd.action)
)),
}
}
fn execute_timer(cmd: &Command) -> AuroraResult<Pipeline> {
match cmd.action.as_str() {
"start" => {
let seconds = cmd.args.first()
.and_then(|v| v.parse::<u64>().ok())
.ok_or_else(|| aurora_core::AuroraError::InvalidInput("missing or invalid seconds".into()))?;
let name = cmd.args.get(1).map(|s| s.clone());
timer::timer_start(seconds, name.as_deref())
}
"stop" => timer::timer_stop(),
"status" => timer::timer_status(),
_ => Err(aurora_core::AuroraError::CommandNotFound(
format!("timer.{}", cmd.action)
)),
}
}
fn execute_note(cmd: &Command) -> AuroraResult<Pipeline> {
match cmd.action.as_str() {
"add" | "new" => {
let text = cmd.args.clone();
if text.is_empty() {
return Err(aurora_core::AuroraError::InvalidInput(
"missing note text".into()
));
}
note::note_add(&text)
}
_ => Err(aurora_core::AuroraError::CommandNotFound(
format!("note.{}", cmd.action)
)),
}
}
fn execute_clip(cmd: &Command) -> AuroraResult<Pipeline> {
match cmd.action.as_str() {
"get" => clip::clip_get(),
"set" => {
let text = cmd.args.clone();
clip::clip_set(&text)
}
"clear" => clip::clip_clear(),
_ => Err(aurora_core::AuroraError::CommandNotFound(
format!("clip.{}", cmd.action)
)),
}
}
fn execute_text(cmd: &Command) -> AuroraResult<Pipeline> {
match cmd.action.as_str() {
"grep" => {
let pattern = cmd.args.first().ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing search pattern".into())
})?;
let path = cmd.args.get(1).map(|s| s.as_str()).unwrap_or(".");
text::text_grep(pattern, path)
}
"replace" => {
let pattern = cmd.args.first().ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing search pattern".into())
})?;
let replacement = cmd.args.get(1).ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing replacement".into())
})?;
let path = cmd.args.get(2).ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing file path".into())
})?;
text::text_replace(pattern, replacement, path)
}
"transform" => {
let path = cmd.args.first().ok_or_else(|| {
aurora_core::AuroraError::InvalidInput("missing file path".into())
})?;
let upper = cmd.switches.contains(&"upper".into());
let lower = cmd.switches.contains(&"lower".into());
text::text_transform(path, upper, lower)
}
_ => Err(aurora_core::AuroraError::CommandNotFound(
format!("text.{}", cmd.action)
)),
}
}