use bitflags::bitflags;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NodeAppInfo {
pub name: String,
pub version: String,
pub author: String,
pub description: String,
pub capabilities: Vec<String>,
}
impl NodeAppInfo {
pub fn capability_flags(&self) -> Capabilities {
let mut flags = Capabilities::empty();
for cap in &self.capabilities {
match cap.as_str() {
"http_handler" => flags |= Capabilities::HTTP_HANDLER,
"event_listener" => flags |= Capabilities::EVENT_LISTENER,
"filesystem_read" => flags |= Capabilities::FILESYSTEM_READ,
"filesystem_write" => flags |= Capabilities::FILESYSTEM_WRITE,
"network_outbound" => flags |= Capabilities::NETWORK_OUTBOUND,
"system_info" => flags |= Capabilities::SYSTEM_INFO,
"capability_provider" => flags |= Capabilities::CAPABILITY_PROVIDER,
_ => {
eprintln!("[node-app-api] Unknown capability '{}', ignoring", cap);
}
}
}
flags
}
}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct Capabilities: u32 {
const HTTP_HANDLER = 0b0000_0001; const EVENT_LISTENER = 0b0000_0010; const FILESYSTEM_READ = 0b0000_0100; const FILESYSTEM_WRITE = 0b0000_1000; const NETWORK_OUTBOUND = 0b0001_0000; const SYSTEM_INFO = 0b0010_0000; const CAPABILITY_PROVIDER = 0b0100_0000; }
}
impl Capabilities {
pub fn to_string_list(&self) -> Vec<String> {
let mut list = Vec::new();
if self.contains(Capabilities::HTTP_HANDLER) {
list.push("http_handler".to_string());
}
if self.contains(Capabilities::EVENT_LISTENER) {
list.push("event_listener".to_string());
}
if self.contains(Capabilities::FILESYSTEM_READ) {
list.push("filesystem_read".to_string());
}
if self.contains(Capabilities::FILESYSTEM_WRITE) {
list.push("filesystem_write".to_string());
}
if self.contains(Capabilities::NETWORK_OUTBOUND) {
list.push("network_outbound".to_string());
}
if self.contains(Capabilities::SYSTEM_INFO) {
list.push("system_info".to_string());
}
if self.contains(Capabilities::CAPABILITY_PROVIDER) {
list.push("capability_provider".to_string());
}
list
}
pub fn from_bits_safe(bits: u32) -> Self {
Capabilities::from_bits_truncate(bits)
}
pub fn from_string(s: &str) -> Option<Self> {
match s.to_lowercase().as_str() {
"http_handler" => Some(Capabilities::HTTP_HANDLER),
"event_listener" => Some(Capabilities::EVENT_LISTENER),
"filesystem_read" => Some(Capabilities::FILESYSTEM_READ),
"filesystem_write" => Some(Capabilities::FILESYSTEM_WRITE),
"network_outbound" => Some(Capabilities::NETWORK_OUTBOUND),
"system_info" => Some(Capabilities::SYSTEM_INFO),
"capability_provider" => Some(Capabilities::CAPABILITY_PROVIDER),
_ => None,
}
}
pub fn all_capability_names() -> &'static [&'static str] {
&[
"http_handler",
"event_listener",
"filesystem_read",
"filesystem_write",
"network_outbound",
"system_info",
"capability_provider",
]
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct CallerContext {
pub app_name: String,
pub granted_permissions: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AppRequest {
pub id: String,
pub method: String,
pub path: String,
pub headers: HashMap<String, String>,
pub body: serde_json::Value,
#[serde(default)]
pub caller: Option<CallerContext>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AppResponse {
pub status: u16,
pub headers: HashMap<String, String>,
pub body: serde_json::Value,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AppEvent {
pub name: String,
pub data: serde_json::Value,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct CapabilityRequest {
pub id: String,
pub capability: String,
pub payload: serde_json::Value,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub timeout_ms: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub trace_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub span_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub parent_span_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub trace_depth: Option<u8>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CapabilityResponse {
pub id: String,
pub success: bool,
pub payload: serde_json::Value,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProvidedCapability {
pub name: String,
pub description: String,
#[serde(default)]
pub request_schema: Option<serde_json::Value>,
#[serde(default)]
pub response_schema: Option<serde_json::Value>,
#[serde(default = "default_capability_priority")]
pub priority: i32,
#[serde(default)]
pub examples: Vec<CapabilityExample>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CapabilityExample {
pub label: String,
pub request: serde_json::Value,
}
fn default_capability_priority() -> i32 {
100
}