mirror of
https://github.com/voltrevo/ValueScript.git
synced 2026-04-18 03:00:27 -04:00
Split out db_host
This commit is contained in:
@@ -1,17 +1,15 @@
|
||||
use std::{io::Write, process::exit, rc::Rc};
|
||||
|
||||
use actix_web::{dev, web, App, FromRequest, HttpRequest, HttpResponse, HttpServer, Responder};
|
||||
|
||||
use storage::{storage_head_ptr, SledBackend, Storage, StorageReader};
|
||||
use valuescript_compiler::{assemble, compile_str, inline_valuescript};
|
||||
use valuescript_compiler::{assemble, compile_str};
|
||||
use valuescript_vm::{
|
||||
vs_object::VsObject,
|
||||
vs_value::{ToVal, Val},
|
||||
Bytecode, DecoderMaker, VirtualMachine,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
create_db::create_db,
|
||||
db_host::db_host,
|
||||
exit_command_failed::exit_command_failed,
|
||||
handle_diagnostics_cli::handle_diagnostics_cli,
|
||||
parse_command_line::parse_command_line,
|
||||
@@ -152,132 +150,6 @@ fn db_call(path: &String, args: &[String]) {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
async fn get_body(req: &HttpRequest, mut payload: dev::Payload) -> Result<Val, actix_web::Error> {
|
||||
let payload = web::Payload::from_request(req, &mut payload).await?;
|
||||
|
||||
let body = payload
|
||||
.to_bytes_limited(1_024 * 1_024)
|
||||
.await
|
||||
.map_err(|_| actix_web::error::PayloadError::Overflow)??;
|
||||
|
||||
if body.is_empty() {
|
||||
Ok(Val::Undefined)
|
||||
} else {
|
||||
match serde_json::from_slice::<serde_json::Value>(&body) {
|
||||
Ok(json_value) => Ok(Val::from_json(&json_value)),
|
||||
Err(err) => Err(actix_web::error::ErrorBadRequest(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_request(
|
||||
req: HttpRequest,
|
||||
payload: web::Payload,
|
||||
data: web::Data<String>,
|
||||
) -> impl Responder {
|
||||
let path = req.path();
|
||||
let method = req.method();
|
||||
let mut storage = Storage::new(SledBackend::open(data.as_ref()).unwrap());
|
||||
|
||||
let body = match get_body(&req, payload.into_inner()).await {
|
||||
Ok(body) => body,
|
||||
Err(e) => return e.into(),
|
||||
};
|
||||
|
||||
let mut instance: Val = storage
|
||||
.get_head(storage_head_ptr(b"state"))
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
let fn_ = inline_valuescript(
|
||||
r#"
|
||||
export default function(req) {
|
||||
if ("handleRequest" in this) {
|
||||
return this.handleRequest(req);
|
||||
}
|
||||
|
||||
const handlerName = `${req.method} ${req.path}`;
|
||||
|
||||
if (!this[handlerName]) {
|
||||
throw new Error("No handler for request");
|
||||
}
|
||||
|
||||
if (req.method === "GET") {
|
||||
// Enforce GET as read-only
|
||||
const state = this;
|
||||
return state[handlerName](req.body);
|
||||
}
|
||||
|
||||
return this[handlerName](req.body);
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
||||
let req_val = VsObject {
|
||||
string_map: vec![
|
||||
("path".to_string(), path.to_val()),
|
||||
("method".to_string(), method.to_string().to_val()),
|
||||
("body".to_string(), body),
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
symbol_map: vec![].into_iter().collect(),
|
||||
prototype: Val::Void,
|
||||
}
|
||||
.to_val();
|
||||
|
||||
let mut vm = VirtualMachine::default();
|
||||
|
||||
let res = match vm.run(None, &mut instance, fn_, vec![req_val]) {
|
||||
Ok(res) => match res.to_json() {
|
||||
Some(json) => HttpResponse::Ok().json(json),
|
||||
None => HttpResponse::InternalServerError().body("Failed to serialize response"),
|
||||
},
|
||||
Err(err) => {
|
||||
println!("Uncaught exception: {}", err.pretty());
|
||||
HttpResponse::InternalServerError().body("Uncaught exception")
|
||||
}
|
||||
};
|
||||
|
||||
storage
|
||||
.set_head(storage_head_ptr(b"state"), &instance)
|
||||
.unwrap();
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
fn db_host(path: &str, args: &[String]) {
|
||||
if !args.is_empty() {
|
||||
// TODO
|
||||
exit_command_failed(
|
||||
args,
|
||||
Some("Not implemented: host arguments"),
|
||||
"vstc db help",
|
||||
);
|
||||
}
|
||||
|
||||
let path = path.to_owned();
|
||||
|
||||
// TODO: Multi-thread?
|
||||
let runtime = tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
runtime.block_on(async {
|
||||
HttpServer::new(move || {
|
||||
App::new()
|
||||
.app_data(web::Data::new(path.clone()))
|
||||
.default_service(web::route().to(handle_request))
|
||||
})
|
||||
.bind("127.0.0.1:8080")
|
||||
.unwrap()
|
||||
.run()
|
||||
.await
|
||||
.unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
fn db_run_inline(path: &String, source: &str) {
|
||||
let mut vm = VirtualMachine::default();
|
||||
|
||||
|
||||
135
vstc/src/db_host.rs
Normal file
135
vstc/src/db_host.rs
Normal file
@@ -0,0 +1,135 @@
|
||||
use crate::exit_command_failed::exit_command_failed;
|
||||
use actix_web::{dev, web, App, FromRequest, HttpRequest, HttpResponse, HttpServer, Responder};
|
||||
use storage::{storage_head_ptr, SledBackend, Storage, StorageReader};
|
||||
use valuescript_compiler::inline_valuescript;
|
||||
use valuescript_vm::{
|
||||
vs_object::VsObject,
|
||||
vs_value::{ToVal, Val},
|
||||
VirtualMachine,
|
||||
};
|
||||
|
||||
pub fn db_host(path: &str, args: &[String]) {
|
||||
if !args.is_empty() {
|
||||
// TODO
|
||||
exit_command_failed(
|
||||
args,
|
||||
Some("Not implemented: host arguments"),
|
||||
"vstc db help",
|
||||
);
|
||||
}
|
||||
|
||||
let path = path.to_owned();
|
||||
|
||||
// TODO: Multi-thread?
|
||||
let runtime = tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
runtime.block_on(async {
|
||||
HttpServer::new(move || {
|
||||
App::new()
|
||||
.app_data(web::Data::new(path.clone()))
|
||||
.default_service(web::route().to(handle_request))
|
||||
})
|
||||
.bind("127.0.0.1:8080")
|
||||
.unwrap()
|
||||
.run()
|
||||
.await
|
||||
.unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
async fn handle_request(
|
||||
req: HttpRequest,
|
||||
payload: web::Payload,
|
||||
data: web::Data<String>,
|
||||
) -> impl Responder {
|
||||
let path = req.path();
|
||||
let method = req.method();
|
||||
let mut storage = Storage::new(SledBackend::open(data.as_ref()).unwrap());
|
||||
|
||||
let body = match get_body(&req, payload.into_inner()).await {
|
||||
Ok(body) => body,
|
||||
Err(e) => return e.into(),
|
||||
};
|
||||
|
||||
let mut instance: Val = storage
|
||||
.get_head(storage_head_ptr(b"state"))
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
let fn_ = inline_valuescript(
|
||||
r#"
|
||||
export default function(req) {
|
||||
if ("handleRequest" in this) {
|
||||
return this.handleRequest(req);
|
||||
}
|
||||
|
||||
const handlerName = `${req.method} ${req.path}`;
|
||||
|
||||
if (!this[handlerName]) {
|
||||
throw new Error("No handler for request");
|
||||
}
|
||||
|
||||
if (req.method === "GET") {
|
||||
// Enforce GET as read-only
|
||||
const state = this;
|
||||
return state[handlerName](req.body);
|
||||
}
|
||||
|
||||
return this[handlerName](req.body);
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
||||
let req_val = VsObject {
|
||||
string_map: vec![
|
||||
("path".to_string(), path.to_val()),
|
||||
("method".to_string(), method.to_string().to_val()),
|
||||
("body".to_string(), body),
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
symbol_map: vec![].into_iter().collect(),
|
||||
prototype: Val::Void,
|
||||
}
|
||||
.to_val();
|
||||
|
||||
let mut vm = VirtualMachine::default();
|
||||
|
||||
let res = match vm.run(None, &mut instance, fn_, vec![req_val]) {
|
||||
Ok(res) => match res.to_json() {
|
||||
Some(json) => HttpResponse::Ok().json(json),
|
||||
None => HttpResponse::InternalServerError().body("Failed to serialize response"),
|
||||
},
|
||||
Err(err) => {
|
||||
println!("Uncaught exception: {}", err.pretty());
|
||||
HttpResponse::InternalServerError().body("Uncaught exception")
|
||||
}
|
||||
};
|
||||
|
||||
storage
|
||||
.set_head(storage_head_ptr(b"state"), &instance)
|
||||
.unwrap();
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
async fn get_body(req: &HttpRequest, mut payload: dev::Payload) -> Result<Val, actix_web::Error> {
|
||||
let payload = web::Payload::from_request(req, &mut payload).await?;
|
||||
|
||||
let body = payload
|
||||
.to_bytes_limited(1_024 * 1_024)
|
||||
.await
|
||||
.map_err(|_| actix_web::error::PayloadError::Overflow)??;
|
||||
|
||||
if body.is_empty() {
|
||||
Ok(Val::Undefined)
|
||||
} else {
|
||||
match serde_json::from_slice::<serde_json::Value>(&body) {
|
||||
Ok(json_value) => Ok(Val::from_json(&json_value)),
|
||||
Err(err) => Err(actix_web::error::ErrorBadRequest(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ mod compile_command;
|
||||
mod console_command;
|
||||
mod create_db;
|
||||
mod db_command;
|
||||
mod db_host;
|
||||
mod exit_command_failed;
|
||||
mod handle_diagnostics_cli;
|
||||
mod parse_command_line;
|
||||
|
||||
Reference in New Issue
Block a user