use std::collections::HashMap; use warp::Filter; use serde::{ Serialize, Deserialize }; use rust_util::XResult; include!("lib.rs"); pub use qjs::*; pub use sig::*; pub use rpc::*; pub use util::*; #[derive(Serialize, Deserialize)] struct CallJSBody { method: String, params: Option, } #[tokio::main] async fn main() { let get_public_key = warp::path("get_signing_public_key").map(|| { match get_signing_public_key() { None => "null".to_owned(), Some(public_key) => { let mut map = HashMap::new(); map.insert("public_key", hex::encode(&public_key)); serde_json::to_string_pretty(&map).unwrap_or_else(|e| format!("get public key error: {}", e)) + "\n" }, } }); let list_js = warp::path("list_js").map(|| { call_fn(|| -> XResult { let mut jss = vec![]; if let Ok(read_dir) = std::fs::read_dir("js") { for entry in read_dir { if let Ok(dir_entry) = entry { if let Ok(file_name) = dir_entry.file_name().into_string() { if file_name.ends_with(".js") { let chars = file_name.chars(); jss.push(chars.take(file_name.chars().count() - 3).collect::()); } } } } } Ok(serde_json::to_string_pretty(&jss).unwrap() + "\n") }) }); let get_js = warp::path!("get_js" / String).map(|js_hex| { call_fn(|| -> XResult { let js_fn = format!("js/{}.js", js_hex); let js_sig_fn = format!("js/{}.sig.json", js_hex); let js = read_file(&js_fn)?; let js_sig = read_file(&js_sig_fn)?; let signed_message: SignedMessage = serde_json::from_str(&js_sig)?; let mut result = HashMap::new(); result.insert("js", js); result.insert("sig", js_sig); result.insert("verify", signed_message.verify(&load_signing_key_pair()?.public_key()).to_string()); Ok(serde_json::to_string_pretty(&result)? + "\n") }) }); let call_js = warp::post() .and(warp::path!("call_js" / String)) .and(warp::body::json()) .map(|js_hex, call_js_body: CallJSBody| { call_fn(|| -> XResult { let js_fn = format!("js/{}.js", js_hex); let js_sig_fn = format!("js/{}.sig.json", js_hex); let js = read_file(&js_fn)?; let js_sig = read_file(&js_sig_fn)?; let signed_message: SignedMessage = serde_json::from_str(&js_sig)?; if !signed_message.verify(&load_signing_key_pair()?.public_key()) { return Ok(HttpResult::new_400( "Script verify failed!".to_owned(), Some(format!("{}", js_hex)) ).to_string_pretty()); } let context = QuickJSContext::new()?; context.init(&js)?; let r = context.call_fn(&call_js_body.method, &call_js_body.params.unwrap_or_else(|| "[]".to_owned())); let mut http_status = HttpResult::new(); http_status.js_hash(format!("{}", js_hex)); match r { Err(e) => { http_status.status(500) .message("Script call failed!".to_owned()) .result(format!("{}", e)); }, Ok(r) => { http_status.status(200) .message("Script call successed!".to_owned()) .result(r.into_string().unwrap_or_else(|| "null".to_owned())); }, } Ok(http_status.to_string_pretty()) }) }); println!("Listen at 127.0.0.1:8888 ..."); warp::serve( get_public_key.or(list_js) .or(get_js) .or(call_js) ) .run(([127, 0, 0, 1], 8888)) .await; } fn call_fn(f: F) -> String where F: FnOnce() -> XResult { match f() { Err(e) => { HttpResult::new_500( "Call fn failed!".to_owned(), Some(format!("{}", e)) ).to_string_pretty() }, Ok(r) => r, } }