use std::path::PathBuf;
use buswatch_types::Snapshot;
#[cfg(feature = "otel")]
use std::sync::Arc;
#[cfg(feature = "otel")]
use crate::otel::{OtelConfig, OtelExporter};
#[derive(Debug)]
pub enum Output {
File(PathBuf),
Tcp(String),
#[cfg(feature = "tokio")]
Channel(tokio::sync::mpsc::Sender<Snapshot>),
#[cfg(feature = "otel")]
Otel(Arc<OtelExporter>),
}
impl Output {
pub fn file(path: impl Into<PathBuf>) -> Self {
Output::File(path.into())
}
pub fn tcp(addr: impl Into<String>) -> Self {
Output::Tcp(addr.into())
}
#[cfg(feature = "tokio")]
pub fn channel(buffer: usize) -> (Self, tokio::sync::mpsc::Receiver<Snapshot>) {
let (tx, rx) = tokio::sync::mpsc::channel(buffer);
(Output::Channel(tx), rx)
}
#[cfg(feature = "otel")]
pub fn otel(config: OtelConfig) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
let exporter = OtelExporter::new(&config)?;
Ok(Output::Otel(Arc::new(exporter)))
}
#[cfg(feature = "tokio")]
pub(crate) async fn emit(&self, snapshot: &Snapshot) -> std::io::Result<()> {
match self {
Output::File(path) => {
let json = serde_json::to_string_pretty(snapshot)?;
tokio::fs::write(path, json).await?;
}
Output::Tcp(addr) => {
use tokio::io::AsyncWriteExt;
use tokio::net::TcpStream;
if let Ok(mut stream) = TcpStream::connect(addr).await {
let json = serde_json::to_string(snapshot)?;
let _ = stream.write_all(json.as_bytes()).await;
let _ = stream.write_all(b"\n").await;
}
}
Output::Channel(tx) => {
let _ = tx.try_send(snapshot.clone());
}
#[cfg(feature = "otel")]
Output::Otel(exporter) => {
exporter.record(snapshot);
}
}
Ok(())
}
}