summaryrefslogtreecommitdiff
path: root/src/handler/lua.rs
blob: 377111f75da0d7ddc071b25604c12a53c98daf2f (plain)
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
use std::{collections::HashMap, str::FromStr};

use mlua::{FromLua, Lua, Value};

use crate::{
    handler::{self, Handle},
    request::Request,
    response::{Body, Response, Status},
};

#[derive(Debug, Clone)]
pub struct LuaResponse {
    content: Option<Vec<u8>>,
    status: Status,
    headers: HashMap<String, Vec<u8>>,
}

impl Handle for LuaResponse {
    async fn handle(self, _: Request) -> Result<Response, handler::Error> {
        Ok(Response::builder()
            .status(self.status)
            .headers(self.headers)
            .body(match self.content {
                Some(content) => Body::Buffer(content),
                None => Body::Empty,
            }))
    }
}

impl FromLua for LuaResponse {
    fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
        match value {
            Value::Table(table) => {
                let content = match table.get("content")? {
                    Value::String(string) => Some(string.as_bytes().to_vec()),
                    _ => None,
                };

                let status = match table.get("status")? {
                    Value::String(string) => Status::from_str(&string.to_str()?).map_err(|e| {
                        mlua::Error::RuntimeError(format!(
                            "failed to parse status from string: {e}"
                        ))
                    })?,
                    Value::Integer(i) => Status::from_repr(i as usize).ok_or_else(|| {
                        mlua::Error::runtime(format!("failed to parse status from integer: {i}"))
                    })?,
                    _ => return Err(mlua::Error::runtime("invalid type when reading status")),
                };

                let headers: HashMap<String, Vec<u8>> = match table.get::<Value>("headers")? {
                    Value::Table(table) => {
                        let mut hashmap = HashMap::<String, Vec<u8>>::new();

                        for result in table.pairs() {
                            let (key, value): (String, mlua::BString) = result?;

                            hashmap.insert(key, value.to_vec());
                        }

                        hashmap
                    }
                    _ => HashMap::new(),
                };

                Ok(Self {
                    content,
                    status,
                    headers,
                })
            }
            _ => Err(mlua::Error::runtime("expected table")),
        }
    }
}