use std::fmt;
use std::ptr::null_mut;
use crate::api::status::Status;
use crate::api::types::Bytes;
const LOG_FUNCTION_NAME: &str = "flex_log";
const CREATE_SERVICE_FUNCTION_NAME: &str = "flex_create_service";
const GET_METADATA_FUNCTION_NAME: &str = "flex_get_policy_metadata";
const GET_CONFIGURATION_FUNCTION_NAME: &str = "flex_get_policy_configuration";
const GET_ENV_FUNCTION_NAME: &str = "flex_get_env";
#[cfg(feature = "experimental_enable_stop_iteration")]
const ENABLE_STOP_ITERATION_FUNCTION_NAME: &str = "flex_enable_stop_iteration";
#[cfg(target_arch = "wasm32")]
extern "C" {
fn proxy_call_foreign_function(
name_data: *const u8,
name_size: usize,
args_data: *const u8,
args_size: usize,
return_data: *mut *mut u8,
return_size: *mut usize,
) -> Status;
}
#[cfg(not(target_arch = "wasm32"))]
fn proxy_call_foreign_function(
_name_data: *const u8,
_name_size: usize,
_args_data: *const u8,
_args_size: usize,
_return_data: *mut *mut u8,
_return_size: *mut usize,
) -> Status {
unimplemented!("Not implemented for current target")
}
fn raw_flex_call(name: &str, args: &[&str]) -> Result<Option<Bytes>, Status> {
let mut return_data: *mut u8 = null_mut();
let mut return_size: usize = 0;
let arg = to_json_array(args)?;
unsafe {
match proxy_call_foreign_function(
name.as_ptr(),
name.len(),
arg.as_ptr(),
arg.len(),
&mut return_data,
&mut return_size,
) {
Status::Ok => Ok((!return_data.is_null())
.then(|| Bytes::from_raw_parts(return_data, return_size, return_size))),
Status::NotFound => Ok(None),
status => Err(status),
}
}
}
fn to_json_array(args: &[&str]) -> Result<String, Status> {
serde_json::to_string(args).map_err(|_| Status::ParseFailure)
}
#[derive(Debug)]
pub enum FlexLogLevel {
Trace,
Debug,
Info,
Warn,
Error,
}
impl fmt::Display for FlexLogLevel {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl FlexLogLevel {
pub fn as_str(&self) -> &'static str {
match self {
FlexLogLevel::Trace => "trace",
FlexLogLevel::Debug => "debug",
FlexLogLevel::Info => "info",
FlexLogLevel::Warn => "warn",
FlexLogLevel::Error => "error",
}
}
}
pub fn log(level: FlexLogLevel, msg: &str) {
raw_flex_call(LOG_FUNCTION_NAME, &[level.as_str(), msg]).unwrap_or_default();
}
pub fn service_create(name: &str, ns: &str, uri: &str) -> Result<(), Status> {
raw_flex_call(CREATE_SERVICE_FUNCTION_NAME, &[name, ns, uri]).map(|_| ())
}
#[cfg(feature = "experimental_enable_stop_iteration")]
pub fn enable_stop_iteration() -> Result<(), Status> {
raw_flex_call(ENABLE_STOP_ITERATION_FUNCTION_NAME, &[]).map(|_| ())
}
#[allow(dead_code)]
pub fn get_env(name: &str) -> Option<String> {
match raw_flex_call(GET_ENV_FUNCTION_NAME, &[name]) {
Ok(Some(v)) => String::from_utf8(v).ok(),
Ok(None) | Err(_) => None,
}
}
pub fn get_configuration() -> Result<Option<Bytes>, Status> {
raw_flex_call(GET_CONFIGURATION_FUNCTION_NAME, &[])
}
pub fn get_metadata() -> Result<Option<Bytes>, Status> {
raw_flex_call(GET_METADATA_FUNCTION_NAME, &[])
}