use std::fs;
use std::path::Path;
pub fn run(name: &str, template: &str) {
let project_dir = Path::new(name);
if project_dir.exists() {
eprintln!("error: directory `{}` already exists", name);
std::process::exit(1);
}
let src_dir = project_dir.join("src");
fs::create_dir_all(&src_dir).unwrap_or_else(|e| {
eprintln!("error: failed to create directory: {e}");
std::process::exit(1);
});
let cargo_toml = generate_cargo_toml(name);
write_file(&project_dir.join("Cargo.toml"), &cargo_toml);
let main_rs = match template {
"minimal" => generate_minimal_main(),
"command" => generate_command_main(),
"full" => generate_full_main(),
other => {
eprintln!("error: unknown template `{other}`. Available: minimal, command, full");
let _ = fs::remove_dir_all(project_dir);
std::process::exit(1);
}
};
write_file(&src_dir.join("main.rs"), &main_rs);
write_file(
&project_dir.join(".env.example"),
"MZRS_BOT_ID=\nMZRS_TOKEN=\n",
);
write_file(&project_dir.join(".gitignore"), "/target\n.env\n");
println!("Created new mzrs bot project `{name}` (template: {template})");
println!();
println!(" cd {name}");
println!(" cp .env.example .env # fill in your credentials");
println!(" cargo run");
}
fn write_file(path: &Path, content: &str) {
fs::write(path, content).unwrap_or_else(|e| {
eprintln!("error: failed to write {}: {e}", path.display());
std::process::exit(1);
});
}
fn generate_cargo_toml(name: &str) -> String {
format!(
r#"[package]
name = "{name}"
version = "0.1.0"
edition = "2021"
[dependencies]
mzrs-bot = "0.1"
mzrs-macros = "0.1"
tokio = {{ version = "1", features = ["macros", "rt-multi-thread"] }}
async-trait = "0.1"
tracing = "0.1"
tracing-subscriber = "0.3"
dotenvy = "0.15"
"#
)
}
fn generate_minimal_main() -> String {
r#"use mzrs_bot::prelude::*;
struct Handler;
#[async_trait]
impl BotHandler for Handler {
async fn on_channel_message(&self, bot: &Bot, msg: ChannelMessage) {
if is_own_message(bot, &msg) {
return;
}
if parse_text(&msg.content).trim() == "!ping" {
let _ = bot.reply_text(&msg, "Pong!").await;
}
}
}
#[tokio::main]
async fn main() -> Result<(), BotError> {
dotenvy::dotenv().ok();
tracing_subscriber::fmt::init();
Bot::from_env()?.build()?.run(Handler).await
}
"#
.to_string()
}
fn generate_command_main() -> String {
r#"use mzrs_bot::prelude::*;
use mzrs_macros::command;
struct Handler;
#[async_trait]
impl BotHandler for Handler {}
#[command(name = "ping", description = "Check bot status")]
async fn ping(ctx: MessageContext<'_>) -> Result<(), BotError> {
ctx.reply("Pong!").await
}
#[command(name = "echo", description = "Echo a message")]
async fn echo(ctx: MessageContext<'_>) -> Result<(), BotError> {
let text = ctx.args().join(" ");
if text.is_empty() {
ctx.reply("Usage: !echo <text>").await
} else {
ctx.reply(&text).await
}
}
#[tokio::main]
async fn main() -> Result<(), BotError> {
dotenvy::dotenv().ok();
tracing_subscriber::fmt::init();
Bot::from_env()?
.prefix("!")
.command("ping", PingCommand)
.command("echo", EchoCommand)
.build()?
.run(Handler)
.await
}
"#
.to_string()
}
fn generate_full_main() -> String {
r#"use mzrs_bot::prelude::*;
use mzrs_macros::command;
struct Handler;
#[async_trait]
impl BotHandler for Handler {
async fn on_connected(&self, _bot: &Bot) {
tracing::info!("Bot connected!");
}
async fn on_disconnected(&self, _bot: &Bot) {
tracing::warn!("Bot disconnected!");
}
async fn on_channel_message(&self, bot: &Bot, msg: ChannelMessage) {
if is_own_message(bot, &msg) {
return;
}
let text = parse_text(&msg.content);
tracing::info!(sender = msg.sender_id, %text, "received message");
}
}
#[command(name = "ping", description = "Check bot status")]
async fn ping(ctx: MessageContext<'_>) -> Result<(), BotError> {
ctx.reply("Pong!").await
}
#[command(name = "echo", description = "Echo a message")]
async fn echo(ctx: MessageContext<'_>) -> Result<(), BotError> {
let text = ctx.args().join(" ");
if text.is_empty() {
ctx.reply("Usage: !echo <text>").await
} else {
ctx.reply(&text).await
}
}
#[command(name = "help", description = "Show available commands")]
async fn help(ctx: MessageContext<'_>) -> Result<(), BotError> {
ctx.reply("Available commands: !ping, !echo <text>, !help")
.await
}
#[tokio::main]
async fn main() -> Result<(), BotError> {
dotenvy::dotenv().ok();
tracing_subscriber::fmt::init();
Bot::from_env()?
.prefix("!")
.command("ping", PingCommand)
.command("echo", EchoCommand)
.command("help", HelpCommand)
.build()?
.run(Handler)
.await
}
"#
.to_string()
}