the code I have written isn’t very idiomatic or efficient. I am still new to Rust so I am learning things. I am amazed that I can write a pastebin in just 60 lines of Rust code. It’s awesome. I am thinking about deploying it on my server.
any suggestions would be appreciated :)
code:
use axum::{extract::Path, routing::get, Router};
use std::fs::{read_to_string, File};
use std::io::prelude::*;
use std::net::{TcpListener, TcpStream};
use std::str;
const MAX_FILE_SIZE: usize = 1024 * 1024 * 10;
static mut FILE_COUNT: usize = 0;
fn handle_client(stream: &mut TcpStream) -> std::io::Result<()> {
let mut buf = vec![0; 1024];
unsafe {
let file_name = FILE_COUNT.to_string();
FILE_COUNT += 1;
let mut file = File::create(file_name)?;
let mut size: usize = 0;
loop {
let read_data = stream.read(&mut buf).unwrap();
size += read_data;
if size >= MAX_FILE_SIZE {
return Ok(())
}
if read_data == 0 {
return Ok(());
}
stream.write_all(&buf[..read_data]).unwrap();
write!(file, "{}", str::from_utf8(&buf[..read_data]).unwrap())?;
}
}
}
async fn upload_handle() -> std::io::Result<()> {
let listener = TcpListener::bind("127.0.0.1:8080")?;
// accept connections and process them serially
for stream in listener.incoming() {
handle_client(&mut stream?)?;
}
Ok(())
}
async fn handle(Path(id): Path<String>) -> String {
if let Ok(content) = read_to_string(id) {
return content;
}
return String::from("ERROR: File not found");
}
#[tokio::main]
async fn main() {
tokio::spawn(upload_handle());
let app = Router::new()
.route("/", get(|| async { "Paste something in pastebin!" }))
.route("/{id}", get(handle));
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
In your handle-function, you kind of just assume that an error while reading the file means that the file isn’t there. But it could also have the wrong permissions, for example.
The
fs::read_to_string()
function returns anio::Result
, so you can match on that and then match again on theerror.kind()
. One of theErrorKind
variants isNotFound
, which is when you can respond to the user with “File not found”.Thank you for the suggestion, I will update the code locally :)
Awesome. I don’t know how, but I’m thinking the unsafe block isn’t necessary? What was causing borrow checker issues?
It’s because I am changing the value of a static variable, there could be more than one thread trying to change the value of FILE_COUNT which could lead to race condition.
Look no further than AtomicUsize in the standard library.
deleted by creator
If you deploy with Docker you need to attach to the external interface – I bound to localhost in a Docker container once and its painful enough to debug that it is something I never forget.
I expect that
upload_handle()
would need to change to0.0.0.0
rather than axum to bind to localhost.