omg so much better updates now doing good

This commit is contained in:
2025-01-23 19:25:23 +01:00
parent 67ef237e93
commit 1f017dc24b

View File

@@ -4,7 +4,7 @@ use std::{collections::HashMap, fs, io::ErrorKind, path::PathBuf, str::FromStr};
use icon::extract_icon; use icon::extract_icon;
use mlua::{ use mlua::{
Lua, Table, FromLua, Lua, Number, Table,
Value::{self as LuaValue}, Value::{self as LuaValue},
}; };
use once_cell::sync::{Lazy, OnceCell}; use once_cell::sync::{Lazy, OnceCell};
@@ -17,6 +17,7 @@ use axum::{
routing::get, routing::get,
}; };
use base64::prelude::*; use base64::prelude::*;
use reqwest::Method;
use serde::Serialize; use serde::Serialize;
use tera::{to_value, Context, Result as TeraResult, Tera, Value}; use tera::{to_value, Context, Result as TeraResult, Tera, Value};
use time::OffsetDateTime; use time::OffsetDateTime;
@@ -29,6 +30,34 @@ pub type AResult<T> = Result<T, AError>;
pub static CWD: Lazy<PathBuf> = Lazy::new(|| std::env::current_dir().unwrap()); pub static CWD: Lazy<PathBuf> = Lazy::new(|| std::env::current_dir().unwrap());
#[derive(Debug, Clone)]
struct ArrayBuffer(Vec<u8>);
impl mlua::FromLua for ArrayBuffer {
fn from_lua(value: LuaValue, _: &Lua) -> mlua::Result<Self> {
if let Some(data) = value.as_str() {
return Ok(Self(data.as_bytes().to_owned()));
}
if let Some(data) = value.as_table() {
let mut out = vec![];
for pair in data.pairs::<mlua::Value, mlua::Value>() {
let (_, v) = pair?;
if let Some(value) = v.as_integer() {
out.push(value as u8);
}
}
return Ok(Self(out));
}
Err(mlua::Error::FromLuaConversionError {
from: value.type_name(),
to: "ArrayBuffer".to_string(),
message: None,
})
}
}
pub static TERA: Lazy<Tera> = Lazy::new(|| { pub static TERA: Lazy<Tera> = Lazy::new(|| {
let mut tera = Tera::default(); let mut tera = Tera::default();
tera.add_raw_template( tera.add_raw_template(
@@ -172,6 +201,48 @@ struct FileInfo {
description: Option<String>, description: Option<String>,
} }
#[derive(Debug, Clone)]
struct FetchOptions {
method: String,
headers: HashMap<String, String>,
body: Option<ArrayBuffer>,
}
impl Default for FetchOptions {
fn default() -> Self {
Self {
method: "GET".to_string(),
headers: HashMap::new(),
body: None,
}
}
}
impl FromLua for FetchOptions {
fn from_lua(value: LuaValue, _lua: &Lua) -> mlua::Result<Self> {
let Some(options) = value.as_table() else {
return Err(mlua::Error::FromLuaConversionError {
from: value.type_name(),
to: "FetchOptions".to_string(),
message: Some("options must be a table".to_string()),
});
};
let mut result = FetchOptions::default();
if let Ok(method) = options.get::<String>("method") {
result.method = method;
}
if let Ok(headers) = options.get::<HashMap<String, String>>("headers") {
result.headers = headers;
}
if let Ok(body) = options.get::<Option<ArrayBuffer>>("body") {
result.body = body;
}
Ok(result)
}
}
#[tokio::main] #[tokio::main]
async fn main() -> AResult<()> { async fn main() -> AResult<()> {
let listener = tokio::net::TcpListener::bind("[::]:3000").await.unwrap(); let listener = tokio::net::TcpListener::bind("[::]:3000").await.unwrap();
@@ -216,12 +287,75 @@ async fn file_handler(request: Request) -> impl IntoResponse {
use mlua::{ExternalResult, LuaSerdeExt}; use mlua::{ExternalResult, LuaSerdeExt};
let fetch_json = lua let fetch = lua
.create_function(|lua, uri: String| { .create_function(|lua, params: (String, Option<FetchOptions>)| {
let resp = reqwest::blocking::get(&uri) let uri = params.0;
let options = params.1;
let options = options.unwrap_or_default();
let Ok(method) = Method::from_bytes(options.method.as_bytes()) else {
return Err(mlua::Error::RuntimeError("Invalid method".to_string()));
};
let Ok(uri) = reqwest::Url::parse(&uri) else {
return Err(mlua::Error::RuntimeError("Invalid uri".to_string()));
};
let mut request = reqwest::blocking::Request::new(method, uri);
// let mut headers = ;
for (k, v) in &options.headers {
let Ok(k) = reqwest::header::HeaderName::from_str(k) else {
return Err(mlua::Error::RuntimeError("Invalid header name".to_string()));
};
let Ok(v) = reqwest::header::HeaderValue::from_str(v) else {
return Err(mlua::Error::RuntimeError(
"Invalid header value".to_string(),
));
};
let _ = request.headers_mut().try_append(k, v);
}
*request.body_mut() = options.body.map(|f| f.0.into());
let client = reqwest::blocking::Client::new();
let resp = client
.execute(request)
.and_then(|resp| resp.error_for_status()) .and_then(|resp| resp.error_for_status())
.into_lua_err()?; .into_lua_err()?;
let json = resp.json::<serde_json::Value>().into_lua_err()?;
let json = resp.bytes().into_lua_err()?;
lua.to_value(&json.to_vec())
})
.map_err(|e| {
eprintln!("Lua Error: {:?}", e);
render_lua_error(e)
})?;
let base64_encode = lua
.create_function(|lua, bytes: ArrayBuffer| {
let b64 = BASE64_STANDARD.encode(&bytes.0);
lua.to_value(&b64)
})
.map_err(|e| {
eprintln!("Lua Error: {:?}", e);
render_lua_error(e)
})?;
let base64_decode = lua
.create_function(|lua, data: ArrayBuffer| {
let b64 = BASE64_STANDARD.decode(&data.0).into_lua_err()?;
lua.to_value(&b64)
})
.map_err(|e| {
eprintln!("Lua Error: {:?}", e);
render_lua_error(e)
})?;
let json_decode = lua
.create_function(|lua, data: ArrayBuffer| {
let data = String::from_utf8_lossy(&data.0);
let json = serde_json::from_str::<serde_json::Value>(&data).into_lua_err()?; //data.json::<serde_json::Value>().into_lua_err()?;
lua.to_value(&json) lua.to_value(&json)
}) })
.map_err(|e| { .map_err(|e| {
@@ -229,14 +363,10 @@ async fn file_handler(request: Request) -> impl IntoResponse {
render_lua_error(e) render_lua_error(e)
})?; })?;
let fetch_b64 = lua let to_string = lua
.create_function(|lua, uri: String| { .create_function(|lua, data: ArrayBuffer| {
let resp = reqwest::blocking::get(&uri) let data = String::from_utf8_lossy(&data.0);
.and_then(|resp| resp.error_for_status()) lua.to_value(&data)
.into_lua_err()?;
let bytes = resp.bytes().into_lua_err()?;
let b64 = BASE64_STANDARD.encode(bytes);
lua.to_value(&b64)
}) })
.map_err(|e| { .map_err(|e| {
eprintln!("Lua Error: {:?}", e); eprintln!("Lua Error: {:?}", e);
@@ -253,21 +383,41 @@ async fn file_handler(request: Request) -> impl IntoResponse {
render_lua_error(e) render_lua_error(e)
})?; })?;
globals.set("fetch", fetch_json).map_err(|e| { globals.set("fetch", fetch).map_err(|e| {
eprintln!("Lua Error: {:?}", e); eprintln!("Lua Error: {:?}", e);
render_lua_error(e) render_lua_error(e)
})?; })?;
globals.set("fetch_b64", fetch_b64).map_err(|e| { globals.set("base64_encode", base64_encode).map_err(|e| {
eprintln!("Lua Error: {:?}", e); eprintln!("Lua Error: {:?}", e);
render_lua_error(e) render_lua_error(e)
})?; })?;
globals.set("base64_decode", base64_decode).map_err(|e| {
eprintln!("Lua Error: {:?}", e);
render_lua_error(e)
})?;
globals.set("json_decode", json_decode).map_err(|e| {
eprintln!("Lua Error: {:?}", e);
render_lua_error(e)
})?;
// globals.set("fetch_b64", fetch_b64).map_err(|e| {
// eprintln!("Lua Error: {:?}", e);
// render_lua_error(e)
// })?;
globals.set("dbg", dbg).map_err(|e| { globals.set("dbg", dbg).map_err(|e| {
eprintln!("Lua Error: {:?}", e); eprintln!("Lua Error: {:?}", e);
render_lua_error(e) render_lua_error(e)
})?; })?;
globals.set("to_string", to_string).map_err(|e| {
eprintln!("Lua Error: {:?}", e);
render_lua_error(e)
})?;
let request_table = lua.create_table().map_err(|e| { let request_table = lua.create_table().map_err(|e| {
eprintln!("Lua Error: {:?}", e); eprintln!("Lua Error: {:?}", e);
render_lua_error(e) render_lua_error(e)
@@ -415,6 +565,12 @@ async fn file_handler(request: Request) -> impl IntoResponse {
let mut response = Html(script).into_response(); let mut response = Html(script).into_response();
if let Ok(status_code) = result.get::<Number>("code") {
if let Ok(code) = StatusCode::from_u16(status_code as u16) {
*response.status_mut() = code;
}
}
if let Ok(headers) = result.get::<Table>("headers") { if let Ok(headers) = result.get::<Table>("headers") {
let pairs = headers.pairs::<String, String>(); let pairs = headers.pairs::<String, String>();
@@ -425,11 +581,11 @@ async fn file_handler(request: Request) -> impl IntoResponse {
})?; })?;
response.headers_mut().insert( response.headers_mut().insert(
HeaderName::from_str(&k).map_err(|e| { HeaderName::from_str(&k).map_err(|e| {
eprintln!("Lua Error: {:?}", e); eprintln!("Response Error: {:?}", e);
(StatusCode::INTERNAL_SERVER_ERROR, e.to_string()) (StatusCode::INTERNAL_SERVER_ERROR, e.to_string())
})?, })?,
HeaderValue::from_str(&v).map_err(|e| { HeaderValue::from_str(&v).map_err(|e| {
eprintln!("Lua Error: {:?}", e); eprintln!("Response Error: {:?}", e);
(StatusCode::INTERNAL_SERVER_ERROR, e.to_string()) (StatusCode::INTERNAL_SERVER_ERROR, e.to_string())
})?, })?,
); );
@@ -439,17 +595,94 @@ async fn file_handler(request: Request) -> impl IntoResponse {
Ok(response) Ok(response)
} }
#[allow(unused_variables)]
fn render_lua_error(e: mlua::Error) -> (StatusCode, String) { fn render_lua_error(e: mlua::Error) -> (StatusCode, String) {
let e = e match e {
.to_string() mlua::Error::SyntaxError {
.split(':') message,
.skip(4) incomplete_input,
.collect::<Vec<&str>>() } => {
.join(":"); let mut message = message.split("]:");
( message.next();
StatusCode::INTERNAL_SERVER_ERROR, (
format!("LuaError on line {}", e), StatusCode::INTERNAL_SERVER_ERROR,
) message.next().unwrap_or_default().to_string(),
)
}
mlua::Error::RuntimeError(message) => (StatusCode::INTERNAL_SERVER_ERROR, message),
mlua::Error::MemoryError(message) => (StatusCode::INTERNAL_SERVER_ERROR, message),
mlua::Error::SafetyError(message) => (StatusCode::INTERNAL_SERVER_ERROR, message),
mlua::Error::MemoryControlNotAvailable => (
StatusCode::INTERNAL_SERVER_ERROR,
"MemoryControlNotAvailable".to_string(),
),
mlua::Error::RecursiveMutCallback => (
StatusCode::INTERNAL_SERVER_ERROR,
"RecursiveMutCallback".to_string(),
),
mlua::Error::CallbackDestructed => (
StatusCode::INTERNAL_SERVER_ERROR,
"CallbackDestructed".to_string(),
),
mlua::Error::StackError => (StatusCode::INTERNAL_SERVER_ERROR, "StackError".to_string()),
mlua::Error::BindError => (StatusCode::INTERNAL_SERVER_ERROR, "BindError".to_string()),
mlua::Error::BadArgument {
to,
pos,
name,
cause,
} => (
StatusCode::INTERNAL_SERVER_ERROR,
format!(
"Bad Argument:\n\tto: {}\n\tpos: {}\n\tname: {}\n\tcause: {:?}",
to.unwrap_or_default(),
pos,
name.unwrap_or_default(),
cause
),
),
mlua::Error::ToLuaConversionError { from, to, message } => (
StatusCode::INTERNAL_SERVER_ERROR,
message.unwrap_or_default(),
),
mlua::Error::FromLuaConversionError { from, to, message } => (
StatusCode::INTERNAL_SERVER_ERROR,
message.unwrap_or_default(),
),
mlua::Error::CoroutineUnresumable => (StatusCode::INTERNAL_SERVER_ERROR, String::new()),
mlua::Error::UserDataTypeMismatch => (StatusCode::INTERNAL_SERVER_ERROR, String::new()),
mlua::Error::UserDataDestructed => (StatusCode::INTERNAL_SERVER_ERROR, String::new()),
mlua::Error::UserDataBorrowError => (StatusCode::INTERNAL_SERVER_ERROR, String::new()),
mlua::Error::UserDataBorrowMutError => (StatusCode::INTERNAL_SERVER_ERROR, String::new()),
mlua::Error::MetaMethodRestricted(message) => (StatusCode::INTERNAL_SERVER_ERROR, message),
mlua::Error::MetaMethodTypeError {
method,
type_name,
message,
} => (
StatusCode::INTERNAL_SERVER_ERROR,
message.unwrap_or_default(),
),
mlua::Error::MismatchedRegistryKey => (StatusCode::INTERNAL_SERVER_ERROR, String::new()),
mlua::Error::CallbackError { traceback, cause } => (
StatusCode::INTERNAL_SERVER_ERROR,
format!("{}\n\n{:#?}", traceback, cause),
),
mlua::Error::PreviouslyResumedPanic => (StatusCode::INTERNAL_SERVER_ERROR, String::new()),
mlua::Error::SerializeError(message) => (StatusCode::INTERNAL_SERVER_ERROR, message),
mlua::Error::DeserializeError(message) => (StatusCode::INTERNAL_SERVER_ERROR, message),
mlua::Error::ExternalError(error) => {
(StatusCode::INTERNAL_SERVER_ERROR, format!("{:#?}", error))
}
mlua::Error::WithContext { context, cause } => (
StatusCode::INTERNAL_SERVER_ERROR,
format!("{}\n\n{:#?}", context, cause),
),
_ => (
StatusCode::INTERNAL_SERVER_ERROR,
String::from("Unknown Error"),
),
}
} }
async fn handler(request: Request) -> Result<Html<String>, (StatusCode, String)> { async fn handler(request: Request) -> Result<Html<String>, (StatusCode, String)> {