use clap::{Parser, Subcommand};
use oxidite_core::{Router, Server, OxiditeRequest, OxiditeResponse, Result};
use oxidite_middleware::{ServiceBuilder, LoggerLayer};
use http_body_util::Full;
use bytes::Bytes;
mod commands;
#[derive(Parser)]
#[command(name = "oxidite")]
#[command(about = "Oxidite Framework CLI", long_about = None)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
Serve {
#[arg(short, long, default_value = "127.0.0.1:3000")]
addr: String,
},
New {
name: String,
#[arg(short, long)]
project_type: Option<String>,
},
Make {
#[command(subcommand)]
generator: Generator,
},
Migrate {
#[command(subcommand)]
migration: MigrateCommand,
},
Seed {
#[command(subcommand)]
seeder: SeedCommand,
},
Queue {
#[command(subcommand)]
queue: QueueCommand,
},
Doctor,
Build {
#[arg(short, long)]
release: bool,
},
Dev,
}
#[derive(Subcommand)]
enum Generator {
Model { name: String },
Controller { name: String },
Middleware { name: String },
}
#[derive(Subcommand)]
enum MigrateCommand {
Create { name: String },
Run,
Revert,
Status,
}
#[derive(Subcommand)]
enum SeedCommand {
Run,
Create { name: String },
}
#[derive(Subcommand)]
enum QueueCommand {
Work {
#[arg(short, long, default_value = "4")]
workers: usize,
},
List,
Dlq,
Clear,
}
async fn hello(_req: OxiditeRequest) -> Result<OxiditeResponse> {
Ok(hyper::Response::new(Full::new(Bytes::from("Hello, Oxidite!"))))
}
#[tokio::main]
async fn main() -> Result<()> {
let cli = Cli::parse();
match cli.command {
Commands::Serve { addr } => {
let mut router = Router::new();
router.get("/", hello);
let service = ServiceBuilder::new()
.layer(LoggerLayer)
.service(router);
let server = Server::new(service);
println!("🚀 Server running on http://{}", addr);
server.listen(addr.parse().unwrap()).await
}
Commands::New { name, project_type } => {
commands::create_project(&name, project_type)
.map_err(|e| oxidite_core::Error::Server(e.to_string()))?;
Ok(())
}
Commands::Make { generator } => {
match generator {
Generator::Model { name } => {
commands::make::make_model(&name)
.map_err(|e| oxidite_core::Error::Server(e.to_string()))?;
}
Generator::Controller { name } => {
commands::make::make_controller(&name)
.map_err(|e| oxidite_core::Error::Server(e.to_string()))?;
}
Generator::Middleware { name } => {
commands::make::make_middleware(&name)
.map_err(|e| oxidite_core::Error::Server(e.to_string()))?;
}
}
Ok(())
}
Commands::Migrate { migration } => {
match migration {
MigrateCommand::Create { name } => {
commands::migrate::create_migration(&name)
.map_err(|e| oxidite_core::Error::Server(e.to_string()))?;
}
MigrateCommand::Run => {
commands::migrate::run_migrations()
.await
.map_err(|e| oxidite_core::Error::Server(e.to_string()))?;
}
MigrateCommand::Revert => {
commands::migrate::revert_migration()
.await
.map_err(|e| oxidite_core::Error::Server(e.to_string()))?;
}
MigrateCommand::Status => {
commands::migrate::migration_status()
.await
.map_err(|e| oxidite_core::Error::Server(e.to_string()))?;
}
}
Ok(())
}
Commands::Seed { seeder } => {
match seeder {
SeedCommand::Run => {
commands::seed::run_seeders()
.await
.map_err(|e| oxidite_core::Error::Server(e.to_string()))?;
}
SeedCommand::Create { name } => {
commands::seed::create_seeder(&name)
.map_err(|e| oxidite_core::Error::Server(e.to_string()))?;
}
}
Ok(())
}
Commands::Queue { queue } => {
match queue {
QueueCommand::Work { workers } => {
commands::queue::queue_work(workers)
.await
.map_err(|e| oxidite_core::Error::Server(e.to_string()))?;
}
QueueCommand::List => {
commands::queue::queue_list()
.await
.map_err(|e| oxidite_core::Error::Server(e.to_string()))?;
}
QueueCommand::Dlq => {
commands::queue::queue_dlq()
.await
.map_err(|e| oxidite_core::Error::Server(e.to_string()))?;
}
QueueCommand::Clear => {
commands::queue::queue_clear()
.await
.map_err(|e| oxidite_core::Error::Server(e.to_string()))?;
}
}
Ok(())
}
Commands::Doctor => {
commands::doctor::run_doctor()
.map_err(|e| oxidite_core::Error::Server(e.to_string()))?;
Ok(())
}
Commands::Build { release } => {
println!("🔨 Building Oxidite project...");
let mut cmd = std::process::Command::new("cargo");
cmd.arg("build");
if release {
cmd.arg("--release");
println!("📦 Building in release mode");
}
let status = cmd.status()
.map_err(|e| oxidite_core::Error::Server(e.to_string()))?;
if status.success() {
println!("✅ Build completed successfully");
} else {
return Err(oxidite_core::Error::Server("Build failed".to_string()));
}
Ok(())
}
Commands::Dev => {
commands::dev::start_dev_server()
.map_err(|e| oxidite_core::Error::Server(e.to_string()))?;
Ok(())
}
}
}