Can update files
This commit is contained in:
		
							
								
								
									
										71
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										71
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @@ -89,6 +89,24 @@ dependencies = [ | ||||
|  "syn", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "actix-multipart" | ||||
| version = "0.4.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "c9edfb0e7663d7fe18c8d5b668c9c1bcf79176b1dcc9d4da9592503209a6bfb0" | ||||
| dependencies = [ | ||||
|  "actix-utils", | ||||
|  "actix-web", | ||||
|  "bytes", | ||||
|  "derive_more", | ||||
|  "futures-core", | ||||
|  "httparse", | ||||
|  "local-waker", | ||||
|  "log", | ||||
|  "mime", | ||||
|  "twoway", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "actix-router" | ||||
| version = "0.5.0" | ||||
| @@ -460,6 +478,18 @@ dependencies = [ | ||||
|  "termcolor", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "filetime" | ||||
| version = "0.2.15" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" | ||||
| dependencies = [ | ||||
|  "cfg-if", | ||||
|  "libc", | ||||
|  "redox_syscall", | ||||
|  "winapi", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "firestorm" | ||||
| version = "0.5.0" | ||||
| @@ -522,6 +552,7 @@ dependencies = [ | ||||
|  "futures-task", | ||||
|  "pin-project-lite", | ||||
|  "pin-utils", | ||||
|  "slab", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| @@ -819,10 +850,14 @@ name = "pages_server" | ||||
| version = "0.1.0" | ||||
| dependencies = [ | ||||
|  "actix-files", | ||||
|  "actix-multipart", | ||||
|  "actix-web", | ||||
|  "bytes", | ||||
|  "clap", | ||||
|  "env_logger", | ||||
|  "futures-util", | ||||
|  "log", | ||||
|  "tar", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| @@ -1091,6 +1126,17 @@ dependencies = [ | ||||
|  "unicode-xid", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "tar" | ||||
| version = "0.4.38" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" | ||||
| dependencies = [ | ||||
|  "filetime", | ||||
|  "libc", | ||||
|  "xattr", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "termcolor" | ||||
| version = "1.1.3" | ||||
| @@ -1206,12 +1252,28 @@ dependencies = [ | ||||
|  "lazy_static", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "twoway" | ||||
| version = "0.2.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "c57ffb460d7c24cd6eda43694110189030a3d1dfe418416d9468fd1c1d290b47" | ||||
| dependencies = [ | ||||
|  "memchr", | ||||
|  "unchecked-index", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "typenum" | ||||
| version = "1.15.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" | ||||
|  | ||||
| [[package]] | ||||
| name = "unchecked-index" | ||||
| version = "0.2.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "eeba86d422ce181a719445e51872fa30f1f7413b62becb52e95ec91aa262d85c" | ||||
|  | ||||
| [[package]] | ||||
| name = "unicase" | ||||
| version = "2.6.0" | ||||
| @@ -1346,6 +1408,15 @@ version = "0.32.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" | ||||
|  | ||||
| [[package]] | ||||
| name = "xattr" | ||||
| version = "0.2.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" | ||||
| dependencies = [ | ||||
|  "libc", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "zstd" | ||||
| version = "0.10.0+zstd.1.5.2" | ||||
|   | ||||
| @@ -9,5 +9,9 @@ edition = "2021" | ||||
| clap = { version = "3.1.6", features = ["derive", "env"] } | ||||
| actix-web = "4" | ||||
| actix-files = "0.6" | ||||
| actix-multipart = "0.4" | ||||
| env_logger = "0.9.0" | ||||
| log = "0.4" | ||||
| log = "0.4" | ||||
| bytes = "1.1.0" | ||||
| futures-util = { version = "0.3.7", default-features = false, features = ["std"] } | ||||
| tar = "0.4.38" | ||||
							
								
								
									
										88
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								src/main.rs
									
									
									
									
									
								
							| @@ -1,10 +1,15 @@ | ||||
| use std::io::Read; | ||||
| use std::path::{Path, PathBuf}; | ||||
|  | ||||
| use actix_files::{Files, NamedFile}; | ||||
| use actix_web::{App, HttpResponse, HttpServer}; | ||||
| use actix_multipart::Multipart; | ||||
| use actix_web::{App, Error, HttpRequest, HttpResponse, HttpServer, web}; | ||||
| use actix_web::dev::{fn_service, ServiceRequest, ServiceResponse}; | ||||
| use actix_web::error::{ErrorInternalServerError, ErrorUnauthorized}; | ||||
| use actix_web::middleware::Logger; | ||||
| use bytes::BufMut; | ||||
| use clap::Parser; | ||||
| use futures_util::TryStreamExt; | ||||
|  | ||||
| /// Simple pages server | ||||
| #[derive(Parser, Debug, Clone)] | ||||
| @@ -50,6 +55,82 @@ impl Args { | ||||
|  | ||||
| static mut ARGS: Option<Args> = None; | ||||
|  | ||||
| struct NewFile { | ||||
|     path: PathBuf, | ||||
|     bytes: Vec<u8>, | ||||
| } | ||||
|  | ||||
| /// Replace all the files of the website | ||||
| async fn replace_files(args: web::Data<Args>, req: HttpRequest, mut payload: Multipart) -> Result<HttpResponse, Error> { | ||||
|  | ||||
|     // Check token | ||||
|     let token = match req.headers().get("Token") { | ||||
|         None => { | ||||
|             return Err(ErrorUnauthorized("Token required!")); | ||||
|         } | ||||
|         Some(t) => t.to_str() | ||||
|             .map_err(|_| ErrorInternalServerError("Failed to parse token!"))? | ||||
|     }; | ||||
|  | ||||
|     if !token.eq(&args.update_token) || args.update_token.is_empty() { | ||||
|         return Err(ErrorUnauthorized("Invalid update token!")); | ||||
|     } | ||||
|  | ||||
|     let mut new_files = Vec::new(); | ||||
|  | ||||
|     // iterate over multipart stream | ||||
|     if let Some(mut field) = payload.try_next().await? { | ||||
|         let mut b = bytes::BytesMut::new(); | ||||
|  | ||||
|         // Field in turn is stream of *Bytes* object | ||||
|         while let Some(chunk) = field.try_next().await? { | ||||
|             b.put(chunk); | ||||
|         } | ||||
|  | ||||
|         let mut archive = tar::Archive::new(b.as_ref()); | ||||
|         for entry in archive.entries() | ||||
|             .map_err(|_| ErrorInternalServerError("Failed to parse TAR archive!"))? { | ||||
|             let mut file = entry?; | ||||
|             let inner_path = file.header().path()?; | ||||
|  | ||||
|             if inner_path.is_absolute() { | ||||
|                 return Err(ErrorInternalServerError("Cowardly refusing to unpack absolute file!")); | ||||
|             } | ||||
|  | ||||
|             if inner_path.is_dir() || inner_path.to_string_lossy().ends_with("/") { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             let dest_file = args.storage_path().join(inner_path); | ||||
|             let mut buf = Vec::with_capacity(file.size() as usize); | ||||
|             file.read_to_end(&mut buf)?; | ||||
|  | ||||
|             new_files.push(NewFile { | ||||
|                 path: dest_file, | ||||
|                 bytes: buf, | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // Delete all current files in storage | ||||
|     for entry in std::fs::read_dir(args.storage_path())? { | ||||
|         let entry = entry?; | ||||
|         if entry.path().is_dir() { | ||||
|             std::fs::remove_dir_all(entry.path())?; | ||||
|         } else { | ||||
|             std::fs::remove_file(entry.path())?; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // Apply new files | ||||
|     for file in new_files { | ||||
|         std::fs::create_dir_all(file.path.parent().unwrap())?; | ||||
|         std::fs::write(file.path, file.bytes)?; | ||||
|     } | ||||
|  | ||||
|     Ok(HttpResponse::Ok().into()) | ||||
| } | ||||
|  | ||||
| #[actix_web::main] | ||||
| async fn main() -> std::io::Result<()> { | ||||
|     let args: Args = Args::parse(); | ||||
| @@ -67,6 +148,10 @@ async fn main() -> std::io::Result<()> { | ||||
|     HttpServer::new(move || { | ||||
|         App::new() | ||||
|  | ||||
|             // Update service | ||||
|             .service(web::resource("/_mgmt/replace_files") | ||||
|                 .route(web::post().to(replace_files))) | ||||
|  | ||||
|             // Serve a tree of static files at the web root and specify the index file. | ||||
|             // Note that the root path should always be defined as the last item. The paths are | ||||
|             // resolved in the order they are defined. If this would be placed before the `/images` | ||||
| @@ -90,6 +175,7 @@ async fn main() -> std::io::Result<()> { | ||||
|  | ||||
|             // Enable the logger. | ||||
|             .wrap(Logger::default()) | ||||
|             .app_data(web::Data::new(args.clone())) | ||||
|     }) | ||||
|         .bind(listen_address)? | ||||
|         .run() | ||||
|   | ||||
		Reference in New Issue
	
	Block a user