use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IpcMessage {
pub id: String,
pub payload: IpcPayload,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum IpcPayload {
Request(IpcRequest),
Response(IpcResponse),
Event(IpcEvent),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IpcRequest {
pub method: String,
pub params: serde_json::Value,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IpcResponse {
pub success: bool,
pub result: Option<serde_json::Value>,
pub error: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IpcEvent {
pub event_type: String,
pub data: serde_json::Value,
}
impl IpcMessage {
#[must_use]
pub fn request(method: impl Into<String>, params: serde_json::Value) -> Self {
Self {
id: uuid_v4(),
payload: IpcPayload::Request(IpcRequest {
method: method.into(),
params,
}),
}
}
#[must_use]
pub fn success(id: impl Into<String>, result: serde_json::Value) -> Self {
Self {
id: id.into(),
payload: IpcPayload::Response(IpcResponse {
success: true,
result: Some(result),
error: None,
}),
}
}
#[must_use]
pub fn error(id: impl Into<String>, error: impl Into<String>) -> Self {
Self {
id: id.into(),
payload: IpcPayload::Response(IpcResponse {
success: false,
result: None,
error: Some(error.into()),
}),
}
}
#[must_use]
pub fn event(event_type: impl Into<String>, data: serde_json::Value) -> Self {
Self {
id: uuid_v4(),
payload: IpcPayload::Event(IpcEvent {
event_type: event_type.into(),
data,
}),
}
}
}
fn uuid_v4() -> String {
let bytes: [u8; 16] = rand::random();
format!(
"{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
bytes[0],
bytes[1],
bytes[2],
bytes[3],
bytes[4],
bytes[5],
(bytes[6] & 0x0f) | 0x40,
bytes[7],
(bytes[8] & 0x3f) | 0x80,
bytes[9],
bytes[10],
bytes[11],
bytes[12],
bytes[13],
bytes[14],
bytes[15]
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_request_message() {
let msg = IpcMessage::request("test.method", serde_json::json!({"key": "value"}));
assert!(!msg.id.is_empty());
if let IpcPayload::Request(req) = msg.payload {
assert_eq!(req.method, "test.method");
} else {
panic!("Expected request payload");
}
}
#[test]
fn test_success_response() {
let msg = IpcMessage::success("123", serde_json::json!({"result": true}));
if let IpcPayload::Response(resp) = msg.payload {
assert!(resp.success);
assert!(resp.result.is_some());
} else {
panic!("Expected response payload");
}
}
}