mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 04:01:58 +00:00
feat: fetch effect (#1605)
* feat: fetch effect * fix: Make not available in sandbox * chore: Update to use text(), and to use headers * chore: use the postman echo for testing * chore: add json * chore: Testing the json * chore: Make the json lazy
This commit is contained in:
@@ -10,6 +10,7 @@ dashmap = "5.1.0"
|
||||
deno_core = "=0.136.0"
|
||||
deno_ast = {version="=0.15.0", features = ["transpiling"]}
|
||||
dprint-swc-ext = "=0.1.1"
|
||||
reqwest = { version = "0.11.4" }
|
||||
swc_atoms = "=0.2.11"
|
||||
swc_common = "=0.18.7"
|
||||
swc_config = "=0.1.1"
|
||||
|
||||
@@ -51,6 +51,20 @@ const warn = (x) => Deno.core.opSync("log_warn", x);
|
||||
const error = (x) => Deno.core.opSync("log_error", x);
|
||||
const debug = (x) => Deno.core.opSync("log_debug", x);
|
||||
const info = (x) => Deno.core.opSync("log_info", x);
|
||||
const fetch = async (url, options = null) => {
|
||||
const {body, ...response} = await Deno.core.opAsync("fetch", url, options);
|
||||
const textValue = Promise.resolve(body)
|
||||
return {
|
||||
...response,
|
||||
text() {
|
||||
return textValue
|
||||
},
|
||||
json() {
|
||||
return textValue.then(x => JSON.parse(x))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const currentFunction = Deno.core.opSync("current_function");
|
||||
const input = Deno.core.opSync("get_input");
|
||||
@@ -66,6 +80,7 @@ const effects = {
|
||||
trace,
|
||||
info,
|
||||
isSandboxed,
|
||||
fetch,
|
||||
removeFile,
|
||||
createDir,
|
||||
removeDir,
|
||||
|
||||
@@ -252,6 +252,7 @@ impl JsExecutionEnvironment {
|
||||
}
|
||||
fn declarations() -> Vec<OpDecl> {
|
||||
vec![
|
||||
fns::fetch::decl(),
|
||||
fns::read_file::decl(),
|
||||
fns::metadata::decl(),
|
||||
fns::write_file::decl(),
|
||||
@@ -330,11 +331,11 @@ impl JsExecutionEnvironment {
|
||||
|
||||
/// Note: Make sure that we have the assumption that all these methods are callable at any time, and all call restrictions should be in rust
|
||||
mod fns {
|
||||
use std::cell::RefCell;
|
||||
use std::convert::TryFrom;
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::rc::Rc;
|
||||
use std::{cell::RefCell, collections::BTreeMap};
|
||||
|
||||
use deno_core::anyhow::{anyhow, bail};
|
||||
use deno_core::error::AnyError;
|
||||
@@ -345,6 +346,75 @@ mod fns {
|
||||
use super::{AnswerState, JsContext};
|
||||
use crate::{system_time_as_unix_ms, MetadataJs};
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Default)]
|
||||
struct FetchOptions {
|
||||
method: Option<String>,
|
||||
headers: Option<BTreeMap<String, String>>,
|
||||
body: Option<String>,
|
||||
}
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Default)]
|
||||
struct FetchResponse {
|
||||
method: String,
|
||||
ok: bool,
|
||||
status: u32,
|
||||
headers: BTreeMap<String, String>,
|
||||
body: Option<String>,
|
||||
}
|
||||
#[op]
|
||||
async fn fetch(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
url: url::Url,
|
||||
options: Option<FetchOptions>,
|
||||
) -> Result<FetchResponse, AnyError> {
|
||||
let state = state.borrow();
|
||||
let ctx: &JsContext = state.borrow();
|
||||
|
||||
if ctx.sandboxed {
|
||||
bail!("Will not run fetch in sandboxed mode");
|
||||
}
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let options = options.unwrap_or_default();
|
||||
let method = options
|
||||
.method
|
||||
.unwrap_or_else(|| "GET".to_string())
|
||||
.to_uppercase();
|
||||
let mut request_builder = match &*method {
|
||||
"GET" => client.get(url),
|
||||
"POST" => client.post(url),
|
||||
"PUT" => client.put(url),
|
||||
"DELETE" => client.delete(url),
|
||||
"HEAD" => client.head(url),
|
||||
"PATCH" => client.patch(url),
|
||||
x => bail!("Unsupported method: {}", x),
|
||||
};
|
||||
if let Some(headers) = options.headers {
|
||||
for (key, value) in headers {
|
||||
request_builder = request_builder.header(key, value);
|
||||
}
|
||||
}
|
||||
if let Some(body) = options.body {
|
||||
request_builder = request_builder.body(body);
|
||||
}
|
||||
let response = request_builder.send().await?;
|
||||
|
||||
let fetch_response = FetchResponse {
|
||||
method,
|
||||
ok: response.status().is_success(),
|
||||
status: response.status().as_u16() as u32,
|
||||
headers: response
|
||||
.headers()
|
||||
.iter()
|
||||
.filter_map(|(head, value)| {
|
||||
Some((format!("{}", head), value.to_str().ok()?.to_string()))
|
||||
})
|
||||
.collect(),
|
||||
body: response.text().await.ok(),
|
||||
};
|
||||
|
||||
return Ok(fetch_response);
|
||||
}
|
||||
|
||||
#[op]
|
||||
async fn read_file(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
|
||||
Reference in New Issue
Block a user