use serde::{Deserialize, Serialize};
use ts_rs::TS;
pub mod yaml;
pub use streamkit_core::control::{ConnectionMode, NodeControlMessage};
pub use streamkit_core::{NodeDefinition, NodeState, NodeStats};
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, TS)]
#[ts(export)]
#[serde(rename_all = "lowercase")]
pub enum MessageType {
Request,
Response,
Event,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Message<T> {
#[serde(rename = "type")]
pub message_type: MessageType,
#[serde(skip_serializing_if = "Option::is_none")]
pub correlation_id: Option<String>,
pub payload: T,
}
#[derive(Serialize, Deserialize, Debug, TS)]
#[ts(export)]
#[serde(tag = "action")]
#[serde(rename_all = "lowercase")]
pub enum RequestPayload {
CreateSession {
#[serde(skip_serializing_if = "Option::is_none")]
name: Option<String>,
},
DestroySession {
session_id: String,
},
ListSessions,
ListNodes,
AddNode {
session_id: String,
node_id: String,
kind: String,
#[serde(skip_serializing_if = "Option::is_none")]
#[ts(type = "JsonValue")]
params: Option<serde_json::Value>,
},
RemoveNode {
session_id: String,
node_id: String,
},
Connect {
session_id: String,
from_node: String,
from_pin: String,
to_node: String,
to_pin: String,
#[serde(default)]
mode: ConnectionMode,
},
Disconnect {
session_id: String,
from_node: String,
from_pin: String,
to_node: String,
to_pin: String,
},
TuneNode {
session_id: String,
node_id: String,
message: NodeControlMessage,
},
TuneNodeAsync {
session_id: String,
node_id: String,
message: NodeControlMessage,
},
GetPipeline {
session_id: String,
},
ValidateBatch {
session_id: String,
operations: Vec<BatchOperation>,
},
ApplyBatch {
session_id: String,
operations: Vec<BatchOperation>,
},
GetPermissions,
}
#[derive(Serialize, Deserialize, Debug, Clone, TS)]
#[ts(export)]
#[serde(tag = "action")]
#[serde(rename_all = "lowercase")]
pub enum BatchOperation {
AddNode {
node_id: String,
kind: String,
#[serde(skip_serializing_if = "Option::is_none")]
#[ts(type = "JsonValue")]
params: Option<serde_json::Value>,
},
RemoveNode {
node_id: String,
},
Connect {
from_node: String,
from_pin: String,
to_node: String,
to_pin: String,
#[serde(default)]
mode: ConnectionMode,
},
Disconnect {
from_node: String,
from_pin: String,
to_node: String,
to_pin: String,
},
}
pub type Request = Message<RequestPayload>;
#[allow(clippy::struct_excessive_bools)]
#[derive(Serialize, Deserialize, Debug, Clone, TS)]
#[ts(export, export_to = "bindings/")]
pub struct PermissionsInfo {
pub create_sessions: bool,
pub destroy_sessions: bool,
pub list_sessions: bool,
pub modify_sessions: bool,
pub tune_nodes: bool,
pub load_plugins: bool,
pub delete_plugins: bool,
pub list_nodes: bool,
pub list_samples: bool,
pub read_samples: bool,
pub write_samples: bool,
pub delete_samples: bool,
pub access_all_sessions: bool,
pub upload_assets: bool,
pub delete_assets: bool,
}
#[derive(Serialize, Deserialize, Debug, TS)]
#[ts(export)]
#[serde(tag = "action")]
#[serde(rename_all = "lowercase")]
pub enum ResponsePayload {
SessionCreated {
session_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
name: Option<String>,
created_at: String,
},
SessionDestroyed {
session_id: String,
},
SessionsListed {
sessions: Vec<SessionInfo>,
},
NodesListed {
nodes: Vec<NodeDefinition>,
},
Pipeline {
pipeline: ApiPipeline,
},
ValidationResult {
errors: Vec<ValidationError>,
},
BatchApplied {
success: bool,
errors: Vec<String>,
},
Permissions {
role: String,
permissions: PermissionsInfo,
},
Success,
Error {
message: String,
},
}
#[derive(Serialize, Deserialize, Debug, Clone, TS)]
#[ts(export)]
pub struct ValidationError {
pub error_type: ValidationErrorType,
pub message: String,
pub node_id: Option<String>,
pub connection_id: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone, TS)]
#[ts(export)]
#[serde(rename_all = "lowercase")]
pub enum ValidationErrorType {
Error,
Warning,
}
#[derive(Serialize, Deserialize, Debug, Clone, TS)]
#[ts(export)]
pub struct SessionInfo {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
pub created_at: String,
}
pub type Response = Message<ResponsePayload>;
#[derive(Serialize, Deserialize, Debug, Clone, TS)]
#[ts(export)]
#[serde(tag = "event")]
#[serde(rename_all = "lowercase")]
pub enum EventPayload {
NodeStateChanged {
session_id: String,
node_id: String,
state: NodeState,
timestamp: String,
},
NodeStatsUpdated {
session_id: String,
node_id: String,
stats: NodeStats,
timestamp: String,
},
NodeParamsChanged {
session_id: String,
node_id: String,
#[ts(type = "JsonValue")]
params: serde_json::Value,
},
SessionCreated {
session_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
name: Option<String>,
created_at: String,
},
SessionDestroyed {
session_id: String,
},
NodeAdded {
session_id: String,
node_id: String,
kind: String,
#[ts(type = "JsonValue")]
params: Option<serde_json::Value>,
},
NodeRemoved {
session_id: String,
node_id: String,
},
ConnectionAdded {
session_id: String,
from_node: String,
from_pin: String,
to_node: String,
to_pin: String,
},
ConnectionRemoved {
session_id: String,
from_node: String,
from_pin: String,
to_node: String,
to_pin: String,
},
NodeTelemetry {
session_id: String,
node_id: String,
type_id: String,
#[ts(type = "JsonValue")]
data: serde_json::Value,
#[serde(skip_serializing_if = "Option::is_none")]
timestamp_us: Option<u64>,
timestamp: String,
},
}
pub type Event = Message<EventPayload>;
#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, Default, TS)]
#[ts(export)]
#[serde(rename_all = "lowercase")]
pub enum EngineMode {
#[serde(rename = "oneshot")]
OneShot,
#[default]
Dynamic,
}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, TS)]
#[ts(export)]
pub struct Connection {
pub from_node: String,
pub from_pin: String,
pub to_node: String,
pub to_pin: String,
#[serde(default, skip_serializing_if = "is_default_mode")]
pub mode: ConnectionMode,
}
#[allow(clippy::trivially_copy_pass_by_ref)] fn is_default_mode(mode: &ConnectionMode) -> bool {
*mode == ConnectionMode::Reliable
}
#[derive(Debug, Deserialize, Serialize, Clone, TS)]
#[ts(export)]
pub struct Node {
pub kind: String,
#[ts(type = "JsonValue")]
pub params: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub state: Option<NodeState>,
}
#[derive(Debug, Deserialize, Serialize, Default, Clone, TS)]
#[ts(export)]
pub struct Pipeline {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(default)]
pub mode: EngineMode,
#[ts(type = "Record<string, Node>")]
pub nodes: indexmap::IndexMap<String, Node>,
pub connections: Vec<Connection>,
}
pub type ApiConnection = Connection;
pub type ApiNode = Node;
pub type ApiPipeline = Pipeline;
#[derive(Serialize, Deserialize, Debug, Clone, TS)]
#[ts(export)]
pub struct SamplePipeline {
pub id: String,
pub name: String,
pub description: String,
pub yaml: String,
pub is_system: bool,
pub mode: String,
#[serde(default)]
pub is_fragment: bool,
}
#[derive(Serialize, Deserialize, Debug, Clone, TS)]
#[ts(export)]
pub struct SavePipelineRequest {
pub name: String,
pub description: String,
pub yaml: String,
#[serde(default)]
pub overwrite: bool,
#[serde(default)]
pub is_fragment: bool,
}
#[derive(Serialize, Deserialize, Debug, Clone, TS)]
#[ts(export)]
pub struct AudioAsset {
pub id: String,
pub name: String,
pub path: String,
pub format: String,
pub size_bytes: u64,
#[serde(skip_serializing_if = "Option::is_none")]
pub license: Option<String>,
pub is_system: bool,
}