use std::time::{Duration, SystemTime};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Input {
GetInput,
Log(Level),
SendResponse(String),
Random(Types),
Sleep(std::time::Duration),
HTTPRequest(HttpRequest),
GetSecret(String),
TimeNow,
RecvMessage(Option<Duration>, Vec<String>),
StartWorkflow(String, String),
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Output {
Unit,
Value(Types),
String(String),
ResponseSent(bool),
HTTPResponse(Result<HttpResponse, HttpError>),
Time(SystemTime),
Message(String, String),
Timeout,
Secret(Option<String>),
}
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Types {
Bool(bool),
I32(i32),
I64(i64),
F32(f32),
F64(f64),
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Level {
Info(String),
Warn(String),
Error(String),
Debug(String),
Trace(String),
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Error {
NoAllocExport = -1,
NoMemoryExport = -2,
AllocCallFailed = -3,
InputSerializationFailed = -4,
InputDeserializationFailed = -5,
OutputSerializationFailed = -6,
OutputWriteFailed = -7,
OutputDeserializationFailed = -8,
}
impl Error {
pub fn from_code(value: i32) -> Self {
match value {
-1 => Error::NoAllocExport,
-2 => Error::NoMemoryExport,
-3 => Error::AllocCallFailed,
-4 => Error::InputSerializationFailed,
-5 => Error::InputDeserializationFailed,
-6 => Error::OutputSerializationFailed,
-7 => Error::OutputWriteFailed,
-8 => Error::OutputDeserializationFailed,
_ => unreachable!("unknown error code"),
}
}
pub fn code(&self) -> i32 {
*self as i32
}
}
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct HttpConfig {
pub idempotent: bool,
pub timeout: std::time::Duration,
pub response_body_limit: u64,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct HttpRequest {
pub config: HttpConfig,
pub method: String,
pub url: String,
pub headers: Vec<(String, String)>,
pub body: Vec<u8>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct HttpResponse {
pub status_code: u16,
pub url: String,
pub headers: Vec<(String, String)>,
pub body: Vec<u8>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum HttpError {
Status(u16, HttpResponse),
Transport(HttpTransportError),
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct HttpTransportError {
pub kind: HttpErrorKind,
pub message: Option<String>,
pub url: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum HttpErrorKind {
InvalidUrl,
UnknownScheme,
Dns,
ConnectionFailed,
TooManyRedirects,
BadStatus,
BadHeader,
RequestInterrupted,
Io,
StatusCode,
}
#[export_name = "wasabi::alloc"]
pub fn alloc(capacity: usize) -> *const u8 {
let allocation = Vec::with_capacity(capacity);
let ptr = allocation.as_ptr();
std::mem::forget(allocation);
ptr
}
#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
mod abi {
#[link(wasm_import_module = "wasabi")]
extern "C" {
pub fn submit(in_ptr: *const u8, in_len: usize, out_ptr: *mut *mut u8, out_len: *mut usize) -> i32;
}
}
#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
pub fn submit(input: &Input) -> Result<Output, Error> {
let input = match serde_json::to_string(input) {
Ok(input) => input,
Err(_) => return Err(Error::InputSerializationFailed),
};
let mut out_ptr: *mut u8 = std::ptr::null_mut();
let mut out_len: usize = 0;
let output = unsafe {
match abi::submit(input.as_ptr(), input.len(), &mut out_ptr as *mut *mut u8, &mut out_len) {
0 => (), error_code => return Err(Error::from_code(error_code)),
};
Vec::from_raw_parts(out_ptr, out_len, out_len)
};
match serde_json::from_slice(&output) {
Ok(output) => Ok(output),
Err(_) => Err(Error::OutputDeserializationFailed),
}
}
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
pub fn submit(_input: &Input) -> Result<Output, Error> {
unreachable!("`submit` can only be used inside the flawless runtime")
}