From e939c6bb2f391e0e4fce2fb702b146b2407ed6d0 Mon Sep 17 00:00:00 2001 From: theMackabu Date: Sat, 9 Dec 2023 12:29:57 -0800 Subject: [PATCH] support status codes --- Cargo.lock | 36 ++++++++++---------- Cargo.toml | 5 ++- Maidfile.toml | 8 ++--- app.routes | 4 +-- script/Cargo.toml | 8 +++++ script/src/main.rs | 3 ++ src/main.rs | 83 +++++++++++++++++++++++++++++++--------------- 7 files changed, 96 insertions(+), 51 deletions(-) create mode 100644 script/Cargo.toml create mode 100644 script/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 6780225..a397f53 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -695,24 +695,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" -[[package]] -name = "httpin" -version = "0.1.0" -dependencies = [ - "actix-web", - "fancy-regex", - "lazy_static", - "macros-rs", - "peg", - "reqwest", - "rhai", - "rhai-fs", - "rhai-url", - "serde", - "serde_json", - "termcolor", -] - [[package]] name = "hyper" version = "0.14.27" @@ -1318,6 +1300,24 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "script" +version = "0.1.0" +dependencies = [ + "actix-web", + "fancy-regex", + "lazy_static", + "macros-rs", + "peg", + "reqwest", + "rhai", + "rhai-fs", + "rhai-url", + "serde", + "serde_json", + "termcolor", +] + [[package]] name = "security-framework" version = "2.9.2" diff --git a/Cargo.toml b/Cargo.toml index 5215be1..1ff250d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,10 @@ [package] -name = "httpin" +name = "script" version = "0.1.0" edition = "2021" +license = "MIT" +repository = "https://lab.themackabu.dev/self/script" +description = "barebones http scripting" [dependencies] peg = "0.8.2" diff --git a/Maidfile.toml b/Maidfile.toml index f2883e5..3ac0b07 100644 --- a/Maidfile.toml +++ b/Maidfile.toml @@ -1,18 +1,18 @@ [project] -name = "httpin" +name = "script" version = "0.1.0" [tasks] clean = { script = ["rm -rf bin", "mkdir bin"] } -run = { script = ["maid build -q", "./bin/httpin"] } +run = { script = ["maid build -q", "./bin/script"] } [tasks.build] depends = ["clean"] script = [ "cargo zigbuild --release", - "cp target/release/httpin bin/httpin" + "cp target/release/script bin/script" ] [tasks.build.cache] path = "src" -target = ["bin/httpin"] \ No newline at end of file +target = ["bin/script"] \ No newline at end of file diff --git a/app.routes b/app.routes index bc147c0..fd0045f 100644 --- a/app.routes +++ b/app.routes @@ -7,11 +7,11 @@ hello() { } example() { - html(get("https://example.org")) + html(http::get("https://example.org")) } example/json() { - json(get("https://httpbin.org/json")) + text(http::get("https://httpbin.org//json")) } test.json() { diff --git a/script/Cargo.toml b/script/Cargo.toml new file mode 100644 index 0000000..c37bf22 --- /dev/null +++ b/script/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "script" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/script/src/main.rs b/script/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/script/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/src/main.rs b/src/main.rs index 7d619df..2c3e20c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,11 +4,11 @@ use macros_rs::{crashln, ternary}; use reqwest::blocking::Client; use std::{fs, path::PathBuf}; -use rhai::{packages::Package, Engine, Map, ParseError, Scope, AST}; +use rhai::{packages::Package, plugin::*, Engine, FnNamespace, Map, ParseError, Scope, AST}; use rhai_fs::FilesystemPackage; use rhai_url::UrlPackage; -use actix_web::{get, http::header::ContentType, web::Path, App, HttpRequest, HttpResponse, HttpServer, Responder}; +use actix_web::{get, http::header::ContentType, http::StatusCode, web::Path, App, HttpRequest, HttpResponse, HttpServer, Responder}; // convert to peg lazy_static! { @@ -33,34 +33,56 @@ fn convert_to_format(input: &str) -> String { .to_string() } -fn text(string: String) -> (String, ContentType) { (string, ContentType::plaintext()) } -fn html(string: String) -> (String, ContentType) { (string, ContentType::html()) } +fn convert_status(code: i64) -> StatusCode { + let u16_code = code as u16; + StatusCode::from_u16(u16_code).unwrap_or(StatusCode::OK) +} -fn get(url: String) -> String { - let client = Client::new(); - let response = match client.get(url).send() { - Ok(res) => res, - Err(err) => return err.to_string(), - }; +fn error(engine: &Engine, path: &str, err: ParseError) -> AST { + match engine.compile(format!("fn {path}(){{text(\"error reading script file: {err}\")}}")) { + Ok(ast) => ast, + Err(_) => Default::default(), + } +} - if response.status().is_success() { - response.text().unwrap() - } else { - format!("request failed with status code: {}", response.status()) +#[export_module] +mod default { + pub fn text(string: String) -> (String, ContentType, StatusCode) { (string, ContentType::plaintext(), StatusCode::OK) } + pub fn html(string: String) -> (String, ContentType, StatusCode) { (string, ContentType::html(), StatusCode::OK) } + pub fn json(object: Map) -> (String, ContentType, StatusCode) { + match serde_json::to_string(&object) { + Ok(result) => (result, ContentType::json(), StatusCode::OK), + Err(err) => (err.to_string(), ContentType::plaintext(), StatusCode::INTERNAL_SERVER_ERROR), + } } } -fn json(object: Map) -> (String, ContentType) { - match serde_json::to_string(&object) { - Ok(result) => (result, ContentType::json()), - Err(err) => (err.to_string(), ContentType::plaintext()), +#[export_module] +mod status { + pub fn text(string: String, status: i64) -> (String, ContentType, StatusCode) { (string, ContentType::plaintext(), convert_status(status)) } + pub fn html(string: String, status: i64) -> (String, ContentType, StatusCode) { (string, ContentType::html(), convert_status(status)) } + pub fn json(object: Map, status: i64) -> (String, ContentType, StatusCode) { + match serde_json::to_string(&object) { + Ok(result) => (result, ContentType::json(), convert_status(status)), + Err(err) => (err.to_string(), ContentType::plaintext(), StatusCode::INTERNAL_SERVER_ERROR), + } } } -fn error(engine: &Engine, path: &str, err: ParseError) -> AST { - match engine.compile(format!("fn {path}(){{text(\"error reading script file: {err}\")}}")) { - Ok(ast) => ast, - Err(_) => Default::default(), +#[export_module] +mod http { + pub fn get(url: String) -> String { + let client = Client::new(); + let response = match client.get(url).send() { + Ok(res) => res, + Err(err) => return err.to_string(), + }; + + if response.status().is_success() { + response.text().unwrap() + } else { + format!("request failed with status code: {}", response.status()) + } } } @@ -73,6 +95,7 @@ async fn handler(url: Path, req: HttpRequest) -> impl Responder { let filename: PathBuf = "app.routes".into(); let fs_pkg = FilesystemPackage::new(); let url_pkg = UrlPackage::new(); + let http = exported_module!(http); let mut engine = Engine::new(); let mut scope = Scope::new(); @@ -84,6 +107,7 @@ async fn handler(url: Path, req: HttpRequest) -> impl Responder { fs_pkg.register_into_engine(&mut engine); url_pkg.register_into_engine(&mut engine); + engine.register_static_module("http", http.into()); scope .push_constant("path", url.to_string()) @@ -91,7 +115,13 @@ async fn handler(url: Path, req: HttpRequest) -> impl Responder { .push_constant("ver", format!("{:?}", req.version())) .push_constant("query", req.query_string().to_string()); - engine.register_fn("get", get).register_fn("text", text).register_fn("json", json).register_fn("html", html); + engine + .register_fn("text", default::text) + .register_fn("json", default::json) + .register_fn("html", default::html) + .register_fn("text", status::text) + .register_fn("json", status::json) + .register_fn("html", status::html); let contents = match fs::read_to_string(&filename) { Ok(contents) => contents, @@ -121,24 +151,25 @@ async fn handler(url: Path, req: HttpRequest) -> impl Responder { ast.set_source(filename.to_string_lossy().to_string()); - let (body, content_type) = match engine.call_fn::<(String, ContentType)>(&mut scope, &ast, &path, ()) { + let (body, content_type, status_code) = match engine.call_fn::<(String, ContentType, StatusCode)>(&mut scope, &ast, &path, ()) { Ok(response) => response, Err(err) => { if has_wildcard || has_error_page { engine - .call_fn::<(String, ContentType)>(&mut scope, &ast, ternary!(has_wildcard, "_wildcard", "_error_404"), (err.to_string(),)) + .call_fn::<(String, ContentType, StatusCode)>(&mut scope, &ast, ternary!(has_wildcard, "_wildcard", "_error_404"), (err.to_string(),)) .unwrap() } else { eprintln!("Error reading script file: {}\n{}", filename.to_string_lossy(), err); ( format!("function not found.\ndid you create {url}()?\n\nyou can add * {{}} or 404 {{}} routes as well."), ContentType::plaintext(), + StatusCode::NOT_FOUND, ) } } }; - HttpResponse::Ok().content_type(content_type).body(body) + HttpResponse::build(status_code).content_type(content_type).body(body) } #[actix_web::main] -- GitLab