summaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs92
1 files changed, 92 insertions, 0 deletions
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..9cf8e90
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,92 @@
+use std::collections::HashMap;
+use std::sync::Arc;
+use http::code::Code;
+use http::header::Header;
+use http::request::Request;
+use http::response::Response;
+use tokio::net::{TcpListener, TcpStream};
+use tokio::io::{AsyncReadExt, AsyncWriteExt};
+
+use crate::bash::handle_script;
+
+mod http;
+mod bash;
+
+async fn handle_response(mut socket: TcpStream, code: Code, body: String) {
+ let mut res = Response::new();
+ res.headers.put(Header::new("Content-Type", "text/plain"));
+ res.status = code;
+ res.body = Some(body);
+
+ let res_str = res.deserialize();
+
+ let _ = socket.write(res_str.as_bytes()).await;
+}
+
+async fn handle_connection(mut socket: TcpStream, config: Arc<HashMap<String, String>>) {
+
+ let mut buf = [0; 1204];
+
+ let n: usize = match socket.read(&mut buf).await {
+ Ok(n) if n == 0 => return,
+ Ok(n) => n as usize,
+ Err(e) => {
+ eprintln!("failed to read from socket; err = {:?}", e);
+ return
+ }
+ };
+
+ let str = String::from_utf8_lossy(&buf[0..n]);
+
+ let Some(req) = Request::serialize(&str) else {
+ return
+ };
+
+
+ let Some(script) = config.get(&req.uri.route) else {
+ handle_response(socket, Code::MethodNotAllowed, "Method Not Allowed".to_owned()).await;
+ return
+ };
+
+ match handle_script(script, req.body.as_ref()) {
+ Ok(out) => {
+ handle_response(socket, Code::Success, out).await;
+ },
+ Err(err) => {
+ handle_response(socket, Code::MethodNotAllowed, err).await;
+ },
+ }
+}
+
+#[tokio::main]
+async fn main() {
+
+ let config = Arc::new(bash::load_config());
+
+ let port = std::env::var("PORT")
+ .unwrap_or_else(|_| String::from("8080"))
+ .parse::<u16>()
+ .unwrap_or_else(|_| 8080);
+
+ let addr = format!("127.0.0.1:{port}");
+
+ let Ok(listener) = TcpListener::bind(&addr).await else {
+ println!("failed to bind {addr}");
+ return
+ };
+
+ println!("listening to tcp requests on {addr}");
+
+ loop {
+ let Ok((socket, _)) = listener.accept().await else {
+ println!("failed to accept new connection");
+ continue
+ };
+
+ let config = config.clone();
+
+ tokio::spawn(async move {
+ handle_connection(socket, config).await;
+ });
+ }
+}