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 headers;
|
||||
pub mod record;
|
||||
pub mod request;
|
||||
pub mod response;
|
||||
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"};
|
||||
)
|
||||
}
|
||||
|
||||
#[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