impliment file upload backend and frontend with rust

impliment with actix_web

use std::path::PathBuf;
use actix_web::{web, App, HttpResponse, HttpServer};
use futures::StreamExt;
#[allow(warnings)]
async fn upload(mut payload: web::Payload) -> HttpResponse {
let path = "./stream.data";
let pathbuf = PathBuf::from(path);
if pathbuf.exists(){
std::fs::remove_file(pathbuf.clone()).unwrap();
}
while let Some(item) = payload.next().await {
let chunk = item.unwrap();
doe::fs::append_data_to_file(path, chunk.to_vec()).unwrap();
}
if let Ok(d) = std::fs::read(path){
if let Some(ex) = get_file_extension(&d){
std::fs::copy(path, format!("./stream.{}",ex)).unwrap();
}else{
std::fs::copy(path, format!("./stream")).unwrap();
}
}
if pathbuf.exists(){
std::fs::remove_file(pathbuf).unwrap();
}
HttpResponse::Ok().finish()
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.service(web::resource("/").route(web::post().to(upload)))
})
.bind("127.0.0.1:8080")?
.run()
.await
}

impliment with rocket

lib.rs

#![allow(unused)]
fn main() {
pub mod file_upload_server{
use log::info;
use rocket::{Data, post, routes, Rocket, get, response::content::Json};
use rocket_contrib::serve::StaticFiles;
use std::{fs, path::PathBuf, net::{IpAddr, SocketAddr}};
#[allow(warnings)]
#[post("/", data = "<data>")]
fn upload(data: Data) -> Result<Json<&'static str>, std::io::Error> {
let path = "./stream.data";
let pathbuf = PathBuf::from(path);
if pathbuf.exists() {
fs::remove_file(pathbuf.clone()).unwrap();
}
let mut file = fs::File::create(path)?;
data.stream_to_file(path)
.map(|n| format!("Wrote {} bytes to stream.data", n)).unwrap();
if let Ok(buf) = fs::read(path) {
if !buf.starts_with(&[0x2D,0x2D,0x2D,0x2D,0x2D,0x2D]){
if let Some(ex) = get_file_extension(&buf) {
fs::copy(path, format!("./stream.{}", ex)).unwrap();
} else {
fs::copy(path, format!("./stream")).unwrap();
}
}else{
use doe::*;
let mut buf = buf.clone();
let remove_last = buf.split_at(buf.len()-46).0.to_vec();
let remove_first_contet = remove_last.split_at(97).1;
let (head,other) = remove_first_contet.split_at(200);
let s = vec_element_to_string!(head).join(":");
let file_name = vec_element_clone!(split_to_vec!(String::from_utf8_lossy(head),"\""),0);
let s = split_to_vec!(s,":13:10:13:10:").last().unwrap().to_string();
let mut s_vec = split_to_vec!(s,":").into_iter().filter(|s|!s.is_empty()).map(|s|s.trim().to_string().parse::<u8>().unwrap()).collect::<Vec<u8>>();
s_vec.extend(other.iter());
std::fs::write(file_name, s_vec).unwrap();
}
}
if pathbuf.exists() {
fs::remove_file(pathbuf).unwrap();
}
Ok(Json("{\"status\":\"Ok\"}"))
}
#[allow(warnings)]
use rocket::response::{content, Content};
use rocket::http::ContentType;
#[get("/")]
fn index() -> Content<&'static str> {
let content_type = ContentType::HTML;
let body = include_str!("./html/index.html");
Content(content_type, body)
}
#[allow(warnings)]
fn get_file_extension(data: &[u8]) -> Option<&'static str> {
let ext = match data[..] {
// Windows PE 可执行文件
[b'M', b'Z', ..] => Some("exe"),
// Linux ELF 可执行文件
[0x7f, b'E', b'L', b'F', ..] => Some("elf"),
// PNG 图像文件
[b'\x89', b'P', b'N', b'G', ..] => Some("png"),
// HTML 文档
[b'<', b'!', b'D', b'O', b'C', b'T', ..] => Some("html"),
// PDF 文件
[b'%', b'P', b'D', b'F', ..] => Some("pdf"),
// ZIP 压缩文件
[b'P', b'K', 3, 4, ..] => Some("zip"),
// 7z 压缩文件
[0x37, 0x7a, 0xbc, 0xaf, 0x27, 0x1c, ..] => Some("7z"),
// RAR 压缩文件
[b'R', b'a', b'r', b'!', ..] => Some("rar"),
// GZIP 压缩文件
[b'\x1f', b'\x8b', 8, 0, ..] => Some("gz"),
// BZIP2 压缩文件
[b'B', b'Z', b'h', ..] => Some("bz2"),
// CPIO 归档文件
[b'I', b's', b'c', b'(', ..] => Some("cpio"),
// TAR 归档文件
[b'u', b's', b't', b'a', b'r', ..] => Some("tar"),
// CHM 帮助文件
[b'I', b'T', b'S', b'F', ..] => Some("chm"),
// MP3 音频文件
[b'I', b'D', b'3', ..] => Some("mp3"),
// AVI 视频文件
[b'R', b'I', b'F', b'F', ..] => Some("avi"),
// JPEG/JFIF 图像文件
[b'\xff', b'\xd8', b'\xff', ..] => Some("jpg"),
// BMP 图像文件
[b'B', b'M', ..] => Some("bmp"),
// ICO 图标文件
[0, 1, ..] => Some("ico"),
// WAV 音频文件
[b'R', b'I', b'F', b'F', ..] => Some("wav"),
// Ogg 容器
[b'O', b'g', b'g', b'S', ..] => Some("ogg"),
// FLAC 音频文件
[b'f', b'L', b'a', b'C', ..] => Some("flac"),
// Impress 演示文稿
[b'I', b'M', b'P', b'S', ..] => Some("impress"),
// MIDI 文件
[b'M', b'T', b'h', b'd', ..] => Some("midi"),
// TIFF 图像文件
[b'M', b'M', 0, 42, ..] => Some("tiff"),
// CR2 图像文件
[b'I', b'I', 0x2a, 0, 0x10, 0, 0, 0, b'C', b'R', ..] => Some("cr2"),
// NEF 图像文件
[b'M', b'M', 0, 0x2a, ..] => Some("nef"),
// WebP 图像文件
[b'W', b'E', b'B', b'P', ..] => Some("webp"),
// Cab 归档文件
[b'M', b'S', b'C', b'F', ..] => Some("cab"),
// Microsoft Office Open XML 文档
[b'P', b'K', 3, 4, ..] => Some("xlsx"),
// XZ 压缩格式
[b'\xfd', b'7', b'z', b'X', b'Z', 0, ..] => Some("xz"),
// iCalendar 文档
[b'B', b'E', b'G', b'I', b'N', b':', b'V', b'C', ..] => Some("ics"),
// vCard 文档
[b'B', b'E', b'G', b'I', b'N', b':', b'V', b'C', b'A', b'R', b'D', ..] => Some("vcf"),
// SQLite 数据库文件
[b'S', b'Q', b'L', b'i', b't', b'e', b' ', b'f', b'o', b'r', b'm', b'a', b't', b' ', b'3', ..] => Some("sqlite"),
// GIF 图像文件
[b'G', b'I', b'F', b'8', b'7', b'a', ..] |
[b'G', b'I', b'F', b'8', b'9', b'a', ..] => Some("gif"),
_ => None,
};
ext
}
pub async fn start() {
let ip_addr: IpAddr =  match local_ipaddress::get() {
Some(x)=>{
x.parse().expect("Found local IP Address is invalid")
},
None=>IpAddr::from([127, 0, 0, 1])
};
use rocket::config::{Config, Environment};
let socket_addr = SocketAddr::from((ip_addr, 8585));
info!("Server listening on http://{}", socket_addr);
let config = Config::build(Environment::Production)
.address(socket_addr.ip().to_string())  // 设置应用程序监听地址
.port(socket_addr.port())            // 设置应用程序监听端口
.finalize()
.unwrap();
Rocket::custom(config)
.mount("/", StaticFiles::from("static"))
.mount("/", routes![upload,index])
.launch();
}
}
}

index.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>File Upload</title>
</head>
<style>
h1 {
text-align: center;
}
form {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-top: 50px;
}
input[type=file] {
margin-bottom: 20px;
font-size: 16px;
padding: 10px;
border-radius: 5px;
background-color: #f2f2f2;
border: none;
}
button[type=submit] {
padding: 10px 20px;
background-color: #4CAF50;
color: #fff;
border: none;
border-radius: 5px;
font-size: 16px;
cursor: pointer;
}
#message {
display: none; /* 初始时隐藏 */
width: 100%;
padding: 20px;
background-color: #4CAF50;
color: #fff;
text-align: center;
margin-top: 50px;
}
</style>
<body>
<h1>File Upload</h1>
<form method="post" action="/" enctype="application/x-www-form-urlencoded">
<input type="file" name="file">
<button type="submit">Upload</button>
</form>
<div id="message"></div> <!-- 显示上传成功信息的 div -->
</body>
<script>
const form = document.querySelector('form');
const message = document.querySelector('#message');
form.addEventListener('submit', (event) => {
event.preventDefault();
const fileInput = document.querySelector('input[type=file]');
const files = fileInput.files;
if (files.length === 0) {
alert('Please select a file!');
return;
}
const formData = new FormData();
formData.append('file', files[0]);
fetch('/', { method: 'POST', body: formData })
.then(response => response.json())
.then(data => {
if (data.status) {
showSuccessMessage();
} else {
alert(data.message);
}
});
});
function showSuccessMessage() {
message.innerHTML = 'File uploaded successfully!';
message.style.display = 'block';
setTimeout(() => {
message.style.display = 'none';
}, 3000); // 3秒后自动隐藏提示信息
}
</script>
</html>