this post was submitted on 03 Jan 2025
34 points (100.0% liked)

Rust

6958 readers
1 users here now

Welcome to the Rust community! This is a place to discuss about the Rust programming language.

Wormhole

[email protected]

Credits

  • The icon is a modified version of the official rust logo (changing the colors to a gradient and black background)

founded 2 years ago
MODERATORS
 

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();
}

all 10 comments
sorted by: hot top controversial new old
[–] [email protected] 13 points 5 months ago (1 children)

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 an io::Result, so you can match on that and then match again on the error.kind(). One of the ErrorKind variants is NotFound, which is when you can respond to the user with "File not found".

[–] [email protected] 6 points 5 months ago

Thank you for the suggestion, I will update the code locally :)

[–] [email protected] 10 points 5 months ago (1 children)

Awesome. I don’t know how, but I’m thinking the unsafe block isn’t necessary? What was causing borrow checker issues?

[–] [email protected] 5 points 5 months ago (1 children)

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.

[–] aurele 15 points 5 months ago (1 children)

Look no further than AtomicUsize in the standard library.

[–] [email protected] 1 points 4 months ago

Atomics are not free, and there is no need to make access to FILE_COUNT thread-safe in this case. Though of course this code has many other issues.

[–] [email protected] 5 points 5 months ago* (last edited 5 months ago) (1 children)

A mutable static is rare and sometimes used in embedded environments. This is very unneccessary for a simple pastebin clone.

I am also not very sure why you're using axum and then handling uploading the actual text without axum. You could have made this much more simpler.

[–] [email protected] 3 points 5 months ago

This is very unneccessary for a simple pastebin clone.

It might be but as I said I am very new to Rust and don't know how to do some stuff in Rust. someone on IRC said I should use Arc to get around this issue but I didn't know much about Arc so I went with unsafe.