Constellation, Spacedust, Slingshot, UFOs: atproto crates and services for microcosm
at main 3.8 kB view raw
1use clap::{ArgAction, Parser}; 2use metrics_exporter_prometheus::{BuildError as PromBuildError, PrometheusBuilder}; 3use std::path::PathBuf; 4use tokio_util::sync::CancellationToken; 5use who_am_i::{Tokens, serve}; 6 7/// Aggregate links in the at-mosphere 8#[derive(Parser, Debug, Clone)] 9#[command(version, about, long_about = None)] 10struct Args { 11 /// secret key from which the cookie-signing key is derived 12 /// 13 /// must have at least 512 bits (64 bytes) of randomness 14 /// 15 /// eg: `cat /dev/urandom | head -c 64 | base64` 16 #[arg(long, env)] 17 app_secret: String, 18 /// path to at-oauth private key (PEM pk8 format) 19 /// 20 /// generate with: 21 /// 22 /// openssl ecparam -genkey -noout -name prime256v1 \ 23 /// | openssl pkcs8 -topk8 -nocrypt -out <PATH-TO-PRIV-KEY>.pem 24 #[arg(long, env)] 25 oauth_private_key: Option<PathBuf>, 26 /// path to jwt private key (PEM pk8 format) 27 /// 28 /// generate with: 29 /// 30 /// openssl ecparam -genkey -noout -name prime256v1 \ 31 /// | openssl pkcs8 -topk8 -nocrypt -out <PATH-TO-PRIV-KEY>.pem 32 #[arg(long)] 33 jwt_private_key: PathBuf, 34 /// this server's client-reachable base url, for oauth redirect + jwt check 35 /// 36 /// required unless running in localhost mode with --dev 37 #[arg(long, env)] 38 base_url: Option<String>, 39 /// host:port to bind to on startup 40 #[arg(long, env, default_value = "127.0.0.1:9997")] 41 bind: String, 42 /// Enable dev mode 43 /// 44 /// enables automatic template reloading, uses localhost oauth config, etc 45 #[arg(long, action)] 46 dev: bool, 47 /// Hosts who are allowed to one-click auth 48 /// 49 /// Pass this argument multiple times to allow multiple hosts 50 #[arg(long = "allow_host", short = 'a', action = ArgAction::Append)] 51 allowed_hosts: Vec<String>, 52} 53 54#[tokio::main(flavor = "current_thread")] 55async fn main() { 56 let shutdown = CancellationToken::new(); 57 58 let ctrlc_shutdown = shutdown.clone(); 59 ctrlc::set_handler(move || ctrlc_shutdown.cancel()).expect("failed to set ctrl-c handler"); 60 61 let args = Args::parse(); 62 63 // let bind = args.bind.to_socket_addrs().expect("--bind must be ToSocketAddrs"); 64 65 let base = args.base_url.unwrap_or_else(|| { 66 if args.dev { 67 format!("http://{}", args.bind) 68 } else { 69 panic!("not in --dev mode so --base-url is required") 70 } 71 }); 72 73 if !args.dev && args.oauth_private_key.is_none() { 74 panic!("--at-oauth-key is required except in --dev"); 75 } else if args.dev && args.oauth_private_key.is_some() { 76 eprintln!("warn: --at-oauth-key is ignored in dev (localhost config)"); 77 } 78 79 if args.allowed_hosts.is_empty() { 80 panic!("at least one --allowed-host host must be set"); 81 } 82 83 println!("starting with allowed_hosts hosts:"); 84 for host in &args.allowed_hosts { 85 println!(" - {host}"); 86 } 87 88 let tokens = Tokens::from_files(args.jwt_private_key).unwrap(); 89 90 if let Err(e) = install_metrics_server() { 91 eprintln!("failed to install metrics server: {e:?}"); 92 }; 93 94 serve( 95 shutdown, 96 args.app_secret, 97 args.oauth_private_key, 98 tokens, 99 base, 100 args.bind, 101 args.allowed_hosts, 102 args.dev, 103 ) 104 .await; 105} 106 107fn install_metrics_server() -> Result<(), PromBuildError> { 108 println!("installing metrics server..."); 109 let host = [0, 0, 0, 0]; 110 let port = 8765; 111 PrometheusBuilder::new() 112 .set_enable_unit_suffix(false) 113 .with_http_listener((host, port)) 114 .install()?; 115 println!( 116 "metrics server installed! listening on http://{}.{}.{}.{}:{port}", 117 host[0], host[1], host[2], host[3] 118 ); 119 Ok(()) 120}