♻️ refactor: rename file_server::State to file_server::FileServer
							parent
							
								
									ae33337156
								
							
						
					
					
						commit
						fd238d8c2b
					
				| 
						 | 
				
			
			@ -30,12 +30,12 @@ use ptth_server::{
 | 
			
		|||
	file_server::{
 | 
			
		||||
		self,
 | 
			
		||||
		metrics,
 | 
			
		||||
		State,
 | 
			
		||||
		FileServer,
 | 
			
		||||
	},
 | 
			
		||||
	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>>
 | 
			
		||||
{
 | 
			
		||||
	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_resp = file_server::serve_all (
 | 
			
		||||
		&state,
 | 
			
		||||
	let ptth_resp = state.serve_all (
 | 
			
		||||
		ptth_req.method, 
 | 
			
		||||
		&ptth_req.uri, 
 | 
			
		||||
		&ptth_req.headers
 | 
			
		||||
| 
						 | 
				
			
			@ -95,7 +94,7 @@ async fn main () -> anyhow::Result <()> {
 | 
			
		|||
		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,
 | 
			
		||||
		&PathBuf::new (),
 | 
			
		||||
		config_file.name.unwrap_or_else (|| "PTTH File Server".to_string ()),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,7 +46,7 @@ struct DirEntry {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
pub async fn serve_root (
 | 
			
		||||
	state: &super::State,
 | 
			
		||||
	state: &super::FileServer,
 | 
			
		||||
) -> Result <Response, FileServerError>
 | 
			
		||||
{
 | 
			
		||||
	#[derive (Serialize)]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -59,7 +59,7 @@ pub struct Config {
 | 
			
		|||
	pub file_server_root: Option <PathBuf>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct State {
 | 
			
		||||
pub struct FileServer {
 | 
			
		||||
	pub config: Config,
 | 
			
		||||
	pub handlebars: handlebars::Handlebars <'static>,
 | 
			
		||||
	pub metrics_startup: metrics::Startup,
 | 
			
		||||
| 
						 | 
				
			
			@ -67,7 +67,7 @@ pub struct State {
 | 
			
		|||
	pub hidden_path: Option <PathBuf>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl State {
 | 
			
		||||
impl FileServer {
 | 
			
		||||
	pub fn new (
 | 
			
		||||
		file_server_root: Option <PathBuf>,
 | 
			
		||||
		asset_root: &Path,
 | 
			
		||||
| 
						 | 
				
			
			@ -332,98 +332,100 @@ async fn stream_file (
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// 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.
 | 
			
		||||
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.
 | 
			
		||||
 | 
			
		||||
#[instrument (level = "debug", skip (state, headers))]
 | 
			
		||||
pub async fn serve_all (
 | 
			
		||||
	state: &State,
 | 
			
		||||
	method: Method,
 | 
			
		||||
	uri: &str,
 | 
			
		||||
	headers: &HashMap <String, Vec <u8>>
 | 
			
		||||
)
 | 
			
		||||
-> Result <Response, FileServerError>
 | 
			
		||||
{
 | 
			
		||||
	use internal::{
 | 
			
		||||
		OutputFormat,
 | 
			
		||||
		Response::*,
 | 
			
		||||
	};
 | 
			
		||||
	
 | 
			
		||||
	fn serve_error <S: Into <Vec <u8>>> (
 | 
			
		||||
		status_code: StatusCode,
 | 
			
		||||
		msg: S
 | 
			
		||||
	#[instrument (level = "debug", skip (self, headers))]
 | 
			
		||||
	pub async fn serve_all (
 | 
			
		||||
		&self,
 | 
			
		||||
		method: Method,
 | 
			
		||||
		uri: &str,
 | 
			
		||||
		headers: &HashMap <String, Vec <u8>>
 | 
			
		||||
	)
 | 
			
		||||
	-> Response
 | 
			
		||||
	-> Result <Response, FileServerError>
 | 
			
		||||
	{
 | 
			
		||||
		let mut resp = Response::default ();
 | 
			
		||||
		resp.status_code (status_code);
 | 
			
		||||
		resp.body_bytes (msg.into ());
 | 
			
		||||
		resp
 | 
			
		||||
		use internal::{
 | 
			
		||||
			OutputFormat,
 | 
			
		||||
			Response::*,
 | 
			
		||||
		};
 | 
			
		||||
		
 | 
			
		||||
		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 (
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,7 +46,7 @@ pub mod load_toml;
 | 
			
		|||
use errors::ServerError;
 | 
			
		||||
 | 
			
		||||
struct State {
 | 
			
		||||
	file_server: file_server::State,
 | 
			
		||||
	file_server: file_server::FileServer,
 | 
			
		||||
	config: Config,
 | 
			
		||||
	client: Client,
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -63,8 +63,7 @@ async fn handle_one_req (
 | 
			
		|||
	
 | 
			
		||||
	debug! ("Handling request {}", req_id);
 | 
			
		||||
	
 | 
			
		||||
	let response = file_server::serve_all (
 | 
			
		||||
		&state.file_server,
 | 
			
		||||
	let response = state.file_server.serve_all (
 | 
			
		||||
		parts.method, 
 | 
			
		||||
		&parts.uri, 
 | 
			
		||||
		&parts.headers,
 | 
			
		||||
| 
						 | 
				
			
			@ -253,7 +252,7 @@ pub async fn run_server (
 | 
			
		|||
	});
 | 
			
		||||
	
 | 
			
		||||
	let state = Arc::new (State {
 | 
			
		||||
		file_server: file_server::State::new (
 | 
			
		||||
		file_server: file_server::FileServer::new (
 | 
			
		||||
			config_file.file_server_root,
 | 
			
		||||
			&asset_root,
 | 
			
		||||
			config_file.name,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue