Add blueprint for JavaScript Web APIs
This commit is contained in:
parent
d17b658163
commit
0e8866b4e3
6 changed files with 389 additions and 0 deletions
57
lib/src/fnc/script/classes/blob.rs
Normal file
57
lib/src/fnc/script/classes/blob.rs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
#[js::bind(object, public)]
|
||||||
|
#[quickjs(bare)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
#[allow(clippy::module_inception)]
|
||||||
|
pub mod blob {
|
||||||
|
|
||||||
|
use js::Rest;
|
||||||
|
use js::Value;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
#[quickjs(class)]
|
||||||
|
#[quickjs(cloneable)]
|
||||||
|
pub struct Blob {
|
||||||
|
#[quickjs(hide)]
|
||||||
|
pub(crate) mime: String,
|
||||||
|
#[quickjs(hide)]
|
||||||
|
pub(crate) data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Blob {
|
||||||
|
// ------------------------------
|
||||||
|
// Constructor
|
||||||
|
// ------------------------------
|
||||||
|
|
||||||
|
#[quickjs(constructor)]
|
||||||
|
pub fn new(args: Rest<Value>) -> Self {
|
||||||
|
Self {
|
||||||
|
data: vec![],
|
||||||
|
mime: String::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// Instance properties
|
||||||
|
// ------------------------------
|
||||||
|
|
||||||
|
#[quickjs(get)]
|
||||||
|
pub fn size(&self) -> usize {
|
||||||
|
self.data.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[quickjs(get)]
|
||||||
|
pub fn r#type(&self) -> &str {
|
||||||
|
&self.mime
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// Instance methods
|
||||||
|
// ------------------------------
|
||||||
|
|
||||||
|
// Convert the object to a string
|
||||||
|
pub fn toString(&self) -> String {
|
||||||
|
String::from("[object Blob]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
126
lib/src/fnc/script/classes/headers.rs
Normal file
126
lib/src/fnc/script/classes/headers.rs
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
#[js::bind(object, public)]
|
||||||
|
#[quickjs(bare)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
#[allow(clippy::module_inception)]
|
||||||
|
pub mod headers {
|
||||||
|
|
||||||
|
use js::Rest;
|
||||||
|
use js::Value;
|
||||||
|
use reqwest::header::HeaderName;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
#[quickjs(class)]
|
||||||
|
#[quickjs(cloneable)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub struct Headers {
|
||||||
|
#[quickjs(hide)]
|
||||||
|
pub(crate) inner: HashMap<HeaderName, Vec<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Headers {
|
||||||
|
// ------------------------------
|
||||||
|
// Constructor
|
||||||
|
// ------------------------------
|
||||||
|
|
||||||
|
#[quickjs(constructor)]
|
||||||
|
pub fn new(args: Rest<Value>) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// Instance methods
|
||||||
|
// ------------------------------
|
||||||
|
|
||||||
|
// Convert the object to a string
|
||||||
|
pub fn toString(&self) -> String {
|
||||||
|
String::from("[object Header]")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds or appends a new value to a header
|
||||||
|
pub fn append(&mut self, key: String, val: String, args: Rest<Value>) -> js::Result<()> {
|
||||||
|
// Process and check the header name is valid
|
||||||
|
let key = HeaderName::from_str(&key).map_err(|e| throw!(e))?;
|
||||||
|
// Insert and overwrite the header entry
|
||||||
|
match self.inner.get_mut(&key) {
|
||||||
|
Some(v) => {
|
||||||
|
v.push(val);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
self.inner.insert(key, vec![val]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Everything ok
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deletes a header from the header set
|
||||||
|
pub fn delete(&mut self, key: String, args: Rest<Value>) -> js::Result<()> {
|
||||||
|
// Process and check the header name is valid
|
||||||
|
let key = HeaderName::from_str(&key).map_err(|e| throw!(e))?;
|
||||||
|
// Remove the header entry from the map
|
||||||
|
self.inner.remove(&key);
|
||||||
|
// Everything ok
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns all header entries in the header set
|
||||||
|
pub fn entries(&self, args: Rest<Value>) -> Vec<(String, String)> {
|
||||||
|
self.inner
|
||||||
|
.iter()
|
||||||
|
.map(|(k, v)| {
|
||||||
|
(
|
||||||
|
k.as_str().to_owned(),
|
||||||
|
v.iter().map(|v| v.as_str()).collect::<Vec<&str>>().join(","),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<(String, String)>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns all values of a header in the header set
|
||||||
|
pub fn get(&self, key: String, args: Rest<Value>) -> js::Result<Option<String>> {
|
||||||
|
// Process and check the header name is valid
|
||||||
|
let key = HeaderName::from_str(&key).map_err(|e| throw!(e))?;
|
||||||
|
// Convert the header values to strings
|
||||||
|
Ok(self
|
||||||
|
.inner
|
||||||
|
.get(&key)
|
||||||
|
.map(|v| v.iter().map(|v| v.as_str()).collect::<Vec<&str>>().join(",")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks to see if the header set contains a header
|
||||||
|
pub fn has(&self, key: String, args: Rest<Value>) -> js::Result<bool> {
|
||||||
|
// Process and check the header name is valid
|
||||||
|
let key = HeaderName::from_str(&key).map_err(|e| throw!(e))?;
|
||||||
|
// Check if the header entry exists
|
||||||
|
Ok(self.inner.contains_key(&key))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns all header keys contained in the header set
|
||||||
|
pub fn keys(&self, args: Rest<Value>) -> Vec<String> {
|
||||||
|
self.inner.keys().map(|v| v.as_str().to_owned()).collect::<Vec<String>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets a new value or adds a header to the header set
|
||||||
|
pub fn set(&mut self, key: String, val: String, args: Rest<Value>) -> js::Result<()> {
|
||||||
|
// Process and check the header name is valid
|
||||||
|
let key = HeaderName::from_str(&key).map_err(|e| throw!(e))?;
|
||||||
|
// Insert and overwrite the header entry
|
||||||
|
self.inner.insert(key, vec![val]);
|
||||||
|
// Everything ok
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns all header values contained in the header set
|
||||||
|
pub fn values(&self, args: Rest<Value>) -> Vec<String> {
|
||||||
|
self.inner
|
||||||
|
.values()
|
||||||
|
.map(|v| v.iter().map(|v| v.as_str()).collect::<Vec<&str>>().join(","))
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,7 @@
|
||||||
|
pub mod blob;
|
||||||
pub mod duration;
|
pub mod duration;
|
||||||
|
pub mod headers;
|
||||||
pub mod record;
|
pub mod record;
|
||||||
|
pub mod request;
|
||||||
|
pub mod response;
|
||||||
pub mod uuid;
|
pub mod uuid;
|
||||||
|
|
84
lib/src/fnc/script/classes/request.rs
Normal file
84
lib/src/fnc/script/classes/request.rs
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
#[js::bind(object, public)]
|
||||||
|
#[quickjs(bare)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
#[allow(clippy::module_inception)]
|
||||||
|
pub mod request {
|
||||||
|
|
||||||
|
use super::super::blob::blob::Blob;
|
||||||
|
use crate::sql::value::Value;
|
||||||
|
use js::Rest;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
#[quickjs(class)]
|
||||||
|
#[quickjs(cloneable)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub struct Request {
|
||||||
|
#[quickjs(hide)]
|
||||||
|
pub(crate) url: Option<String>,
|
||||||
|
pub(crate) credentials: Option<String>,
|
||||||
|
pub(crate) headers: Option<String>,
|
||||||
|
pub(crate) method: Option<String>,
|
||||||
|
pub(crate) mode: Option<String>,
|
||||||
|
pub(crate) referrer: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Request {
|
||||||
|
// ------------------------------
|
||||||
|
// Constructor
|
||||||
|
// ------------------------------
|
||||||
|
|
||||||
|
#[quickjs(constructor)]
|
||||||
|
pub fn new(args: Rest<Value>) -> Self {
|
||||||
|
Self {
|
||||||
|
url: None,
|
||||||
|
credentials: None,
|
||||||
|
headers: None,
|
||||||
|
method: None,
|
||||||
|
mode: None,
|
||||||
|
referrer: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// Instance properties
|
||||||
|
// ------------------------------
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// Instance methods
|
||||||
|
// ------------------------------
|
||||||
|
|
||||||
|
// Convert the object to a string
|
||||||
|
pub fn toString(&self) -> String {
|
||||||
|
String::from("[object Request]")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a copy of the request object
|
||||||
|
#[quickjs(rename = "clone")]
|
||||||
|
pub fn copy(&self, args: Rest<Value>) -> Request {
|
||||||
|
self.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a promise with the request body as a Blob
|
||||||
|
pub async fn blob(self, args: Rest<Value>) -> js::Result<Blob> {
|
||||||
|
Err(throw!("Not yet implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a promise with the request body as FormData
|
||||||
|
pub async fn formData(self, args: Rest<Value>) -> js::Result<Value> {
|
||||||
|
Err(throw!("Not yet implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a promise with the request body as JSON
|
||||||
|
pub async fn json(self, args: Rest<Value>) -> js::Result<Value> {
|
||||||
|
Err(throw!("Not yet implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a promise with the request body as text
|
||||||
|
pub async fn text(self, args: Rest<Value>) -> js::Result<Value> {
|
||||||
|
Err(throw!("Not yet implemented"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
98
lib/src/fnc/script/classes/response.rs
Normal file
98
lib/src/fnc/script/classes/response.rs
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
#[js::bind(object, public)]
|
||||||
|
#[quickjs(bare)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
#[allow(clippy::module_inception)]
|
||||||
|
pub mod response {
|
||||||
|
|
||||||
|
use super::super::blob::blob::Blob;
|
||||||
|
use crate::sql::value::Value;
|
||||||
|
use js::Rest;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
#[quickjs(class)]
|
||||||
|
#[quickjs(cloneable)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub struct Response {
|
||||||
|
#[quickjs(hide)]
|
||||||
|
pub(crate) url: Option<String>,
|
||||||
|
pub(crate) credentials: Option<String>,
|
||||||
|
pub(crate) headers: Option<String>,
|
||||||
|
pub(crate) method: Option<String>,
|
||||||
|
pub(crate) mode: Option<String>,
|
||||||
|
pub(crate) referrer: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Response {
|
||||||
|
// ------------------------------
|
||||||
|
// Constructor
|
||||||
|
// ------------------------------
|
||||||
|
|
||||||
|
#[quickjs(constructor)]
|
||||||
|
pub fn new(args: Rest<Value>) -> Self {
|
||||||
|
Self {
|
||||||
|
url: None,
|
||||||
|
credentials: None,
|
||||||
|
headers: None,
|
||||||
|
method: None,
|
||||||
|
mode: None,
|
||||||
|
referrer: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// Instance properties
|
||||||
|
// ------------------------------
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// Instance methods
|
||||||
|
// ------------------------------
|
||||||
|
|
||||||
|
// Convert the object to a string
|
||||||
|
pub fn toString(&self) -> String {
|
||||||
|
String::from("[object Response]")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a copy of the request object
|
||||||
|
#[quickjs(rename = "clone")]
|
||||||
|
pub fn copy(&self, args: Rest<Value>) -> Response {
|
||||||
|
self.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a promise with the response body as a Blob
|
||||||
|
pub async fn blob(self, args: Rest<Value>) -> js::Result<Blob> {
|
||||||
|
Err(throw!("Not yet implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a promise with the response body as FormData
|
||||||
|
pub async fn formData(self, args: Rest<Value>) -> js::Result<Value> {
|
||||||
|
Err(throw!("Not yet implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a promise with the response body as JSON
|
||||||
|
pub async fn json(self, args: Rest<Value>) -> js::Result<Value> {
|
||||||
|
Err(throw!("Not yet implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a promise with the response body as text
|
||||||
|
pub async fn text(self, args: Rest<Value>) -> js::Result<Value> {
|
||||||
|
Err(throw!("Not yet implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// Static methods
|
||||||
|
// ------------------------------
|
||||||
|
|
||||||
|
// Returns a new response representing a network error
|
||||||
|
pub fn error(args: Rest<Value>) -> js::Result<Response> {
|
||||||
|
Err(throw!("Not yet implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a new response with a different URL
|
||||||
|
pub fn redirect(args: Rest<Value>) -> js::Result<Response> {
|
||||||
|
Err(throw!("Not yet implemented"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,3 +20,23 @@ macro_rules! get_cfg {
|
||||||
let $i = || { $( if cfg!($i=$s) { return $s; } );+ "unknown"};
|
let $i = || { $( if cfg!($i=$s) { return $s; } );+ "unknown"};
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "scripting")]
|
||||||
|
macro_rules! throw {
|
||||||
|
($e:ident) => {
|
||||||
|
js::Error::Exception {
|
||||||
|
line: line!() as i32,
|
||||||
|
message: $e.to_string(),
|
||||||
|
file: file!().to_owned(),
|
||||||
|
stack: "".to_owned(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
($str:expr) => {
|
||||||
|
js::Error::Exception {
|
||||||
|
line: line!() as i32,
|
||||||
|
message: $str.to_owned(),
|
||||||
|
file: file!().to_owned(),
|
||||||
|
stack: "".to_owned(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue