use clap::Parser;
use mimalloc::MiMalloc;
use nar_bridge::AppState;
use std::num::NonZeroUsize;
use tower::ServiceBuilder;
use tower_http::trace::{DefaultMakeSpan, TraceLayer};
use tracing::info;
use tvix_store::utils::ServiceUrlsGrpc;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
/// Expose the Nix HTTP Binary Cache protocol for a tvix-store.
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Cli {
#[clap(flatten)]
service_addrs: ServiceUrlsGrpc,
/// The priority to announce at the `nix-cache-info` endpoint.
/// A lower number means it's *more preferred.
#[arg(long, env, default_value_t = 39)]
priority: u64,
/// The address to listen on.
#[clap(flatten)]
listen_args: tokio_listener::ListenerAddressLFlag,
/// The capacity of the lookup table from NarHash to [Node].
/// Should be bigger than the number of concurrent NAR uploads.
#[arg(long, env, default_value_t = NonZeroUsize::new(1000).unwrap())]
root_nodes_cache_capacity: NonZeroUsize,
#[cfg(feature = "otlp")]
/// Whether to configure OTLP. Set --otlp=false to disable.
#[arg(long, default_missing_value = "true", default_value = "true", num_args(0..=1), require_equals(true), action(clap::ArgAction::Set))]
otlp: bool,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let cli = Cli::parse();
let _tracing_handle = {
#[allow(unused_mut)]
let mut builder = tvix_tracing::TracingBuilder::default();
#[cfg(feature = "otlp")]
{
if cli.otlp {
builder = builder.enable_otlp("tvix.store");
}
}
builder.build()?
};
// initialize stores
let (blob_service, directory_service, path_info_service, _nar_calculation_service) =
tvix_store::utils::construct_services(cli.service_addrs).await?;
let state = AppState::new(
blob_service,
directory_service,
path_info_service,
cli.root_nodes_cache_capacity,
);
let app = nar_bridge::gen_router(cli.priority)
.layer(
ServiceBuilder::new()
.layer(
TraceLayer::new_for_http().make_span_with(
DefaultMakeSpan::new()
.level(tracing::Level::INFO)
.include_headers(true),
),
)
.map_request(tvix_tracing::propagate::axum::accept_trace),
)
.with_state(state);
let listen_address = &cli.listen_args.listen_address.unwrap_or_else(|| {
"[::]:9000"
.parse()
.expect("invalid fallback listen address")
});
let listener = tokio_listener::Listener::bind(
listen_address,
&Default::default(),
&cli.listen_args.listener_options,
)
.await?;
info!(listen_address=%listen_address, "starting daemon");
tokio_listener::axum07::serve(
listener,
app.into_make_service_with_connect_info::<tokio_listener::SomeSocketAddrClonable>(),
)
.await?;
Ok(())
}