1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
use std::{env, collections::HashMap, fs::read_to_string, process::Command, result::Result, error::Error};
use crate::http::{response::Response, method::Method};
pub struct Script {
path: String
}
impl Script {
fn new(path: String) -> Self {
Self { path }
}
pub fn run(&self, body: Option<&String>) -> Result<Response, std::io::Error> {
let mut res = Response::new();
let mut command = Command::new(&self.path);
if let Some(body) = body {
command.args([body]);
}
let output = match command.output() {
Ok(output) => output,
Err(err) => return Err(err)
};
let status = output.status.code().unwrap_or(500) as u16;
let response = String::from_utf8_lossy(&output.stdout).into_owned();
let mut lines = response.split('\n').into_iter();
res.headers.serialize(&mut lines);
let body: String = lines.collect::<Vec<&str>>().join("\n");
if body.len() > 0 {
res.body = Some(body);
}
res.status = status;
Ok(res)
}
}
pub struct Config {
map: HashMap<String, Script>
}
impl Config {
fn key(method: &Method, route: &str) -> String {
format!("{}:{}", method.deserialize(), route)
}
pub fn load() -> Result<Self, Box<dyn Error>> {
let config_path = env::var("CONFIG_PATH").unwrap_or_else(|_| String::from("config"));
let config = read_to_string(&config_path)?;
let mut map = HashMap::new();
let lines = config.split("\n").into_iter();
for (i, line) in lines.enumerate() {
let mut parts = line.split_whitespace();
let Some(method_str) = parts.next() else { continue };
let method = Method::serialize(&method_str)
.ok_or(format!("config line {i} has invalid http method: {method_str}"))?;
let route = parts.next()
.ok_or(format!("config line {i} missing http route"))?;
let script = parts.next()
.ok_or(format!{"config line {i} missing script path"})?;
let key = Self::key(&method, route);
let value = Script::new(script.to_owned());
println!("adding script {script} for {} {route}", method.deserialize());
map.insert(key, value);
}
if map.len() < 1 {
return Err("cannot run server, config is empty".into())
}
Ok(Self { map })
}
pub fn get(&self, method: &Method, route: &str) -> Option<&Script> {
self.map.get(&Self::key(method, route))
}
}
|