mirror of
				https://github.com/Tim-Paik/srv.git
				synced 2024-10-13 00:29:43 +00:00 
			
		
		
		
	0.7.2-beta cargo doc support and bugs fix
This commit is contained in:
		
							
								
								
									
										3
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										3
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -2463,9 +2463,10 @@ checksum = "acdb075a845574a1fa5f09fd77e43f7747599301ea3417a9fbffdeedfc1f4a29" | |||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "web" | name = "web" | ||||||
| version = "0.6.5-beta" | version = "0.7.2-beta" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "actix-files", |  "actix-files", | ||||||
|  |  "actix-http", | ||||||
|  "actix-web", |  "actix-web", | ||||||
|  "actix-web-httpauth", |  "actix-web-httpauth", | ||||||
|  "chrono", |  "chrono", | ||||||
|  | |||||||
							
								
								
									
										11
									
								
								Cargo.toml
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								Cargo.toml
									
									
									
									
									
								
							| @ -3,24 +3,25 @@ authors = ["Tim_Paik <timpaikc@outlook.com>"] | |||||||
| description = "simple http server written in rust" | description = "simple http server written in rust" | ||||||
| edition = "2018" | edition = "2018" | ||||||
| name = "web" | name = "web" | ||||||
| version = "0.6.5-beta" | version = "0.7.2-beta" | ||||||
|  |  | ||||||
| [dependencies] | [dependencies] | ||||||
| actix-files = "0.5" | actix-files = "0.5" | ||||||
|  | actix-http = "2.2" | ||||||
| actix-web = {version = "3.3", features = ["openssl"]} | actix-web = {version = "3.3", features = ["openssl"]} | ||||||
| actix-web-httpauth = "0.5" | actix-web-httpauth = "0.5" | ||||||
| chrono = "0.4" | chrono = "0.4" | ||||||
| clap = {version = "3.0.0-beta.2", features = ["wrap_help", "color"]} | clap = {version = "3.0.0-beta.4", features = ["wrap_help", "color"]} | ||||||
| env_logger = "0.9" | env_logger = "0.9" | ||||||
| lazy_static = "1.4" | lazy_static = "1.4" | ||||||
| log = "0.4" | log = "0.4" | ||||||
| mime_guess = "2.0.3" | mime_guess = "2" | ||||||
| openssl = {version = "0.10"} | openssl = {version = "0.10", features = ["v110"]} | ||||||
| regex = "1.5" | regex = "1.5" | ||||||
| serde = "1" | serde = "1" | ||||||
| sha2 = "0.9" | sha2 = "0.9" | ||||||
| tera = "1" | tera = "1" | ||||||
|  |  | ||||||
| [profile.release] | [profile.release] | ||||||
|  | lto = true | ||||||
| opt-level = "z" | opt-level = "z" | ||||||
| lto = true |  | ||||||
							
								
								
									
										138
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										138
									
								
								src/main.rs
									
									
									
									
									
								
							| @ -5,11 +5,11 @@ extern crate lazy_static; | |||||||
