mirror of
https://codeberg.org/insects/cargo-spiel
synced 2025-05-24 02:53:41 +00:00
initial commit
This commit is contained in:
commit
1cea94ea19
22 changed files with 2780 additions and 0 deletions
106
src/server.rs
Normal file
106
src/server.rs
Normal file
|
@ -0,0 +1,106 @@
|
|||
use std::{
|
||||
fs::File,
|
||||
io::{Read, Write},
|
||||
path::PathBuf,
|
||||
process::Command,
|
||||
};
|
||||
|
||||
use axum::{
|
||||
Json, Router,
|
||||
body::Bytes,
|
||||
extract::{Request, State},
|
||||
http::{HeaderMap, HeaderValue, StatusCode, header::CONTENT_TYPE},
|
||||
middleware::{self, Next},
|
||||
response::IntoResponse,
|
||||
routing::get,
|
||||
};
|
||||
use include_dir::{Dir, include_dir};
|
||||
use serde::Serialize;
|
||||
|
||||
static PUBLIC_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/public");
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct OutputResponse {
|
||||
pub stdout: Vec<u8>,
|
||||
pub stderr: Vec<u8>,
|
||||
}
|
||||
|
||||
async fn serve_mem(request: Request, _next: Next) -> impl IntoResponse {
|
||||
let uri = request.uri();
|
||||
let filename = if *uri == *"/" {
|
||||
"index.html".to_string()
|
||||
} else {
|
||||
uri.to_string().trim_start_matches("/").into()
|
||||
};
|
||||
if let Some(file) = PUBLIC_DIR.get_file(filename) {
|
||||
let ext = file.path().extension();
|
||||
let mut headers = HeaderMap::new();
|
||||
let mime = if let Some(Some(ext)) = ext.map(|f| f.to_str()) {
|
||||
match ext {
|
||||
"html" => "text/html",
|
||||
"js" => "application/javascript",
|
||||
"css" => "text/css",
|
||||
"svg" => "image/svg+xml",
|
||||
_ => "text/plain",
|
||||
}
|
||||
} else {
|
||||
"text/plain"
|
||||
};
|
||||
headers.insert(CONTENT_TYPE, HeaderValue::from_str(mime).unwrap());
|
||||
(headers, file.contents()).into_response()
|
||||
} else {
|
||||
StatusCode::NOT_FOUND.into_response()
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_code(State(state): State<ServerState>) -> impl IntoResponse {
|
||||
let mut path = state.path.clone();
|
||||
path.push("src/main.rs");
|
||||
let mut file = File::open(path).unwrap();
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents).unwrap();
|
||||
contents.into_response()
|
||||
}
|
||||
|
||||
async fn put_code(State(state): State<ServerState>, body: Bytes) -> impl IntoResponse {
|
||||
let mut path = state.path.clone();
|
||||
path.push("src/main.rs");
|
||||
let mut file = File::options()
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.open(path)
|
||||
.unwrap();
|
||||
file.write_all(&body[..]).unwrap();
|
||||
StatusCode::OK.into_response()
|
||||
}
|
||||
|
||||
async fn run_code(State(state): State<ServerState>) -> impl IntoResponse {
|
||||
let mut path = state.path.clone();
|
||||
path.push("Cargo.toml");
|
||||
let cargo = std::env::var("CARGO").unwrap();
|
||||
let output = Command::new(cargo)
|
||||
.args(["run", "--manifest-path", path.to_str().unwrap()])
|
||||
.output()
|
||||
.unwrap();
|
||||
let res = OutputResponse {
|
||||
stdout: output.stdout,
|
||||
stderr: output.stderr,
|
||||
};
|
||||
Json(res)
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ServerState {
|
||||
pub path: PathBuf,
|
||||
}
|
||||
|
||||
pub async fn start(path: PathBuf) {
|
||||
let app = Router::new()
|
||||
.layer(middleware::from_fn(serve_mem))
|
||||
.route("/code", get(get_code).post(run_code).put(put_code))
|
||||
.with_state(ServerState { path });
|
||||
let listener = tokio::net::TcpListener::bind("127.0.0.1:4555")
|
||||
.await
|
||||
.unwrap();
|
||||
axum::serve(listener, app).await.unwrap();
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue