♻️ refactor: rename file_server::State to file_server::FileServer
							parent
							
								
									ae33337156
								
							
						
					
					
						commit
						fd238d8c2b
					
				| 
						 | 
					@ -30,12 +30,12 @@ use ptth_server::{
 | 
				
			||||||
	file_server::{
 | 
						file_server::{
 | 
				
			||||||
		self,
 | 
							self,
 | 
				
			||||||
		metrics,
 | 
							metrics,
 | 
				
			||||||
		State,
 | 
							FileServer,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	load_toml,
 | 
						load_toml,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async fn handle_all (req: Request <Body>, state: Arc <State>) 
 | 
					async fn handle_all (req: Request <Body>, state: Arc <FileServer>) 
 | 
				
			||||||
-> anyhow::Result <Response <Body>>
 | 
					-> anyhow::Result <Response <Body>>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	use std::str::FromStr;
 | 
						use std::str::FromStr;
 | 
				
			||||||
| 
						 | 
					@ -51,8 +51,7 @@ async fn handle_all (req: Request <Body>, state: Arc <State>)
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	let ptth_req = RequestParts::from_hyper (parts.method, path_and_query, parts.headers)?;
 | 
						let ptth_req = RequestParts::from_hyper (parts.method, path_and_query, parts.headers)?;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	let ptth_resp = file_server::serve_all (
 | 
						let ptth_resp = state.serve_all (
 | 
				
			||||||
		&state,
 | 
					 | 
				
			||||||
		ptth_req.method, 
 | 
							ptth_req.method, 
 | 
				
			||||||
		&ptth_req.uri, 
 | 
							&ptth_req.uri, 
 | 
				
			||||||
		&ptth_req.headers
 | 
							&ptth_req.headers
 | 
				
			||||||
| 
						 | 
					@ -95,7 +94,7 @@ async fn main () -> anyhow::Result <()> {
 | 
				
			||||||
		file_server::metrics::Interval::monitor (interval_writer).await;
 | 
							file_server::metrics::Interval::monitor (interval_writer).await;
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	let state = Arc::new (State::new (
 | 
						let state = Arc::new (FileServer::new (
 | 
				
			||||||
		config_file.file_server_root,
 | 
							config_file.file_server_root,
 | 
				
			||||||
		&PathBuf::new (),
 | 
							&PathBuf::new (),
 | 
				
			||||||
		config_file.name.unwrap_or_else (|| "PTTH File Server".to_string ()),
 | 
							config_file.name.unwrap_or_else (|| "PTTH File Server".to_string ()),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,7 +46,7 @@ struct DirEntry {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub async fn serve_root (
 | 
					pub async fn serve_root (
 | 
				
			||||||
	state: &super::State,
 | 
						state: &super::FileServer,
 | 
				
			||||||
) -> Result <Response, FileServerError>
 | 
					) -> Result <Response, FileServerError>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	#[derive (Serialize)]
 | 
						#[derive (Serialize)]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -59,7 +59,7 @@ pub struct Config {
 | 
				
			||||||
	pub file_server_root: Option <PathBuf>,
 | 
						pub file_server_root: Option <PathBuf>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct State {
 | 
					pub struct FileServer {
 | 
				
			||||||
	pub config: Config,
 | 
						pub config: Config,
 | 
				
			||||||
	pub handlebars: handlebars::Handlebars <'static>,
 | 
						pub handlebars: handlebars::Handlebars <'static>,
 | 
				
			||||||
	pub metrics_startup: metrics::Startup,
 | 
						pub metrics_startup: metrics::Startup,
 | 
				
			||||||
| 
						 | 
					@ -67,7 +67,7 @@ pub struct State {
 | 
				
			||||||
	pub hidden_path: Option <PathBuf>,
 | 
						pub hidden_path: Option <PathBuf>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl State {
 | 
					impl FileServer {
 | 
				
			||||||
	pub fn new (
 | 
						pub fn new (
 | 
				
			||||||
		file_server_root: Option <PathBuf>,
 | 
							file_server_root: Option <PathBuf>,
 | 
				
			||||||
		asset_root: &Path,
 | 
							asset_root: &Path,
 | 
				
			||||||
| 
						 | 
					@ -332,98 +332,100 @@ async fn stream_file (
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Top-level request handler for the file server module.
 | 
					impl FileServer {
 | 
				
			||||||
/// 
 | 
						/// 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.
 | 
						/// 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))]
 | 
						#[instrument (level = "debug", skip (self, headers))]
 | 
				
			||||||
pub async fn serve_all (
 | 
						pub async fn serve_all (
 | 
				
			||||||
	state: &State,
 | 
							&self,
 | 
				
			||||||
	method: Method,
 | 
							method: Method,
 | 
				
			||||||
	uri: &str,
 | 
							uri: &str,
 | 
				
			||||||
	headers: &HashMap <String, Vec <u8>>
 | 
							headers: &HashMap <String, Vec <u8>>
 | 
				
			||||||
)
 | 
					 | 
				
			||||||
-> Result <Response, FileServerError>
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	use internal::{
 | 
					 | 
				
			||||||
		OutputFormat,
 | 
					 | 
				
			||||||
		Response::*,
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	fn serve_error <S: Into <Vec <u8>>> (
 | 
					 | 
				
			||||||
		status_code: StatusCode,
 | 
					 | 
				
			||||||
		msg: S
 | 
					 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	-> Response
 | 
						-> Result <Response, FileServerError>
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		let mut resp = Response::default ();
 | 
							use internal::{
 | 
				
			||||||
		resp.status_code (status_code);
 | 
								OutputFormat,
 | 
				
			||||||
		resp.body_bytes (msg.into ());
 | 
								Response::*,
 | 
				
			||||||
		resp
 | 
							};
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							fn serve_error <S: Into <Vec <u8>>> (
 | 
				
			||||||
 | 
								status_code: StatusCode,
 | 
				
			||||||
 | 
								msg: S
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
							-> Response
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								let mut resp = Response::default ();
 | 
				
			||||||
 | 
								resp.status_code (status_code);
 | 
				
			||||||
 | 
								resp.body_bytes (msg.into ());
 | 
				
			||||||
 | 
								resp
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							let default_root = PathBuf::from ("./");
 | 
				
			||||||
 | 
							let root: &std::path::Path = self.config.file_server_root
 | 
				
			||||||
 | 
							.as_ref ()
 | 
				
			||||||
 | 
							.unwrap_or (&default_root);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							Ok (match internal::serve_all (root, method, uri, headers, self.hidden_path.as_deref ()).await? {
 | 
				
			||||||
 | 
								Favicon => serve_error (StatusCode::NotFound, "Not found\n"),
 | 
				
			||||||
 | 
								Forbidden => serve_error (StatusCode::Forbidden, "403 Forbidden\n"),
 | 
				
			||||||
 | 
								MethodNotAllowed => serve_error (StatusCode::MethodNotAllowed, "Unsupported method\n"),
 | 
				
			||||||
 | 
								NotFound => serve_error (StatusCode::NotFound, "404 Not Found\nAre you missing a trailing slash?\n"),
 | 
				
			||||||
 | 
								RangeNotSatisfiable (file_len) => {
 | 
				
			||||||
 | 
									let mut resp = Response::default ();
 | 
				
			||||||
 | 
									resp.status_code (StatusCode::RangeNotSatisfiable)
 | 
				
			||||||
 | 
									.header ("content-range".to_string (), format! ("bytes */{}", file_len).into_bytes ());
 | 
				
			||||||
 | 
									resp
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								Redirect (location) => {
 | 
				
			||||||
 | 
									let mut resp = Response::default ();
 | 
				
			||||||
 | 
									resp.status_code (StatusCode::TemporaryRedirect)
 | 
				
			||||||
 | 
									.header ("location".to_string (), location.into_bytes ());
 | 
				
			||||||
 | 
									resp.body_bytes (b"Redirecting...\n".to_vec ());
 | 
				
			||||||
 | 
									resp
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								InvalidQuery => serve_error (StatusCode::BadRequest, "Query is invalid for this object\n"),
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								Root => html::serve_root (self).await?,
 | 
				
			||||||
 | 
								ServeDir (internal::ServeDirParams {
 | 
				
			||||||
 | 
									path,
 | 
				
			||||||
 | 
									dir,
 | 
				
			||||||
 | 
									format
 | 
				
			||||||
 | 
								}) => match format {
 | 
				
			||||||
 | 
									OutputFormat::Json => serve_dir_json (dir.into_inner ()).await?,
 | 
				
			||||||
 | 
									OutputFormat::Html => html::serve_dir (&self.handlebars, &self.metrics_startup, path.to_string_lossy (), dir.into_inner ()).await?,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								ServeFile (internal::ServeFileParams {
 | 
				
			||||||
 | 
									file,
 | 
				
			||||||
 | 
									send_body, 
 | 
				
			||||||
 | 
									range, 
 | 
				
			||||||
 | 
								}) => serve_file (file.into_inner (), send_body, range, headers.get ("if-none-match").map (|v| &v[..])).await?,
 | 
				
			||||||
 | 
								MarkdownErr (e) => {
 | 
				
			||||||
 | 
									#[cfg (feature = "markdown")]
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										use markdown::Error::*;
 | 
				
			||||||
 | 
										let e = e.inner;
 | 
				
			||||||
 | 
										let code = match &e {
 | 
				
			||||||
 | 
											TooBig => StatusCode::InternalServerError,
 | 
				
			||||||
 | 
											//NotMarkdown => serve_error (StatusCode::BadRequest, "File is not Markdown"),
 | 
				
			||||||
 | 
											NotUtf8 => StatusCode::BadRequest,
 | 
				
			||||||
 | 
										};
 | 
				
			||||||
 | 
										
 | 
				
			||||||
 | 
										return Ok (serve_error (code, e.to_string ()));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									
 | 
				
			||||||
 | 
									#[cfg (not (feature = "markdown"))]
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										let _e = e;
 | 
				
			||||||
 | 
										serve_error (StatusCode::BadRequest, "Markdown feature is disabled")
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								MarkdownPreview (s) => html::serve (s),
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	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"),
 | 
					 | 
				
			||||||
		MethodNotAllowed => serve_error (StatusCode::MethodNotAllowed, "Unsupported method\n"),
 | 
					 | 
				
			||||||
		NotFound => serve_error (StatusCode::NotFound, "404 Not Found\nAre you missing a trailing slash?\n"),
 | 
					 | 
				
			||||||
		RangeNotSatisfiable (file_len) => {
 | 
					 | 
				
			||||||
			let mut resp = Response::default ();
 | 
					 | 
				
			||||||
			resp.status_code (StatusCode::RangeNotSatisfiable)
 | 
					 | 
				
			||||||
			.header ("content-range".to_string (), format! ("bytes */{}", file_len).into_bytes ());
 | 
					 | 
				
			||||||
			resp
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		Redirect (location) => {
 | 
					 | 
				
			||||||
			let mut resp = Response::default ();
 | 
					 | 
				
			||||||
			resp.status_code (StatusCode::TemporaryRedirect)
 | 
					 | 
				
			||||||
			.header ("location".to_string (), location.into_bytes ());
 | 
					 | 
				
			||||||
			resp.body_bytes (b"Redirecting...\n".to_vec ());
 | 
					 | 
				
			||||||
			resp
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		InvalidQuery => serve_error (StatusCode::BadRequest, "Query is invalid for this object\n"),
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		Root => html::serve_root (state).await?,
 | 
					 | 
				
			||||||
		ServeDir (internal::ServeDirParams {
 | 
					 | 
				
			||||||
			path,
 | 
					 | 
				
			||||||
			dir,
 | 
					 | 
				
			||||||
			format
 | 
					 | 
				
			||||||
		}) => match format {
 | 
					 | 
				
			||||||
			OutputFormat::Json => serve_dir_json (dir.into_inner ()).await?,
 | 
					 | 
				
			||||||
			OutputFormat::Html => html::serve_dir (&state.handlebars, &state.metrics_startup, path.to_string_lossy (), dir.into_inner ()).await?,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		ServeFile (internal::ServeFileParams {
 | 
					 | 
				
			||||||
			file,
 | 
					 | 
				
			||||||
			send_body, 
 | 
					 | 
				
			||||||
			range, 
 | 
					 | 
				
			||||||
		}) => serve_file (file.into_inner (), send_body, range, headers.get ("if-none-match").map (|v| &v[..])).await?,
 | 
					 | 
				
			||||||
		MarkdownErr (e) => {
 | 
					 | 
				
			||||||
			#[cfg (feature = "markdown")]
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				use markdown::Error::*;
 | 
					 | 
				
			||||||
				let e = e.inner;
 | 
					 | 
				
			||||||
				let code = match &e {
 | 
					 | 
				
			||||||
					TooBig => StatusCode::InternalServerError,
 | 
					 | 
				
			||||||
					//NotMarkdown => serve_error (StatusCode::BadRequest, "File is not Markdown"),
 | 
					 | 
				
			||||||
					NotUtf8 => StatusCode::BadRequest,
 | 
					 | 
				
			||||||
				};
 | 
					 | 
				
			||||||
				
 | 
					 | 
				
			||||||
				return Ok (serve_error (code, e.to_string ()));
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			
 | 
					 | 
				
			||||||
			#[cfg (not (feature = "markdown"))]
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				let _e = e;
 | 
					 | 
				
			||||||
				serve_error (StatusCode::BadRequest, "Markdown feature is disabled")
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		MarkdownPreview (s) => html::serve (s),
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn load_templates (
 | 
					fn load_templates (
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,7 +46,7 @@ pub mod load_toml;
 | 
				
			||||||
use errors::ServerError;
 | 
					use errors::ServerError;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct State {
 | 
					struct State {
 | 
				
			||||||
	file_server: file_server::State,
 | 
						file_server: file_server::FileServer,
 | 
				
			||||||
	config: Config,
 | 
						config: Config,
 | 
				
			||||||
	client: Client,
 | 
						client: Client,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -63,8 +63,7 @@ async fn handle_one_req (
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	debug! ("Handling request {}", req_id);
 | 
						debug! ("Handling request {}", req_id);
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	let response = file_server::serve_all (
 | 
						let response = state.file_server.serve_all (
 | 
				
			||||||
		&state.file_server,
 | 
					 | 
				
			||||||
		parts.method, 
 | 
							parts.method, 
 | 
				
			||||||
		&parts.uri, 
 | 
							&parts.uri, 
 | 
				
			||||||
		&parts.headers,
 | 
							&parts.headers,
 | 
				
			||||||
| 
						 | 
					@ -253,7 +252,7 @@ pub async fn run_server (
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	let state = Arc::new (State {
 | 
						let state = Arc::new (State {
 | 
				
			||||||
		file_server: file_server::State::new (
 | 
							file_server: file_server::FileServer::new (
 | 
				
			||||||
			config_file.file_server_root,
 | 
								config_file.file_server_root,
 | 
				
			||||||
			&asset_root,
 | 
								&asset_root,
 | 
				
			||||||
			config_file.name,
 | 
								config_file.name,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue