aboutsummaryrefslogblamecommitdiff
path: root/src/main.rs
blob: dcbd1871cc60c8f75ab931b2a06548e1541dd7ef (plain) (tree)
1
2
3
4
5
6
7
8
9


                    
                          
                         

                         

               
           
         
          
                 
                  
             


           



                                    


                                           
                                                       
          

                                











                                                                                    
                                                         




                                                




                                                                                            

                                        




                                              


                                         




                                               
                                        

                                                                 
                                                                                  
                                      








                                                                                    
                                                                                                                                                                       

                                        

 
                                                            
                 
                                               
                                                            
         
                                  
 





                                                     

                                   

                                 
                                                  







                                                                                              
                                                                                        
 




                                                    

                                                                                                





                                                           
                                   


                                               
                     

                                                                                             
          
 
                                                       
                                                          
                                                                    
                                               
                 
                           

         
 
                                  


                              
#[macro_use]
extern crate anyhow;

use futures::TryFutureExt;
use std::net::SocketAddr;
use structopt::StructOpt;

mod cert;
mod cert_store;
mod consul;
mod http;
mod https;
mod proxy_config;
mod reverse_proxy;
mod tls_util;

use log::*;

#[derive(StructOpt, Debug)]
#[structopt(name = "tricot")]
struct Opt {
	/// Address of consul server
	#[structopt(
		long = "consul-addr",
		env = "TRICOT_CONSUL_HOST",
		default_value = "http://127.0.0.1:8500"
	)]
	pub consul_addr: String,

	/// CA certificate for Consul server with TLS
	#[structopt(long = "consul-ca-cert", env = "TRICOT_CONSUL_CA_CERT")]
	pub consul_ca_cert: Option<String>,

	/// Client certificate for Consul server with TLS
	#[structopt(long = "consul-client-cert", env = "TRICOT_CONSUL_CLIENT_CERT")]
	pub consul_client_cert: Option<String>,

	/// Client key for Consul server with TLS
	#[structopt(long = "consul-client-key", env = "TRICOT_CONSUL_CLIENT_KEY")]
	pub consul_client_key: Option<String>,

	/// Prefix of Tricot's entries in Consul KV space
	#[structopt(
		long = "consul-kv-prefix",
		env = "TRICOT_CONSUL_KV_PREFIX",
		default_value = "tricot/"
	)]
	pub consul_kv_prefix: String,

	/// Node name
	#[structopt(long = "node-name", env = "TRICOT_NODE_NAME", default_value = "<none>")]
	pub node_name: String,

	/// Bind address for HTTP server
	#[structopt(
		long = "http-bind-addr",
		env = "TRICOT_HTTP_BIND_ADDR",
		default_value = "0.0.0.0:80"
	)]
	pub http_bind_addr: SocketAddr,

	/// Bind address for HTTPS server
	#[structopt(
		long = "https-bind-addr",
		env = "TRICOT_HTTPS_BIND_ADDR",
		default_value = "0.0.0.0:443"
	)]
	pub https_bind_addr: SocketAddr,

	/// E-mail address for Let's Encrypt certificate requests
	#[structopt(long = "letsencrypt-email", env = "TRICOT_LETSENCRYPT_EMAIL")]
	pub letsencrypt_email: String,

	/// Enable compression of responses
	#[structopt(long = "enable-compression", env = "TRICOT_ENABLE_COMPRESSION")]
	pub enable_compression: bool,

	/// Mime types for which to enable compression (comma-separated list)
	#[structopt(
		long = "compress-mime-types",
		env = "TRICOT_COMPRESS_MIME_TYPES",
		default_value = "text/html,text/plain,text/css,text/javascript,text/xml,application/javascript,application/json,application/xml,image/svg+xml,font/ttf"
	)]
	pub compress_mime_types: String,
}

#[tokio::main(flavor = "multi_thread", worker_threads = 10)]
async fn main() {
	if std::env::var("RUST_LOG").is_err() {
		std::env::set_var("RUST_LOG", "tricot=info")
	}
	pretty_env_logger::init();

	// Abort on panic (same behavior as in Go)
	std::panic::set_hook(Box::new(|panic_info| {
		error!("{}", panic_info.to_string());
		std::process::abort();
	}));

	let opt = Opt::from_args();

	info!("Starting Tricot");

	let consul_config = consul::ConsulConfig {
		addr: opt.consul_addr.clone(),
		ca_cert: opt.consul_ca_cert.clone(),
		client_cert: opt.consul_client_cert.clone(),
		client_key: opt.consul_client_key.clone(),
	};

	let consul = consul::Consul::new(consul_config, &opt.consul_kv_prefix, &opt.node_name)
		.expect("Error creating Consul client");
	let mut rx_proxy_config = proxy_config::spawn_proxy_config_task(consul.clone());

	let cert_store = cert_store::CertStore::new(
		consul.clone(),
		rx_proxy_config.clone(),
		opt.letsencrypt_email.clone(),
	);

	tokio::spawn(http::serve_http(opt.http_bind_addr, consul.clone()).map_err(exit_on_err));

	let https_config = https::HttpsConfig {
		bind_addr: opt.https_bind_addr,
		enable_compression: opt.enable_compression,
		compress_mime_types: opt
			.compress_mime_types
			.split(',')
			.map(|x| x.to_string())
			.collect(),
	};
	tokio::spawn(
		https::serve_https(https_config, cert_store.clone(), rx_proxy_config.clone())
			.map_err(exit_on_err),
	);

	while rx_proxy_config.changed().await.is_ok() {
		println!("---- PROXY CONFIGURATION ----");
		for ent in rx_proxy_config.borrow().entries.iter() {
			println!("   {}", ent);
		}
		println!();
	}
}

fn exit_on_err(e: anyhow::Error) {
	error!("{}", e);
	std::process::exit(1);
}