Coming from a bash scripting background, Rust’s syntax is mind boggling. The code from HttpServer... to await? is a single object. Trying to figure out how it works is going to be my first task.

I will return later with results in the replies.

  // Create Http server with websocket support
  let settings_bind = settings.clone();
  HttpServer::new(move || {
    let context = LemmyContext::create(
    let rate_limiter = rate_limiter.clone();
      // The routes
      .configure(|cfg| api_routes::config(cfg, &rate_limiter))
      .configure(|cfg| lemmy_apub::http::routes::config(cfg, &settings))
      .configure(|cfg| images::config(cfg, &rate_limiter))
      .configure(|cfg| webfinger::config(cfg, &settings))
  .bind((settings_bind.bind, settings_bind.port))?
1unu jaro

This is a cool idea for a community

1unu jaro

So I think I figured a few things out.

HttpServer::new(move || {...}) is doing a few things. First, HttpServer is calling a method new which moves the context (settings_bind) into a closure ({...}), which is kind of like a local-use function. The || denotes that no variables are being passed into the closure. Instead, the context is being moved in so I guess it can be destroyed once the scope of HttpServer disappears.

App::new() must refer to a method of HttpServer but I haven’t investigated that yet. I suspect .run() applies the App construct, whatever it is.

1unu jaro

HttpServer is calling a method new

new isn’t a method and HttpServer isn’t calling it. new is an associated function of whatever HttpServer is. Associated functions called new are usually used to create a new “instance” of a type they are associated with. So Type::new will usually return a Type, a Result<Type, _>, a Option<Type> or something similar.

Methods are functions that operate on a type, they always have self or &self or &mut self or whatever as their first parameter. You can omit that parameter if you use the “dot-syntax”.

// So if you have
let instance = Type::new();

// You can either write (like an associated function)
Type::method(instance, other_parameter);
// or (dot syntax)

Instead, the context is being moved

The context (I assume you mean the variable in the closure) isn’t moved anywhere, the move keyword means, that the closure will take the ownership of all variables from the outer scope mentioned inside of it instead of borrowing or copying them.

so I guess it can be destroyed once the scope of HttpServer disappears.

What can be destroyed? In most cases you don’t need to destroy (free/uninit) anything in rust, that is done “automatically” when something goes out of scope.

App::new() must refer to a method of HttpServer

It’s an associated function of App.

I suspect .run() applies the App construct

It’s a method of whatever .bind((settings_bind.bind, settings_bind.port))? returns.

You should really take’s advice and read the book, play around a little bit and maybe do the rustlings course before you try understanding more complex programs. It’s not super hard but it will take some time, but feel free to ask here or in the rust forums if you feel stuck.

7unu jaro

This is a nice idea, but I dont think its the best way to learn. I suggest you start by reading the Rust Book, and writing some code yourself. That code in your post is using actix, so have a look at their docs and examples, and maybe also write a small web server yourself to play around with.

2unu jaro

I’m going to tackle Rust from a variety of angles, one of which is by studying Lemmy.

unu jaro

Initial observations

HttpServer::new(move || { [1] }).bind[2].run().await?; is the basic structure. [1] consists of two parts,

  1. Defining the context and rate_limiter variables
  2. Setting up something called App:new()

We see context being loaded as .app_data in App::new(), and rate_limiter being loaded into the config.

Then routes are added.

Part of what is unusual to me is defining variables within the server setup. But this may have something to do with the way Rust deals with variables. Since context has no meaning outside of this setup, better to use it here and throw it away once we’re done setting up the HttpServer?

Whereas App::new() dealt with Lemmy specific app configuration and behavior, .bind appears to involve more generic HttpServer configuration stuff [2], including the port to bind to.

Then the whole thing .run()s, and then .await?s for multithreading.

Create a post

Learn Rust by looking at Lemmy.

Let’s take apart Lemmy and see how it works.

  • 0 users online
  • 4 users / day
  • 2 users / week
  • 2 users / month
  • 4 users / 6 months
  • 11 subscribers
  • 2 Posts
  • Modlog