added control panel site using rust
parent
b37edb0222
commit
961a688068
|
|
@ -3,3 +3,6 @@
|
||||||
main
|
main
|
||||||
main.exe
|
main.exe
|
||||||
main.pdb
|
main.pdb
|
||||||
|
.idea/
|
||||||
|
restarts.log
|
||||||
|
nohup.out
|
||||||
15
README.md
15
README.md
|
|
@ -4,8 +4,19 @@
|
||||||
|
|
||||||
1. Get a linoox server
|
1. Get a linoox server
|
||||||
2. Clone this repo
|
2. Clone this repo
|
||||||
3. Install rust: `curl https://sh.rustup.rs -sSf | sh`
|
3. Install rust: `sudo apt install cargo`
|
||||||
4. Set up env: `source $HOME/.cargo/env` or add to `.bashrc`
|
|
||||||
5. Build: `cargo build --release`
|
5. Build: `cargo build --release`
|
||||||
6. Run: `sudo ./target/release/VelNetServerRust`
|
6. Run: `sudo ./target/release/VelNetServerRust`
|
||||||
7. Or run in the background so that it doesn't quit when you leave ssh: `nohup sudo ./target/release/VelNetServerRust`. You'll have to install `nohup` with apt.
|
7. Or run in the background so that it doesn't quit when you leave ssh: `nohup sudo ./target/release/VelNetServerRust`. You'll have to install `nohup` with apt.
|
||||||
|
|
||||||
|
|
||||||
|
## Running with control panel server
|
||||||
|
|
||||||
|
You don't need to do both of these steps. The control panel runs the other server.
|
||||||
|
|
||||||
|
1. Get a linoox server
|
||||||
|
2. Clone this repo
|
||||||
|
3. Install rust: `sudo apt install cargo`
|
||||||
|
3. Switch to control panel: `cd control-panel`
|
||||||
|
5. Build: `cargo build --release`
|
||||||
|
6. Run the web server in the background so that it doesn't quit when you leave ssh: `nohup sudo ./target/release/control-panel`. You'll have to install `nohup` with apt.
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
/target
|
||||||
|
.vscode
|
||||||
|
main
|
||||||
|
main.exe
|
||||||
|
main.pdb
|
||||||
|
.idea/
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,12 @@
|
||||||
|
[package]
|
||||||
|
name = "control-panel"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
actix-web = "4"
|
||||||
|
handlebars = { version = "4.2.1", features = ["dir_source"] }
|
||||||
|
serde_json = "1.0"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"port": 8080,
|
||||||
|
"log_file": "/home/ntsfranz/Documents/VelNetServerRust/nohup.out",
|
||||||
|
"server_dir": "/home/ntsfranz/Documents/VelNetServerRust/"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,182 @@
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Macro documentation can be found in the actix_web_codegen crate
|
||||||
|
#[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 data = json!({
|
||||||
|
"log_output": log_file,
|
||||||
|
"restarts_output": restarts_log,
|
||||||
|
"uptime": format!("{}", String::from_utf8_lossy(&uptime.stdout)),
|
||||||
|
});
|
||||||
|
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);
|
||||||
|
|
||||||
|
let output = Command::new("cargo")
|
||||||
|
.arg("build")
|
||||||
|
.arg("--release")
|
||||||
|
.output()
|
||||||
|
.expect("failed to execute process");
|
||||||
|
|
||||||
|
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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>VelNet Control Panel</title>
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css">
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.bottom-scroller {
|
||||||
|
height: 30em;
|
||||||
|
overflow: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-output .panel-block {
|
||||||
|
padding: .1em .75em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="title">
|
||||||
|
VelNet Control Panel
|
||||||
|
</h1>
|
||||||
|
<p class="subtitle">
|
||||||
|
Log output and utilites for <strong>VelNet</strong>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<div class="container">
|
||||||
|
<div class="block">
|
||||||
|
<button class="button" id="restart-button">Restart Server</button>
|
||||||
|
<button class="button" id="pull-button">Git Pull</button>
|
||||||
|
<button class="button" id="compile-button">Compile</button>
|
||||||
|
</div>
|
||||||
|
<div class="block">Uptime: {{uptime}}</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="section">
|
||||||
|
<div class="container">
|
||||||
|
<nav class="panel">
|
||||||
|
<p class="panel-heading">
|
||||||
|
Server Log
|
||||||
|
<code>nohup.out</code>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="content bottom-scroller">
|
||||||
|
<code class="log-output">
|
||||||
|
<div>
|
||||||
|
{{#each log_output}}
|
||||||
|
<div class="panel-block">
|
||||||
|
{{this}}
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<nav class="panel">
|
||||||
|
<p class="panel-heading">
|
||||||
|
Server Restarts
|
||||||
|
<code>restarts.log</code>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="content bottom-scroller">
|
||||||
|
<code class="log-output">
|
||||||
|
<div>
|
||||||
|
{{#each restarts_output}}
|
||||||
|
<div class="panel-block">
|
||||||
|
{{this}}
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
"use strict";
|
||||||
|
document.getElementById('restart-button').addEventListener('click', c=> {
|
||||||
|
fetch('/restart_server').then(r=> {
|
||||||
|
setTimeout(location.reload(), 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
document.getElementById('pull-button').addEventListener('click', c=> {
|
||||||
|
fetch('/git_pull').then(r=> {
|
||||||
|
location.reload();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
document.getElementById('compile-button').addEventListener('click', c=> {
|
||||||
|
fetch('/compile').then(r=> {
|
||||||
|
location.reload();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
BASEDIR=$(dirname "$0")
|
||||||
|
# pushd $BASEDIR
|
||||||
|
echo $(date +"%Y-%m-%dT%T.%3N%z") >> $BASEDIR/restarts.log
|
||||||
|
echo "Before: "
|
||||||
|
pgrep VelNetServer
|
||||||
|
pkill VelNetServer
|
||||||
|
echo "\nAfter: "
|
||||||
|
pgrep VelNetServer
|
||||||
|
echo "\n"
|
||||||
|
(cd $BASEDIR && nohup "./target/release/VelNetServerRust" &)
|
||||||
|
# nohup "$BASEDIR/target/release/VelNetServerRust" &
|
||||||
|
echo "Starting..." >> $BASEDIR/restarts.log
|
||||||
|
# popd $BASEDIR
|
||||||
Loading…
Reference in New Issue