//! Mensajes del protocolo de handshake. //! //! Todos los mensajes que cruzan el wire son variantes de [`Frame`]. use brahman_broker::MatchStrategy; use brahman_card::{TypeRef, WireCard, WitInterface}; use serde::{Deserialize, Serialize}; use ulid::Ulid; /// Identificador de sesión emitido por el servidor en `HelloAck`. pub type SessionId = Ulid; /// Saludo inicial del módulo. Lleva la Card en forma `WireCard` /// (postcard-friendly: sin extensiones JSON arbitrarias). El servidor /// la convierte a `Card` para uso interno. Opcionalmente, una /// `WitInterface` ya extraída — si está presente, el módulo es /// "consciente" y el server lo registra como `ResolvedCard::from_conscious`. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Hello { /// Versión del schema de Card que el cliente sigue. pub schema_version: u16, /// Versión del protocolo handshake del cliente. pub protocol_version: String, /// Tarjeta de Presentación, proyectada al wire. pub card: WireCard, /// Interfaz WIT extraída por el cliente (típicamente con /// `brahman-card-wit`). `None` si el módulo es agnóstico. #[serde(default)] pub wit: Option, } /// Respuesta del servidor a un `Hello` aceptado. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct HelloAck { /// Versión del crate del servidor. pub server_version: String, /// Versión del protocolo soportada por el servidor. pub protocol_version: String, /// Identificador de sesión asignado. pub session: SessionId, /// `true` si el Init está vinculado al servidor; `false` si el servidor /// corre standalone (modo degradado). pub init_attached: bool, } /// Latido del cliente. El servidor responde con [`Pong`] llevando su reloj. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Ping { pub session: SessionId, } /// Respuesta a un `Ping` con timestamp del servidor (ms desde UNIX_EPOCH). #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Pong { pub timestamp_ms: u64, } /// Cierre cooperativo de la sesión por parte del cliente. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Farewell { pub session: SessionId, } /// Errores del protocolo emitidos por el servidor. #[derive(Debug, Clone, Serialize, Deserialize, thiserror::Error)] pub enum HandshakeError { #[error("protocolo incompatible: {0}")] ProtocolMismatch(String), #[error("card inválida: {0}")] InvalidCard(String), #[error("schema de card incompatible: cliente={client}, servidor={server}")] SchemaMismatch { client: u16, server: u16 }, #[error("sin autorización: {0}")] Unauthorized(String), #[error("capacidad requerida no satisfecha: {0}")] CapabilityUnmet(String), #[error("rechazado: {0}")] Rejected(String), #[error("error interno: {0}")] Internal(String), } /// Notificación push del server al consumer: un match disponible o perdido. /// /// El server emite `Available` cuando un productor empieza a satisfacer un /// `flow.input` del consumer (ya sea porque el productor acaba de /// registrarse, o porque cambió el match anterior). Emite `Lost` cuando /// el productor previo dejó de satisfacer el input (desregistro o /// cambio de match). #[derive(Debug, Clone, Serialize, Deserialize)] pub struct MatchEvent { pub kind: MatchEventKind, /// Nombre del input del consumer al que aplica el evento. pub consumer_flow: String, /// Sesión y label del productor (en `Lost` puede ser nil/vacío). pub producer_session: SessionId, pub producer_label: String, pub producer_flow: String, /// Tipo del flujo matcheado. pub ty: TypeRef, /// Estrategia que ganó (relevante en `Available`). pub via: MatchStrategy, /// `true` si fue resuelto por `pin_to`. pub pinned: bool, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] pub enum MatchEventKind { Available, Lost, } /// Frame único de wire — discriminada por variante. Cada conexión es un /// stream de frames. /// /// Direcciones: /// - Cliente → Server: `Hello`, `Ping`, `Farewell`. /// - Server → Cliente: `HelloAck`, `Pong`, `Error`, `MatchEvent`. #[derive(Debug, Clone, Serialize, Deserialize)] pub enum Frame { Hello(Hello), HelloAck(HelloAck), Ping(Ping), Pong(Pong), Farewell(Farewell), Error(HandshakeError), MatchEvent(MatchEvent), }