VelNet-Server/control-panel/src/main.rs

195 lines
5.2 KiB
Rust

use actix_web::body::BoxBody;
use actix_web::dev::ServiceResponse;
use actix_web::http::header::ContentType;
use actix_web::http::StatusCode;
use actix_web::middleware::{ErrorHandlerResponse, ErrorHandlers};
use actix_web::{get, web, App, HttpResponse, HttpServer, Result};
use handlebars::Handlebars;
use serde_json::json;
use std::io;
use std::io::{prelude::*, BufReader};
use std::fs;
use std::fs::File;
use std::path::Path;
use serde::{Serialize, Deserialize};
use std::process::{Command, Stdio};
use std::env;
#[derive(Serialize, Deserialize)]
struct Config {
port: u16,
log_file: String,
server_dir: String
}
fn lines_from_file(filename: impl AsRef<Path>) -> Vec<String> {
let file = File::open(filename).expect("no such file");
let buf = BufReader::new(file);
buf.lines()
.map(|l| l.expect("Could not parse line"))
.collect()
}
#[get("/")]
async fn index(hb: web::Data<Handlebars<'_>>) -> HttpResponse {
//read the config file
let file = fs::read_to_string("config.json").unwrap();
let config: Config = serde_json::from_str(&file).unwrap();
//read the log file
let log_file = lines_from_file(config.log_file);
let restarts_log = lines_from_file("../restarts.log");
let uptime = Command::new("uptime")
.output()
.expect("failed to execute process");
let _onefetch = Command::new("sh")
.arg("onefetch_file.sh")
.output()
.expect("failed");
let onefetch = fs::read_to_string("onefetch.out").unwrap();
let data = json!({
"log_output": log_file,
"restarts_output": restarts_log,
"uptime": format!("{}", String::from_utf8_lossy(&uptime.stdout)),
//"onefetch": format!("{}", String::from_utf8_lossy(&onefetch.stdout))
"onefetch": onefetch
});
let body = hb.render("index", &data).unwrap();
HttpResponse::Ok().body(body)
}
#[get("/restart_server")]
async fn restart_server() -> HttpResponse {
// Restart the process
let _output = Command::new("sh")
.arg("../run.sh")
.stdin(Stdio::null())
//.stdout(Stdio::null())
//.stderr(Stdio::null())
.spawn();
HttpResponse::Ok().body("DONE")
}
#[get("/git_pull")]
async fn git_pull() -> HttpResponse {
let output = Command::new("git")
.arg("pull")
.output()
.expect("failed to execute process");
HttpResponse::Ok().body(output.stdout)
}
#[get("/compile")]
async fn compile() -> HttpResponse {
//read the config file
let file = fs::read_to_string("config.json").unwrap();
let config: Config = serde_json::from_str(&file).unwrap();
let orig_dir = std::env::current_dir().unwrap();
let root = Path::new(&config.server_dir);
let _new_dir = env::set_current_dir(&root);
print!("before");
let output = Command::new("cargo")
.arg("build")
.arg("--release")
.output()
.expect("failed to execute process");
print!("after");
let _new_dir = env::set_current_dir(orig_dir);
HttpResponse::Ok().body(output.stdout)
}
#[actix_web::main]
async fn main() -> io::Result<()> {
let mut handlebars = Handlebars::new();
handlebars.set_dev_mode(true);
handlebars.register_templates_directory(".hbs", "./static/templates").unwrap();
let handlebars_ref = web::Data::new(handlebars);
HttpServer::new(move || {
App::new()
.wrap(error_handlers())
.app_data(handlebars_ref.clone())
.service(index)
.service(restart_server)
.service(git_pull)
.service(compile)
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
// Custom error handlers, to return HTML responses when an error occurs.
fn error_handlers() -> ErrorHandlers<BoxBody> {
ErrorHandlers::new().handler(StatusCode::NOT_FOUND, not_found)
}
// Error handler for a 404 Page not found error.
fn not_found<B>(res: ServiceResponse<B>) -> Result<ErrorHandlerResponse<BoxBody>> {
let response = get_error_response(&res, "Page not found");
Ok(ErrorHandlerResponse::Response(ServiceResponse::new(
res.into_parts().0,
response.map_into_left_body(),
)))
}
// Generic error handler.
fn get_error_response<B>(res: &ServiceResponse<B>, error: &str) -> HttpResponse<BoxBody> {
let request = res.request();
// Provide a fallback to a simple plain text response in case an error occurs during the
// rendering of the error page.
let fallback = |e: &str| {
HttpResponse::build(res.status())
.content_type(ContentType::plaintext())
.body(e.to_string())
};
let hb = request
.app_data::<web::Data<Handlebars>>()
.map(|t| t.get_ref());
match hb {
Some(hb) => {
let data = json!({
"error": error,
"status_code": res.status().as_str()
});
let body = hb.render("error", &data);
match body {
Ok(body) => HttpResponse::build(res.status())
.content_type(ContentType::html())
.body(body),
Err(_) => fallback(error),
}
}
None => fallback(error),
}
}