|  |  | ||||||
| use actix_files as fs; | use actix_files as fs; | ||||||
| use actix_web::{ | use actix_web::{ | ||||||
|     dev::{Service, ServiceResponse}, |     dev::{self, Service, ServiceResponse}, | ||||||
|     http, middleware, App, HttpResponse, HttpServer, |     http, middleware, App, HttpResponse, HttpServer, | ||||||
| }; | }; | ||||||
| use env_logger::fmt::Color; | use env_logger::fmt::Color; | ||||||
| use log::error; | use log::{error, info}; | ||||||
| use sha2::Digest; | use sha2::Digest; | ||||||
| use std::{ | use std::{ | ||||||
|     env::{set_var, var}, |     env::{set_var, var}, | ||||||
| @ -23,7 +23,7 @@ use std::{ | |||||||
| lazy_static! { | lazy_static! { | ||||||
|     pub static ref TEMPLATE: tera::Tera = { |     pub static ref TEMPLATE: tera::Tera = { | ||||||
|         let mut tera = tera::Tera::default(); |         let mut tera = tera::Tera::default(); | ||||||
|         tera.add_raw_template("index", include_str!("../templates/index.html.tera.embed")) |         tera.add_raw_template("index", include_str!("../templates/index.html.tera")) | ||||||
|             .unwrap(); |             .unwrap(); | ||||||
|         tera |         tera | ||||||
|     }; |     }; | ||||||
| @ -301,9 +301,9 @@ fn hash(from: &str) -> String { | |||||||
|  |  | ||||||
| #[inline] | #[inline] | ||||||
| async fn validator( | async fn validator( | ||||||
|     req: actix_web::dev::ServiceRequest, |     req: dev::ServiceRequest, | ||||||
|     auth: actix_web_httpauth::extractors::basic::BasicAuth, |     auth: actix_web_httpauth::extractors::basic::BasicAuth, | ||||||
| ) -> Result<actix_web::dev::ServiceRequest, actix_web::Error> { | ) -> Result<dev::ServiceRequest, actix_web::Error> { | ||||||
|     if auth.user_id() == var("AUTH_USERNAME").unwrap_or("".to_string()).as_str() |     if auth.user_id() == var("AUTH_USERNAME").unwrap_or("".to_string()).as_str() | ||||||
|         && hash(auth.password().unwrap_or(&std::borrow::Cow::from(""))) |         && hash(auth.password().unwrap_or(&std::borrow::Cow::from(""))) | ||||||
|             == var("AUTH_PASSWORD").unwrap_or("".to_string()).as_str() |             == var("AUTH_PASSWORD").unwrap_or("".to_string()).as_str() | ||||||
| @ -333,6 +333,8 @@ async fn main() -> std::io::Result<()> { | |||||||
|         (@arg spa: --spa "Enable Single-Page Application mode (always serve /index.html when the file is not found)") |         (@arg spa: --spa "Enable Single-Page Application mode (always serve /index.html when the file is not found)") | ||||||
|         (@arg dotfiles: -d --dotfiles "Show dotfiles") |         (@arg dotfiles: -d --dotfiles "Show dotfiles") | ||||||
|         (@arg open: -o --open "Open the page in the default browser") |         (@arg open: -o --open "Open the page in the default browser") | ||||||
|  |         (@arg quiet: -q --quiet "Disable access log output") | ||||||
|  |         (@arg quietall: --quietall "Disable all output") | ||||||
|         (@arg ROOT: default_value["."] { |         (@arg ROOT: default_value["."] { | ||||||
|             |path| match std::fs::metadata(path) { |             |path| match std::fs::metadata(path) { | ||||||
|                 Ok(meta) => { |                 Ok(meta) => { | ||||||
| @ -393,6 +395,25 @@ async fn main() -> std::io::Result<()> { | |||||||
|                 Err(e) => Err(e.to_string()), |                 Err(e) => Err(e.to_string()), | ||||||
|             } |             } | ||||||
|         } "Path of TLS/SSL private key") |         } "Path of TLS/SSL private key") | ||||||
|  |         (@subcommand doc => | ||||||
|  |             (about: "Open cargo doc via local server (Need cargo installation)") | ||||||
|  |             (@arg nocolor: --nocolor "Disable cli colors") | ||||||
|  |             (@arg noopen: -no --noopen "Do not open the page in the default browser") | ||||||
|  |             (@arg log: --log "Enable access log output [default: false]") | ||||||
|  |             (@arg quietall: --quietall "Disable all output") | ||||||
|  |             (@arg address: -a --address +takes_value default_value["0.0.0.0"] { | ||||||
|  |                 |s| match IpAddr::from_str(&s) { | ||||||
|  |                     Ok(_) => Ok(()), | ||||||
|  |                     Err(e) => Err(e.to_string()), | ||||||
|  |                 } | ||||||
|  |             } "IP address to serve on") | ||||||
|  |             (@arg port: -p --port +takes_value default_value["8000"] { | ||||||
|  |                 |s| match s.parse::<u16>() { | ||||||
|  |                     Ok(_) => Ok(()), | ||||||
|  |                     Err(e) => Err(e.to_string()), | ||||||
|  |                 } | ||||||
|  |             } "Port to serve on") | ||||||
|  |         ) | ||||||
|     ) |     ) | ||||||
|     .get_matches(); |     .get_matches(); | ||||||
|  |  | ||||||
| @ -406,6 +427,8 @@ async fn main() -> std::io::Result<()> { | |||||||
|     set_var("DOTFILES", matches.is_present("dotfiles").to_string()); |     set_var("DOTFILES", matches.is_present("dotfiles").to_string()); | ||||||
|     set_var("NOCACHE", matches.is_present("nocache").to_string()); |     set_var("NOCACHE", matches.is_present("nocache").to_string()); | ||||||
|     set_var("COMPRESS", matches.is_present("compress").to_string()); |     set_var("COMPRESS", matches.is_present("compress").to_string()); | ||||||
|  |     set_var("QUIET", matches.is_present("quiet").to_string()); | ||||||
|  |     set_var("QUIETALL", matches.is_present("quietall").to_string()); | ||||||
|  |  | ||||||
|     if matches.is_present("nocolor") { |     if matches.is_present("nocolor") { | ||||||
|         set_var("RUST_LOG_STYLE", "never"); |         set_var("RUST_LOG_STYLE", "never"); | ||||||
| @ -458,7 +481,7 @@ async fn main() -> std::io::Result<()> { | |||||||
|         matches.value_of("port").unwrap_or("8000").to_string() |         matches.value_of("port").unwrap_or("8000").to_string() | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
|     if matches.is_present("open") { |     let open_in_browser = |url: &str| { | ||||||
|         if cfg!(target_os = "windows") { |         if cfg!(target_os = "windows") { | ||||||
|             std::process::Command::new("explorer").arg(url).spawn().ok(); |             std::process::Command::new("explorer").arg(url).spawn().ok(); | ||||||
|         } else if cfg!(target_os = "macos") { |         } else if cfg!(target_os = "macos") { | ||||||
| @ -466,10 +489,17 @@ async fn main() -> std::io::Result<()> { | |||||||
|         } else if cfg!(target_os = "linux") { |         } else if cfg!(target_os = "linux") { | ||||||
|             std::process::Command::new("xdg-open").arg(url).spawn().ok(); |             std::process::Command::new("xdg-open").arg(url).spawn().ok(); | ||||||
|         } |         } | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     if matches.is_present("open") { | ||||||
|  |         open_in_browser(&url); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")) |     env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")) | ||||||
|         .format(|buf, record| { |         .format(|buf, record| { | ||||||
|  |             if var("QUIETALL").unwrap_or("false".to_string()) == "true" { | ||||||
|  |                 return Ok(()); | ||||||
|  |             } | ||||||
|             let data = record.args().to_string(); |             let data = record.args().to_string(); | ||||||
|             let mut style = buf.style(); |             let mut style = buf.style(); | ||||||
|             let blue = style.set_color(Color::Rgb(52, 152, 219)); |             let blue = style.set_color(Color::Rgb(52, 152, 219)); | ||||||
| @ -478,6 +508,9 @@ async fn main() -> std::io::Result<()> { | |||||||
|             let mut style = buf.style(); |             let mut style = buf.style(); | ||||||
|             let green = style.set_color(Color::Rgb(76, 175, 80)); |             let green = style.set_color(Color::Rgb(76, 175, 80)); | ||||||
|             if record.target() == "actix_web::middleware::logger" { |             if record.target() == "actix_web::middleware::logger" { | ||||||
|  |                 if var("QUIET").unwrap_or("false".to_string()) == "true" { | ||||||
|  |                     return Ok(()); | ||||||
|  |                 } | ||||||
|                 let data: Vec<&str> = data.splitn(5, "^").collect(); |                 let data: Vec<&str> = data.splitn(5, "^").collect(); | ||||||
|                 let time = blue.value( |                 let time = blue.value( | ||||||
|                     chrono::NaiveDateTime::from_str(data[0]) |                     chrono::NaiveDateTime::from_str(data[0]) | ||||||
| @ -541,6 +574,68 @@ async fn main() -> std::io::Result<()> { | |||||||
|         }) |         }) | ||||||
|         .init(); |         .init(); | ||||||
|  |  | ||||||
|  |     let addr = if let Some(matches) = matches.subcommand_matches("doc") { | ||||||
|  |         info!("[INFO] Generating document (may take a while)"); | ||||||
|  |         match std::process::Command::new("cargo").arg("doc").output() { | ||||||
|  |             Ok(output) => { | ||||||
|  |                 let output = std::str::from_utf8(&output.stderr).unwrap_or(""); | ||||||
|  |                 if output.starts_with("error: could not find `Cargo.toml` in") { | ||||||
|  |                     error!("[ERROR] Cargo.toml Not Found"); | ||||||
|  |                     return Ok(()); | ||||||
|  |                 } else if output.starts_with("error: ") { | ||||||
|  |                     error!( | ||||||
|  |                         "[ERROR] {}", | ||||||
|  |                         output.strip_prefix("error: ").unwrap_or(output) | ||||||
|  |                     ); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             Err(e) => { | ||||||
|  |                 error!("[ERROR] Cargo Error: {}", e.to_string()); | ||||||
|  |                 return Ok(()); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         let path = Path::new("./target/doc/"); | ||||||
|  |         let mut index_path = path.to_path_buf(); | ||||||
|  |         index_path.push(crate_name!().to_string() + "/index.html"); | ||||||
|  |         if !index_path.exists() || !index_path.is_file() { | ||||||
|  |             error!("[ERROR] Cargo Error: doc path not found"); | ||||||
|  |             return Ok(()); | ||||||
|  |         } | ||||||
|  |         set_var("ROOT", display_path(path)); | ||||||
|  |         let ip = matches | ||||||
|  |             .value_of("address") | ||||||
|  |             .unwrap_or("127.0.0.1") | ||||||
|  |             .to_string(); | ||||||
|  |         let addr = format!( | ||||||
|  |             "{}:{}", | ||||||
|  |             ip, | ||||||
|  |             matches.value_of("port").unwrap_or("8000").to_string() | ||||||
|  |         ); | ||||||
|  |         let url = format!( | ||||||
|  |             "http://{}:{}/{}/index.html", | ||||||
|  |             if ip == "0.0.0.0" { | ||||||
|  |                 "127.0.0.1" | ||||||
|  |             } else { | ||||||
|  |                 ip.as_str() | ||||||
|  |             }, | ||||||
|  |             matches.value_of("port").unwrap_or("8000").to_string(), | ||||||
|  |             crate_name!(), | ||||||
|  |         ); | ||||||
|  |         if !matches.is_present("noopen") { | ||||||
|  |             open_in_browser(&url); | ||||||
|  |         } | ||||||
|  |         if !matches.is_present("log") { | ||||||
|  |             set_var("QUIET", true.to_string()); | ||||||
|  |         } | ||||||
|  |         if matches.is_present("nocolor") { | ||||||
|  |             set_var("RUST_LOG_STYLE", "never"); | ||||||
|  |         } | ||||||
|  |         set_var("QUIETALL", matches.is_present("quietall").to_string()); | ||||||
|  |         addr | ||||||
|  |     } else { | ||||||
|  |         addr | ||||||
|  |     }; | ||||||
|  |  | ||||||
|     let server = HttpServer::new(move || { |     let server = HttpServer::new(move || { | ||||||
|         let compress = if var("COMPRESS").unwrap_or("false".to_string()) == "true" { |         let compress = if var("COMPRESS").unwrap_or("false".to_string()) == "true" { | ||||||
|             http::header::ContentEncoding::Auto |             http::header::ContentEncoding::Auto | ||||||
| @ -549,10 +644,6 @@ async fn main() -> std::io::Result<()> { | |||||||
|         }; |         }; | ||||||
|         let app = App::new() |         let app = App::new() | ||||||
|             .wrap(middleware::Compress::new(compress)) |             .wrap(middleware::Compress::new(compress)) | ||||||
|             .wrap(middleware::Condition::new( |  | ||||||
|                 true, |  | ||||||
|                 middleware::NormalizePath::default(), |  | ||||||
|             )) |  | ||||||
|             .wrap(middleware::Condition::new( |             .wrap(middleware::Condition::new( | ||||||
|                 var("ENABLE_AUTH").unwrap_or("false".to_string()) == "true", |                 var("ENABLE_AUTH").unwrap_or("false".to_string()) == "true", | ||||||
|                 actix_web_httpauth::middleware::HttpAuthentication::basic(validator), |                 actix_web_httpauth::middleware::HttpAuthentication::basic(validator), | ||||||
| @ -567,7 +658,7 @@ async fn main() -> std::io::Result<()> { | |||||||
|                 } |                 } | ||||||
|                 let fut = srv.call(req); |                 let fut = srv.call(req); | ||||||
|                 async move { |                 async move { | ||||||
|                     let res = fut.await?.map_body(|head, mut body| { |                     Ok(fut.await?.map_body(|head, mut body| { | ||||||
|                         if var("NOCACHE").unwrap_or("false".to_string()) == "true" { |                         if var("NOCACHE").unwrap_or("false".to_string()) == "true" { | ||||||
|                             head.headers_mut().insert( |                             head.headers_mut().insert( | ||||||
|                                 http::header::CACHE_CONTROL, |                                 http::header::CACHE_CONTROL, | ||||||
| @ -586,10 +677,10 @@ async fn main() -> std::io::Result<()> { | |||||||
|                             head.status = http::StatusCode::FORBIDDEN; |                             head.status = http::StatusCode::FORBIDDEN; | ||||||
|                             *head.headers_mut() = http::HeaderMap::new(); |                             *head.headers_mut() = http::HeaderMap::new(); | ||||||
|                             let _ = body.take_body(); |                             let _ = body.take_body(); | ||||||
|  |                             head.set_connection_type(http::ConnectionType::Close); | ||||||
|                         } |                         } | ||||||
|                         body |                         body | ||||||
|                     }); |                     })) | ||||||
|                     Ok(res) |  | ||||||
|                 } |                 } | ||||||
|             }) |             }) | ||||||
|             .wrap(middleware::Logger::new("%t^%a^%s^%D^%r")); |             .wrap(middleware::Logger::new("%t^%a^%s^%D^%r")); | ||||||
| @ -597,7 +688,26 @@ async fn main() -> std::io::Result<()> { | |||||||
|             .use_hidden_files() |             .use_hidden_files() | ||||||
|             .prefer_utf8(true) |             .prefer_utf8(true) | ||||||
|             .show_files_listing() |             .show_files_listing() | ||||||
|             .files_listing_renderer(render_index); |             .files_listing_renderer(render_index) | ||||||
|  |             .default_handler(|req: dev::ServiceRequest| { | ||||||
|  |                 let (http_req, _payload) = req.into_parts(); | ||||||
|  |                 async { | ||||||
|  |                     let path = var("ROOT").unwrap_or(".".to_string()); | ||||||
|  |                     let mut path = Path::new(&path).to_path_buf(); | ||||||
|  |                     path.push("index.html"); | ||||||
|  |                     if path.exists() | ||||||
|  |                         && path.is_file() | ||||||
|  |                         && var("SPA").unwrap_or("false".to_string()) == "true" | ||||||
|  |                     { | ||||||
|  |                         let res = fs::NamedFile::open(path)?.into_response(&http_req)?; | ||||||
|  |                         return Ok(ServiceResponse::new(http_req, res)); | ||||||
|  |                     } | ||||||
|  |                     return Ok(ServiceResponse::new( | ||||||
|  |                         http_req, | ||||||
|  |                         HttpResponse::NotFound().body(""), | ||||||
|  |                     )); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|         return app.service(files); |         return app.service(files); | ||||||
|     }); |     }); | ||||||
|     let server = if enable_tls { |     let server = if enable_tls { | ||||||
|  | |||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
		Reference in New Issue
	
	Block a user