use serde::Serialize;
use super::cost::{RecordError, ServerMetadata, build_commit};
#[derive(Clone, Copy, Debug)]
pub(in crate::server) enum PublishOrigin<'a> {
Connection { id: u64 },
Host { name: &'a str },
Server { device: &'a str },
}
impl PublishOrigin<'_> {
pub(in crate::server) const fn is_server(&self) -> bool {
matches!(self, Self::Server { .. })
}
}
#[derive(Clone, Copy, Debug)]
pub(in crate::server) enum ServerEvent<'a> {
Lifecycle {
conversation: u64,
generation: u64,
transition: &'a str,
},
Pressure {
connection: u64,
response: &'a str,
},
Flush {
store: &'a str,
batch_rows: Option<u64>,
},
ConnectionOpened {
connection: u64,
},
ConnectionClosed {
connection: u64,
},
}
impl ServerEvent<'_> {
pub(in crate::server) fn encode(
&self,
metadata: &ServerMetadata,
server_time_ms: u64,
) -> Result<Vec<u8>, RecordError> {
let details = match *self {
Self::Lifecycle {
conversation,
generation,
transition,
} => {
if transition.trim().is_empty() {
return Err(RecordError::EmptyLifecycleTransition);
}
EventDetails {
conversation: Some(conversation),
generation: Some(generation),
transition: Some(transition),
..EventDetails::new("lifecycle")
}
}
Self::Pressure {
connection,
response,
} => {
if response.trim().is_empty() {
return Err(RecordError::EmptyPressureResponse);
}
EventDetails {
connection: Some(connection),
response: Some(response),
..EventDetails::new("pressure")
}
}
Self::Flush { store, batch_rows } => {
if store.trim().is_empty() {
return Err(RecordError::EmptyFlushStore);
}
EventDetails {
store: Some(store),
batch_rows,
..EventDetails::new("flush")
}
}
Self::ConnectionOpened { connection } => EventDetails {
connection: Some(connection),
..EventDetails::new("connection_open")
},
Self::ConnectionClosed { connection } => EventDetails {
connection: Some(connection),
..EventDetails::new("connection_close")
},
};
let record = EventRecord {
v: 1,
build_commit: build_commit(),
crate_version: env!("CARGO_PKG_VERSION"),
details,
device: metadata.device(),
publisher: metadata.publisher(),
server_incarnation: metadata.server_incarnation(),
server_time_ms,
};
Ok(serde_json::to_vec(&record)?)
}
}
#[derive(Serialize)]
struct EventRecord<'a> {
v: u8,
build_commit: &'static str,
crate_version: &'static str,
details: EventDetails<'a>,
device: &'a str,
publisher: &'a str,
server_incarnation: u64,
server_time_ms: u64,
}
#[derive(Serialize)]
struct EventDetails<'a> {
#[serde(skip_serializing_if = "Option::is_none")]
batch_rows: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
connection: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
conversation: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
generation: Option<u64>,
kind: &'static str,
#[serde(skip_serializing_if = "Option::is_none")]
store: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
response: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
transition: Option<&'a str>,
}
impl EventDetails<'_> {
const fn new(kind: &'static str) -> Self {
Self {
batch_rows: None,
store: None,
connection: None,
conversation: None,
generation: None,
kind,
response: None,
transition: None,
}
}
}