use serde::Serialize;
use serde_json::Value;
#[derive(Clone, Debug, Serialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ProxyEvent {
Request(Box<RequestEvent>),
SessionStart(SessionStartEvent),
SessionEnd(SessionEndEvent),
Heartbeat(HeartbeatEvent),
SchemaVersionCreated(SchemaVersionCreatedEvent),
}
#[derive(Clone, Debug, Serialize)]
pub struct RequestEvent {
pub id: String,
pub ts: i64,
pub proxy: String,
pub session_id: Option<String>,
pub method: String,
pub path: String,
pub mcp_method: Option<String>,
pub tool: Option<String>,
pub status: u16,
pub latency_us: u64,
pub upstream_us: Option<u64>,
pub request_size: Option<u64>,
pub response_size: Option<u64>,
pub error_code: Option<String>,
pub error_msg: Option<String>,
pub client_name: Option<String>,
pub client_version: Option<String>,
pub note: String,
}
#[derive(Clone, Debug, Serialize)]
pub struct SessionStartEvent {
pub session_id: String,
pub proxy: String,
pub ts: i64,
pub client_name: Option<String>,
pub client_version: Option<String>,
pub client_platform: Option<String>,
}
#[derive(Clone, Debug, Serialize)]
pub struct SessionEndEvent {
pub session_id: String,
pub ts: i64,
}
#[derive(Clone, Debug, Serialize)]
pub struct HeartbeatEvent {
pub ts: i64,
pub proxy: String,
pub mcp_status: String,
pub tunnel_status: String,
pub widgets_status: String,
pub uptime_secs: u64,
pub request_count: u64,
}
#[derive(Clone, Debug, Serialize)]
pub struct SchemaVersionCreatedEvent {
pub ts: i64,
pub upstream_id: String,
pub upstream_url: String,
pub method: String,
pub version: u32,
pub version_id: String,
pub content_hash: String,
pub payload: Value,
}
pub trait EventSink: Send + Sync {
fn on_event(&self, event: &ProxyEvent);
fn on_batch(&self, events: &[ProxyEvent]) {
for event in events {
self.on_event(event);
}
}
fn flush(&self) {}
fn name(&self) -> &'static str;
}
pub struct NoopSink;
impl EventSink for NoopSink {
fn on_event(&self, _event: &ProxyEvent) {}
fn name(&self) -> &'static str {
"noop"
}
}