pub mod archive;
pub mod auth;
mod service;
use std::future::Future;
use std::path::PathBuf;
use std::sync::Arc;
use anyhow::{Context as _, Result};
use telelog_proto::LogServiceServer;
use telelog_sources::Sources;
use tokio::net::TcpListener;
use tokio_stream::wrappers::TcpListenerStream;
use tonic::transport::{Identity, Server, ServerTlsConfig};
pub struct TlsFiles {
pub cert: PathBuf,
pub key: PathBuf,
}
pub struct Config {
pub token: Option<String>,
pub tls: Option<TlsFiles>,
pub archive: Option<Arc<archive::Archive>>,
}
pub async fn serve(
listener: TcpListener,
config: Config,
sources: Sources,
shutdown: impl Future<Output = ()>,
) -> Result<()> {
let _ = rustls::crypto::ring::default_provider().install_default();
let mut builder = Server::builder();
if let Some(tls) = &config.tls {
let cert = std::fs::read(&tls.cert).with_context(|| format!("reading {}", tls.cert.display()))?;
let key = std::fs::read(&tls.key).with_context(|| format!("reading {}", tls.key.display()))?;
builder = builder
.tls_config(ServerTlsConfig::new().identity(Identity::from_pem(cert, key)))
.context("configuring TLS")?;
}
let background: Vec<_> = match &config.archive {
Some(archive) => vec![
tokio::spawn(archive::ingest::run(archive.clone(), sources.clone())),
tokio::spawn(archive::ingest::sweep_forever(archive.clone())),
],
None => Vec::new(),
};
let service = LogServiceServer::with_interceptor(
service::Logs::new(sources, config.archive.clone()),
auth::TokenAuth::new(config.token),
);
builder
.add_service(service)
.serve_with_incoming_shutdown(TcpListenerStream::new(listener), shutdown)
.await?;
for task in background {
task.abort();
}
Ok(())
}