use serde_json::Value;
use crate::{FunctionAccess, FunctionManifest, HttpMethod, Visibility};
use abi_stable::std_types::RString;
pub fn manifest_from_json(entry: &Value) -> Result<FunctionManifest, String> {
let name = entry
.get("name")
.and_then(Value::as_str)
.filter(|n| !n.is_empty())
.ok_or_else(|| "a manifest entry has no `name`".to_string())?;
let string = |key: &str| -> RString {
entry
.get(key)
.and_then(Value::as_str)
.unwrap_or_default()
.into()
};
let schema = |key: &str| -> RString {
match entry.get(key) {
None | Some(Value::Null) => RString::new(),
Some(Value::String(s)) => s.as_str().into(),
Some(other) => other.to_string().into(),
}
};
let access_str = entry
.get("permission")
.or_else(|| entry.get("visibility"))
.and_then(Value::as_str)
.unwrap_or("private");
let access = FunctionAccess::parse(access_str).ok_or_else(|| {
format!(
"function `{name}` has unknown permission `{access_str}`; expected \
\"public\", \"authenticated\", \"member\", \"role:<name>\" or \"private\""
)
})?;
let (visibility, role) = match &access {
FunctionAccess::Public => (Visibility::Public, String::new()),
FunctionAccess::Authenticated | FunctionAccess::Member => {
(Visibility::Authenticated, String::new())
}
FunctionAccess::Role(role) => (Visibility::RoleGated, role.clone()),
FunctionAccess::Private => (Visibility::Private, String::new()),
};
let method_str = entry
.get("method")
.and_then(Value::as_str)
.unwrap_or("POST");
let method = match method_str.to_ascii_uppercase().as_str() {
"GET" => HttpMethod::Get,
"POST" => HttpMethod::Post,
"PUT" => HttpMethod::Put,
"DELETE" => HttpMethod::Delete,
other => {
return Err(format!(
"function `{name}` has unsupported method `{other}`; \
expected GET, POST, PUT or DELETE"
))
}
};
Ok(FunctionManifest {
name: name.into(),
version: match entry.get("version").and_then(Value::as_str) {
Some(v) => v.into(),
None => "0.0.0".into(),
},
description: string("description"),
visibility,
role: role.into(),
method,
permission: access.as_string().into(),
admin: schema("admin"),
config_schema: schema("config_schema"),
input_schema: schema("input_schema"),
output_schema: schema("output_schema"),
})
}