1pub mod auth;
2pub mod service;
3pub mod store;
4
5use std::net::SocketAddr;
6
7use anyhow::{Context, Result};
8use tokio::net::TcpListener;
9use tokio_stream::wrappers::TcpListenerStream;
10use tonic::transport::Server;
11
12pub mod proto {
13 tonic::include_proto!("vyn");
14}
15
16#[derive(Debug, Clone, Default)]
17pub struct ServeConfig {
18 pub s3_bucket: Option<String>,
19 pub s3_region: Option<String>,
20 pub s3_endpoint: Option<String>,
21 pub s3_prefix: Option<String>,
22}
23
24pub async fn serve(port: u16, data_dir: String) -> Result<()> {
25 serve_with_config(port, data_dir, ServeConfig::default()).await
26}
27
28pub async fn serve_with_config(port: u16, data_dir: String, config: ServeConfig) -> Result<()> {
29 let backend_mode = if config.s3_bucket.is_some() && config.s3_region.is_some() {
30 "local + s3-mirror"
31 } else {
32 "local-only"
33 };
34
35 if config.s3_bucket.is_some() ^ config.s3_region.is_some() {
36 eprintln!(
37 "relay warning: partial S3 config detected (need both --s3-bucket and --s3-region); running local-only"
38 );
39 }
40
41 println!("relay startup: backend_mode={backend_mode}, data_dir={data_dir}, port={port}");
42
43 let store = store::FileStore::new(&data_dir, config)
44 .await
45 .context("failed to initialize relay store backend")?;
46 store.init().context("failed to initialize relay store")?;
47
48 let addr: SocketAddr = format!("0.0.0.0:{port}")
49 .parse()
50 .context("failed to parse relay bind address")?;
51
52 let service = service::RelayService::new(store);
53
54 Server::builder()
57 .add_service(proto::vyn_relay_server::VynRelayServer::new(service))
58 .serve(addr)
59 .await
60 .context("relay server terminated with an error")
61}
62
63pub async fn serve_with_listener(listener: TcpListener, data_dir: String) -> Result<()> {
66 let store = store::FileStore::new(&data_dir, ServeConfig::default())
67 .await
68 .context("failed to initialize relay store backend")?;
69 store.init().context("failed to initialize relay store")?;
70
71 let service = service::RelayService::new(store);
72
73 Server::builder()
74 .add_service(proto::vyn_relay_server::VynRelayServer::new(service))
75 .serve_with_incoming(TcpListenerStream::new(listener))
76 .await
77 .context("relay server terminated with an error")
78}