wake-on-lan/src/main.rs
2026-08-03 17:55:45 +02:00

98 lines
2.6 KiB
Rust

use axum::{Json, Router, routing::post};
use serde::Serialize;
use std::process::Command;
use tower_http::services::ServeDir;
#[derive(Serialize)]
struct ApiResponse {
status: String,
message: String,
}
fn env_or_exit(key: &str) -> String {
std::env::var(key).unwrap_or_else(|_| {
eprintln!("Error : env {} missing", key);
std::process::exit(1);
})
}
async fn wake() -> Json<ApiResponse> {
let mac = env_or_exit("MAC_ADDRESS");
let output = Command::new("wakeonlan").arg(&mac).output();
match output {
Ok(o) if o.status.success() => Json(ApiResponse {
status: "ok".into(),
message: "Magic packet send !".into(),
}),
Ok(o) => Json(ApiResponse {
status: "error".into(),
message: String::from_utf8_lossy(&o.stderr).to_string(),
}),
Err(e) => Json(ApiResponse {
status: "error".into(),
message: e.to_string(),
}),
}
}
async fn shutdown() -> Json<ApiResponse> {
let pc_ip = env_or_exit("PC_IP");
let ssh_user = env_or_exit("SSH_USER");
let ssh_key = env_or_exit("SSH_KEY_PATH");
let output = Command::new("ssh")
.args([
"-i",
&ssh_key,
"-o",
"StrictHostKeyChecking=accept-new",
"-o",
"ConnectTimeout=5",
&format!("{}@{}", ssh_user, pc_ip),
"sudo /sbin/shutdown -h now",
])
.output();
match output {
Ok(o) if o.status.success() => Json(ApiResponse {
status: "ok".into(),
message: "Shotdown...".into(),
}),
Ok(o) => Json(ApiResponse {
status: "error".into(),
message: String::from_utf8_lossy(&o.stderr).to_string(),
}),
Err(e) => Json(ApiResponse {
status: "error".into(),
message: e.to_string(),
}),
}
}
#[tokio::main]
async fn main() {
dotenvy::dotenv().ok();
env_or_exit("MAC_ADDRESS");
env_or_exit("PC_IP");
env_or_exit("SSH_USER");
env_or_exit("SSH_KEY_PATH");
let port: u16 = std::env::var("PORT")
.unwrap_or_else(|_| "5050".into())
.parse()
.expect("invalid port");
let app = Router::new()
.route("/wake", post(wake))
.route("/shutdown", post(shutdown))
.nest_service("/", ServeDir::new("public"));
let addr = format!("127.0.0.1:{}", port);
println!("Started on http://{}", addr);
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
axum::serve(listener, app).await.unwrap();
}