From 07c46aef8bb4b126ae75eb1e559ecca26addad69 Mon Sep 17 00:00:00 2001 From: nullsoepic Date: Sun, 2 Jun 2024 20:20:18 +0200 Subject: [PATCH 1/6] Native JSON functions, time(), and handle non-json responses to fetch --- napture/src/b9/lua.rs | 64 +++++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/napture/src/b9/lua.rs b/napture/src/b9/lua.rs index 0d745c30..5a7d366a 100644 --- a/napture/src/b9/lua.rs +++ b/napture/src/b9/lua.rs @@ -4,6 +4,7 @@ use std::thread; use super::css::Styleable; use super::html::Tag; +use chrono::Utc; use glib::GString; use gtk::prelude::*; use mlua::{prelude::*, StdLib}; @@ -192,6 +193,7 @@ pub(crate) async fn run(luacode: String, tags: Rc>>, taburl: St let globals = lua.globals(); let window_table = lua.create_table()?; + let json_table = lua.create_table()?; let query_table = lua.create_table()?; let parts: Vec<&str> = taburl.splitn(2, '?').collect(); @@ -263,43 +265,56 @@ pub(crate) async fn run(luacode: String, tags: Rc>>, taburl: St let errcode = Rc::new(RefCell::new(res.status().as_u16())); let text = res.text().unwrap_or_default(); - let body = serde_json::from_str(&text); - let result = match body { - Ok(body) => body, - Err(e) => { - let errcode_clone = Rc::clone(&errcode); - - lualog!("lua", format!("INFO: failed to parse JSON from response body: {}", e)); - let mut map: Map = Map::new(); - - map.insert("status".to_owned(), serde_json::Value::Number(serde_json::Number::from_f64(*errcode_clone.borrow() as f64).unwrap())); - map.insert("content".to_owned(), serde_json::Value::String(text)); - - serde_json::Value::Object(map) - } - }; - - result + text }); - let json = match handle.join() { - Ok(json) => json, + let result = match handle.join() { + Ok(result) => result, Err(_) => { lualog!( "error", format!("Failed to join request thread at fetch request. Originates from the Lua runtime. Returning null.") ); - serde_json::Value::Null + "null".to_string() } }; - lua.to_value(&json) + lua.to_value(&result) + })?; + + let json_stringify = lua.create_function(|lua, table: LuaTable| { + match serde_json::to_string(&table) { + Ok(value) => Ok(lua.to_value(&value)?), + Err(_) => { + lualog!( + "error", + format!("Failed to stringify JSON. Returning null.") + ); + Ok(lua.null()) + } + } + })?; + + let json_parse = lua.create_function(|lua, json: String| { + match serde_json::from_str::(&json) { + Ok(value) => Ok(lua.to_value(&value)?), + Err(_) => { + lualog!( + "error", + format!("Failed to parse JSON. Returning null.") + ); + Ok(lua.null()) + } + } })?; window_table.set("link", taburl)?; window_table.set("query", query_table)?; + json_table.set("stringify", json_stringify)?; + json_table.set("parse", json_parse)?; + globals.set("print", lua.create_function(print)?)?; globals.set( "get", @@ -308,7 +323,14 @@ pub(crate) async fn run(luacode: String, tags: Rc>>, taburl: St })? )?; globals.set("fetch", fetchtest)?; + globals.set("json", json_table)?; globals.set("window", window_table)?; + globals.set( + "time", + lua.create_function(move |_, () | { + Ok(Utc::now().timestamp()) + })? + )?; let ok = lua.load(luacode).eval::(); From 03006c89db22fb2e2471e91a01066763697d83e9 Mon Sep 17 00:00:00 2001 From: nullsoepic Date: Sun, 2 Jun 2024 23:49:17 +0200 Subject: [PATCH 2/6] Basic require implementation --- napture/src/b9/lua.rs | 47 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/napture/src/b9/lua.rs b/napture/src/b9/lua.rs index 5a7d366a..cee07728 100644 --- a/napture/src/b9/lua.rs +++ b/napture/src/b9/lua.rs @@ -12,7 +12,7 @@ use mlua::{prelude::*, StdLib}; use mlua::{Lua, LuaSerdeExt, OwnedFunction, Value}; use reqwest::header::{HeaderMap, HeaderName, HeaderValue}; -use serde_json::Map; +use std::sync::{Arc, Mutex}; use crate::lualog; @@ -309,6 +309,50 @@ pub(crate) async fn run(luacode: String, tags: Rc>>, taburl: St } })?; + let require = lua.create_async_function(|lua, module: String| async move { + let uri = if module.starts_with("http://") || module.starts_with("https://") { + module + } else { + format!("{}/{}", &taburl, module) + }; + lualog!("info", format!("Fetching {}", uri)); + + let handle = thread::spawn(move || { + let client = reqwest::blocking::Client::new(); + + let req = client.get(uri); + + let res = match req.send() { + Ok(res) => res, + Err(e) => { + return format!("Failed to send request: {}", e).into(); + } + }; + + let errcode = Rc::new(RefCell::new(res.status().as_u16())); + + let text = res.text().unwrap_or_default(); + + text + }); + + let result = match handle.join() { + Ok(result) => result, + Err(_) => { + lualog!( + "error", + format!("Failed to join request thread at fetch request. Originates from the Lua runtime. Returning null.") + ); + "null".to_string() + } + }; + + let load = lua.load(&result); + let result = load.eval::(); + + result + })?; + window_table.set("link", taburl)?; window_table.set("query", query_table)?; @@ -325,6 +369,7 @@ pub(crate) async fn run(luacode: String, tags: Rc>>, taburl: St globals.set("fetch", fetchtest)?; globals.set("json", json_table)?; globals.set("window", window_table)?; + globals.set("require", require)?; globals.set( "time", lua.create_function(move |_, () | { From 1055307d877cdef81dbb9d892d3cde961158cfa5 Mon Sep 17 00:00:00 2001 From: nullsoepic Date: Mon, 3 Jun 2024 15:54:32 +0200 Subject: [PATCH 3/6] Working require implementation Rust is too annoying for taburl to be used here, so the module must be a full url --- napture/src/b9/lua.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/napture/src/b9/lua.rs b/napture/src/b9/lua.rs index cee07728..71c8f524 100644 --- a/napture/src/b9/lua.rs +++ b/napture/src/b9/lua.rs @@ -12,7 +12,6 @@ use mlua::{prelude::*, StdLib}; use mlua::{Lua, LuaSerdeExt, OwnedFunction, Value}; use reqwest::header::{HeaderMap, HeaderName, HeaderValue}; -use std::sync::{Arc, Mutex}; use crate::lualog; @@ -310,17 +309,15 @@ pub(crate) async fn run(luacode: String, tags: Rc>>, taburl: St })?; let require = lua.create_async_function(|lua, module: String| async move { - let uri = if module.starts_with("http://") || module.starts_with("https://") { - module - } else { - format!("{}/{}", &taburl, module) - }; - lualog!("info", format!("Fetching {}", uri)); + if !module.starts_with("http://") && !module.starts_with("https://") { + lualog!("error", "Module argument must be a URL."); + return Ok(lua.null()); + } let handle = thread::spawn(move || { let client = reqwest::blocking::Client::new(); - let req = client.get(uri); + let req = client.get(module); let res = match req.send() { Ok(res) => res, From 69a2d389409ef63e931c551596aa5ec963ec7b69 Mon Sep 17 00:00:00 2001 From: nullsoepic Date: Mon, 3 Jun 2024 16:38:05 +0200 Subject: [PATCH 4/6] Return a table if fetch response is valid json --- napture/src/b9/lua.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/napture/src/b9/lua.rs b/napture/src/b9/lua.rs index 71c8f524..7b94a00d 100644 --- a/napture/src/b9/lua.rs +++ b/napture/src/b9/lua.rs @@ -265,7 +265,10 @@ pub(crate) async fn run(luacode: String, tags: Rc>>, taburl: St let text = res.text().unwrap_or_default(); - text + match serde_json::from_str::(&text) { + Ok(json) => json, + Err(_) => serde_json::Value::String(text), + } }); let result = match handle.join() { @@ -275,7 +278,7 @@ pub(crate) async fn run(luacode: String, tags: Rc>>, taburl: St "error", format!("Failed to join request thread at fetch request. Originates from the Lua runtime. Returning null.") ); - "null".to_string() + serde_json::Value::String("null".to_string()) } }; From 0f76e6cc580b22b0e15cf783ffd50a7d4ac7fa57 Mon Sep 17 00:00:00 2001 From: nullsoepic Date: Tue, 4 Jun 2024 17:36:35 +0200 Subject: [PATCH 5/6] Revert changes to fetch & remove time --- napture/src/b9/lua.rs | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/napture/src/b9/lua.rs b/napture/src/b9/lua.rs index 940ffc30..642127e8 100644 --- a/napture/src/b9/lua.rs +++ b/napture/src/b9/lua.rs @@ -4,7 +4,6 @@ use std::thread; use super::css::Styleable; use super::html::Tag; -use chrono::Utc; use glib::GString; use gtk::prelude::*; use mlua::{prelude::*, StdLib}; @@ -12,6 +11,7 @@ use mlua::{prelude::*, StdLib}; use mlua::{OwnedFunction, Value}; use reqwest::header::{HeaderMap, HeaderName, HeaderValue}; +use serde_json::Map; use crate::{lualog, globals::LUA_TIMEOUTS}; use glib::translate::FromGlib; @@ -313,25 +313,38 @@ pub(crate) async fn run(luacode: String, tags: Rc>>, taburl: St let errcode = Rc::new(RefCell::new(res.status().as_u16())); let text = res.text().unwrap_or_default(); + let body = serde_json::from_str(&text); - match serde_json::from_str::(&text) { - Ok(json) => json, - Err(_) => serde_json::Value::String(text), - } + let result = match body { + Ok(body) => body, + Err(e) => { + let errcode_clone = Rc::clone(&errcode); + + lualog!("lua", format!("INFO: failed to parse JSON from response body: {}", e)); + let mut map: Map = Map::new(); + + map.insert("status".to_owned(), serde_json::Value::Number(serde_json::Number::from_f64(*errcode_clone.borrow() as f64).unwrap())); + map.insert("content".to_owned(), serde_json::Value::String(text)); + + serde_json::Value::Object(map) + } + }; + + result }); - let result = match handle.join() { - Ok(result) => result, + let json = match handle.join() { + Ok(json) => json, Err(_) => { lualog!( "error", format!("Failed to join request thread at fetch request. Originates from the Lua runtime. Returning null.") ); - serde_json::Value::String("null".to_string()) + serde_json::Value::Null } }; - lua.to_value(&result) + lua.to_value(&json) })?; let json_stringify = lua.create_function(|lua, table: LuaTable| { @@ -431,12 +444,6 @@ pub(crate) async fn run(luacode: String, tags: Rc>>, taburl: St globals.set("json", json_table)?; globals.set("window", window_table)?; globals.set("require", require)?; - globals.set( - "time", - lua.create_function(move |_, () | { - Ok(Utc::now().timestamp()) - })? - )?; if let Err(e) = lua.sandbox(true) { lualog!("error", format!("failed to enable sandbox: {}", e)); From 8bf3b81381137348b093424a56212ed4062408d3 Mon Sep 17 00:00:00 2001 From: nullsoepic Date: Tue, 4 Jun 2024 17:41:34 +0200 Subject: [PATCH 6/6] Sandbox require --- napture/src/b9/lua.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/napture/src/b9/lua.rs b/napture/src/b9/lua.rs index 642127e8..a832971b 100644 --- a/napture/src/b9/lua.rs +++ b/napture/src/b9/lua.rs @@ -409,10 +409,13 @@ pub(crate) async fn run(luacode: String, tags: Rc>>, taburl: St } }; - let load = lua.load(&result); - let result = load.eval::(); - - result + if let Err(e) = lua.sandbox(true) { + lualog!("error", format!("failed to enable sandbox: {}", e)); + Err(LuaError::runtime("failed to enable sandbox")) + } else { + let load = lua.load(result); + load.eval::() + } })?; window_table.set("link", taburl)?;