♻️ refactor: clean up ptth_server
- Found I was passing the file server root twice - Removed handlebars from the public API. The templates are fixed when ptth_server ships, so I don't think users of the lib should care what handlebars is. - Making other stuff private where possiblemain
							parent
							
								
									86af3194e5
								
							
						
					
					
						commit
						ae33337156
					
				|  | @ -51,14 +51,8 @@ async fn handle_all (req: Request <Body>, state: Arc <State>) | |||
| 	
 | ||||
| 	let ptth_req = RequestParts::from_hyper (parts.method, path_and_query, parts.headers)?; | ||||
| 	
 | ||||
| 	let default_root = PathBuf::from ("./"); | ||||
| 	let file_server_root: &std::path::Path = state.config.file_server_root | ||||
| 	.as_ref () | ||||
| 	.unwrap_or (&default_root); | ||||
| 	
 | ||||
| 	let ptth_resp = file_server::serve_all ( | ||||
| 		&state, | ||||
| 		file_server_root, | ||||
| 		ptth_req.method, 
 | ||||
| 		&ptth_req.uri, 
 | ||||
| 		&ptth_req.headers | ||||
|  | @ -94,12 +88,6 @@ async fn main () -> anyhow::Result <()> { | |||
| 	
 | ||||
| 	let addr = SocketAddr::from(([0, 0, 0, 0], 4000)); | ||||
| 	
 | ||||
| 	let handlebars = file_server::load_templates (&PathBuf::new ())?; | ||||
| 	
 | ||||
| 	let metrics_startup = metrics::Startup::new ( 
 | ||||
| 		config_file.name.unwrap_or_else (|| "PTTH File Server".to_string ()) | ||||
| 	); | ||||
| 	
 | ||||
| 	let metrics_interval = Arc::new (ArcSwap::default ()); | ||||
| 	
 | ||||
| 	let interval_writer = Arc::clone (&metrics_interval); | ||||
|  | @ -107,15 +95,13 @@ async fn main () -> anyhow::Result <()> { | |||
| 		file_server::metrics::Interval::monitor (interval_writer).await; | ||||
| 	}); | ||||
| 	
 | ||||
| 	let state = Arc::new (State { | ||||
| 		config: file_server::Config { | ||||
| 			file_server_root: config_file.file_server_root, | ||||
| 		}, | ||||
| 		handlebars, | ||||
| 		metrics_startup, | ||||
| 	let state = Arc::new (State::new ( | ||||
| 		config_file.file_server_root, | ||||
| 		&PathBuf::new (), | ||||
| 		config_file.name.unwrap_or_else (|| "PTTH File Server".to_string ()), | ||||
| 		metrics_interval, | ||||
| 		hidden_path: Some (path), | ||||
| 	}); | ||||
| 		Some (path), | ||||
| 	)?); | ||||
| 	
 | ||||
| 	let make_svc = make_service_fn (|_conn| { | ||||
| 		let state = state.clone (); | ||||
|  |  | |||
|  | @ -1,20 +1,30 @@ | |||
| use thiserror::Error; | ||||
| 
 | ||||
| /// Errors thrown when the server loads its TOML config file
 | ||||
| 
 | ||||
| #[derive (Debug, Error)] | ||||
| pub enum LoadTomlError { | ||||
| 	/// The server's config file is readable by other users, meaning
 | ||||
| 	/// that the file server module could accidentally serve it to
 | ||||
| 	/// clients, and expose the server's API key.
 | ||||
| 	#[error ("Config file has bad permissions mode, it should be octal 0600")] | ||||
| 	ConfigBadPermissions, | ||||
| 	
 | ||||
| 	/// Wraps `std::io::Error`
 | ||||
| 	#[error ("I/O")] | ||||
| 	Io (#[from] std::io::Error), | ||||
| 	
 | ||||
| 	/// Wraps `std::string::FromUtf8Error`
 | ||||
| 	#[error ("UTF-8")] | ||||
| 	Utf8 (#[from] std::string::FromUtf8Error), | ||||
| 	
 | ||||
| 	/// Wraps `toml::de::Error`
 | ||||
| 	#[error ("TOML")] | ||||
| 	Toml (#[from] toml::de::Error), | ||||
| } | ||||
| 
 | ||||
| /// Errors thrown when the server is starting up or serving requests
 | ||||
| 
 | ||||
| #[derive (Debug, Error)] | ||||
| pub enum ServerError { | ||||
| 	#[error ("Loading TOML")] | ||||
|  | @ -23,9 +33,6 @@ pub enum ServerError { | |||
| 	#[error ("Loading Handlebars template file")] | ||||
| 	LoadHandlebars (#[from] handlebars::TemplateFileError), | ||||
| 	
 | ||||
| 	#[error ("API key is too weak, server can't use it")] | ||||
| 	WeakApiKey, | ||||
| 	
 | ||||
| 	#[error ("File server error")] | ||||
| 	FileServer (#[from] super::file_server::errors::FileServerError), | ||||
| 	
 | ||||
|  |  | |||
|  | @ -2,9 +2,6 @@ use thiserror::Error; | |||
| 
 | ||||
| #[derive (Debug, Error)] | ||||
| pub enum FileServerError { | ||||
| 	#[error ("Handlebars render error")] | ||||
| 	Handlebars (#[from] handlebars::RenderError), | ||||
| 	
 | ||||
| 	#[error ("I/O error")] | ||||
| 	Io (#[from] std::io::Error), | ||||
| 	
 | ||||
|  | @ -28,6 +25,9 @@ pub enum FileServerError { | |||
| 	
 | ||||
| 	#[error ("Heim process error")] | ||||
| 	HeimProcess, | ||||
| 	
 | ||||
| 	#[error(transparent)] | ||||
| 	Other (#[from] anyhow::Error), | ||||
| } | ||||
| 
 | ||||
| impl From <heim::process::ProcessError> for FileServerError { | ||||
|  |  | |||
|  | @ -60,7 +60,7 @@ pub async fn serve_root ( | |||
| 		metrics_interval: &**state.metrics_interval.load (), | ||||
| 	}; | ||||
| 	
 | ||||
| 	let s = state.handlebars.render ("file_server_root", ¶ms)?; | ||||
| 	let s = state.handlebars.render ("file_server_root", ¶ms).map_err (anyhow::Error::from)?; | ||||
| 	
 | ||||
| 	Ok (serve (s)) | ||||
| } | ||||
|  | @ -85,7 +85,7 @@ pub async fn serve_dir ( | |||
| 		path, | ||||
| 		entries, | ||||
| 		instance_metrics, | ||||
| 	})?; | ||||
| 	}).map_err (anyhow::Error::from)?; | ||||
| 	
 | ||||
| 	Ok (serve (s)) | ||||
| } | ||||
|  |  | |||
|  | @ -67,6 +67,27 @@ pub struct State { | |||
| 	pub hidden_path: Option <PathBuf>, | ||||
| } | ||||
| 
 | ||||
| impl State { | ||||
| 	pub fn new ( | ||||
| 		file_server_root: Option <PathBuf>, | ||||
| 		asset_root: &Path, | ||||
| 		name: String, | ||||
| 		metrics_interval: Arc <ArcSwap <Option <metrics::Interval>>>, | ||||
| 		hidden_path: Option <PathBuf>, | ||||
| 	) -> Result <Self, FileServerError> | ||||
| 	{ | ||||
| 		Ok (Self { | ||||
| 			config: Config { | ||||
| 				file_server_root, | ||||
| 			}, | ||||
| 			handlebars: load_templates (asset_root)?, | ||||
| 			metrics_startup: metrics::Startup::new (name), | ||||
| 			metrics_interval, | ||||
| 			hidden_path, | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #[derive (Serialize)] | ||||
| struct DirJson { | ||||
| 	entries: Vec <DirEntryJson>, | ||||
|  | @ -311,14 +332,14 @@ async fn stream_file ( | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Pass a request to the internal decision-making logic.
 | ||||
| // When it returns, prettify it as HTML or JSON based on what the client
 | ||||
| // asked for.
 | ||||
| /// Top-level request handler for the file server module.
 | ||||
| /// 
 | ||||
| /// Passes a request to the internal file server logic.
 | ||||
| /// Returns an HTTP response as HTML or JSON, depending on the request.
 | ||||
| 
 | ||||
| #[instrument (level = "debug", skip (state, headers))] | ||||
| pub async fn serve_all ( | ||||
| 	state: &State, | ||||
| 	root: &Path, | ||||
| 	method: Method, | ||||
| 	uri: &str, | ||||
| 	headers: &HashMap <String, Vec <u8>> | ||||
|  | @ -342,6 +363,11 @@ pub async fn serve_all ( | |||
| 		resp | ||||
| 	} | ||||
| 	
 | ||||
| 	let default_root = PathBuf::from ("./"); | ||||
| 	let root: &std::path::Path = state.config.file_server_root | ||||
| 	.as_ref () | ||||
| 	.unwrap_or (&default_root); | ||||
| 	
 | ||||
| 	Ok (match internal::serve_all (root, method, uri, headers, state.hidden_path.as_deref ()).await? { | ||||
| 		Favicon => serve_error (StatusCode::NotFound, "Not found\n"), | ||||
| 		Forbidden => serve_error (StatusCode::Forbidden, "403 Forbidden\n"), | ||||
|  | @ -400,10 +426,10 @@ pub async fn serve_all ( | |||
| 	}) | ||||
| } | ||||
| 
 | ||||
| pub fn load_templates ( | ||||
| fn load_templates ( | ||||
| 	asset_root: &Path | ||||
| ) 
 | ||||
| -> Result <Handlebars <'static>, handlebars::TemplateFileError> | ||||
| -> Result <Handlebars <'static>, anyhow::Error> | ||||
| { | ||||
| 	let mut handlebars = Handlebars::new (); | ||||
| 	handlebars.set_strict_mode (true); | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| //! # PTTH Server
 | ||||
| //! 
 | ||||
| //! The PTTH server makes an outgoing HTTP connection to a
 | ||||
| //! The PTTH server makes outgoing HTTP connections to a
 | ||||
| //! PTTH relay, and then serves incoming HTTP requests through
 | ||||
| //! the relay.
 | ||||
| 
 | ||||
|  | @ -35,7 +35,12 @@ use ptth_core::{ | |||
| }; | ||||
| 
 | ||||
| pub mod errors; | ||||
| 
 | ||||
| /// In-process file server module with byte range and ETag support
 | ||||
| pub mod file_server; | ||||
| 
 | ||||
| /// Load and de-serialize structures from TOML, with a size limit
 | ||||
| /// and checking permissions (On Unix)
 | ||||
| pub mod load_toml; | ||||
| 
 | ||||
| use errors::ServerError; | ||||
|  | @ -58,14 +63,8 @@ async fn handle_one_req ( | |||
| 	
 | ||||
| 	debug! ("Handling request {}", req_id); | ||||
| 	
 | ||||
| 	let default_root = PathBuf::from ("./"); | ||||
| 	let file_server_root: &std::path::Path = state.file_server.config.file_server_root | ||||
| 	.as_ref () | ||||
| 	.unwrap_or (&default_root); | ||||
| 	
 | ||||
| 	let response = file_server::serve_all ( | ||||
| 		&state.file_server, | ||||
| 		file_server_root, | ||||
| 		parts.method, 
 | ||||
| 		&parts.uri, 
 | ||||
| 		&parts.headers, | ||||
|  | @ -161,16 +160,30 @@ async fn handle_req_resp ( | |||
| 	Ok (()) | ||||
| } | ||||
| 
 | ||||
| // A complete config file. The bin frontend is allowed to use a different
 | ||||
| // type to load an incomplete file, as long as the command line options
 | ||||
| // complete it.
 | ||||
| /// Config for ptth_server and the file server module
 | ||||
| /// 
 | ||||
| /// This is a complete config. 
 | ||||
| /// The bin frontend is allowed to load an incomplete config from
 | ||||
| /// the TOML file, fill it out with command-line options, and put
 | ||||
| /// the completed config in this struct.
 | ||||
| 
 | ||||
| #[derive (Clone)] | ||||
| pub struct ConfigFile { | ||||
| 	/// A name that uniquely identifies this server on the relay.
 | ||||
| 	/// May be human-readable.
 | ||||
| 	pub name: String, | ||||
| 	
 | ||||
| 	/// Secret API key used to authenticate the server with the relay
 | ||||
| 	pub api_key: String, | ||||
| 	
 | ||||
| 	/// URL of the PTTH relay server that ptth_server should connect to
 | ||||
| 	pub relay_url: String, | ||||
| 	
 | ||||
| 	/// Directory that the file server module will expose to clients
 | ||||
| 	/// over the relay. If None, the current working dir is used.
 | ||||
| 	pub file_server_root: Option <PathBuf>, | ||||
| 	
 | ||||
| 	/// For debugging.
 | ||||
| 	pub throttle_upload: bool, | ||||
| } | ||||
| 
 | ||||
|  | @ -192,12 +205,19 @@ impl ConfigFile { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| /// Config for ptth_server itself
 | ||||
| 
 | ||||
| #[derive (Default)] | ||||
| pub struct Config { | ||||
| 	/// URL of the PTTH relay server that ptth_server should connect to
 | ||||
| 	pub relay_url: String, | ||||
| 	
 | ||||
| 	/// For debugging.
 | ||||
| 	pub throttle_upload: bool, | ||||
| } | ||||
| 
 | ||||
| /// Runs a PTTH file server
 | ||||
| 
 | ||||
| pub async fn run_server ( | ||||
| 	config_file: ConfigFile, | ||||
| 	shutdown_oneshot: oneshot::Receiver <()>, | ||||
|  | @ -224,9 +244,7 @@ pub async fn run_server ( | |||
| 	.default_headers (headers) | ||||
| 	.connect_timeout (Duration::from_secs (30)) | ||||
| 	.build ().map_err (ServerError::CantBuildHttpClient)?; | ||||
| 	let handlebars = file_server::load_templates (&asset_root)?; | ||||
| 	
 | ||||
| 	let metrics_startup = file_server::metrics::Startup::new (config_file.name); | ||||
| 	let metrics_interval = Arc::new (ArcSwap::default ()); | ||||
| 	
 | ||||
| 	let interval_writer = Arc::clone (&metrics_interval); | ||||
|  | @ -235,15 +253,13 @@ pub async fn run_server ( | |||
| 	}); | ||||
| 	
 | ||||
| 	let state = Arc::new (State { | ||||
| 		file_server: file_server::State { | ||||
| 			config: file_server::Config { | ||||
| 				file_server_root: config_file.file_server_root, | ||||
| 			}, | ||||
| 			handlebars, | ||||
| 			metrics_startup, | ||||
| 		file_server: file_server::State::new ( | ||||
| 			config_file.file_server_root, | ||||
| 			&asset_root, | ||||
| 			config_file.name, | ||||
| 			metrics_interval, | ||||
| 			hidden_path, | ||||
| 		}, | ||||
| 		)?, | ||||
| 		config: Config { | ||||
| 			relay_url: config_file.relay_url, | ||||
| 			throttle_upload: config_file.throttle_upload, | ||||
|  |  | |||
|  | @ -26,7 +26,7 @@ fn load_inner < | |||
| 
 | ||||
| /// For files that contain public-viewable information
 | ||||
| 
 | ||||
| pub fn load_public < | ||||
| fn load_public < | ||||
| 	T: DeserializeOwned, | ||||
| 	P: AsRef <Path> + Debug | ||||
| > ( | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 _
						_