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

  • Ephera@lemmy.ml
    link
    fedilink
    English
    arrow-up
    13
    ·
    3 days ago

    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”.

  • maegul (he/they)@lemmy.ml
    link
    fedilink
    English
    arrow-up
    10
    ·
    3 days ago

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

    • whoareu@lemmy.caOP
      link
      fedilink
      arrow-up
      4
      ·
      3 days ago

      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.

        • deadcream
          link
          fedilink
          arrow-up
          1
          ·
          2 days 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.

  • asudox@discuss.tchncs.de
    link
    fedilink
    arrow-up
    5
    ·
    edit-2
    3 days ago

    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.

    • whoareu@lemmy.caOP
      link
      fedilink
      arrow-up
      3
      ·
      3 days 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.

      • TehPers@beehaw.org
        link
        fedilink
        English
        arrow-up
        5
        ·
        3 days ago

        static mut has so many safety requirements to use it soundly that you should just not use it. Use an AtomicUsize instead, and just make it static.

  • BaumGeist@lemmy.ml
    link
    fedilink
    arrow-up
    3
    ·
    3 days ago

    Is there a reason why axum needs to be exposed on every network interface? Because that seems like a potential security concern

    • alienscience@programming.dev
      link
      fedilink
      arrow-up
      3
      ·
      3 days ago

      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 to 0.0.0.0 rather than axum to bind to localhost.