Actix router or blueprint equivalent? [duplicate] - rust

This question already has answers here:
Is there a way to split server routes declaration in actix-web?
(1 answer)
How to register routes in a different function with actix-web?
(1 answer)
Closed last month.
I'm trying to make a server with Rust for learning purposes and one of the things I'd like to do is build a router so in main I don't have 50 .service(route) calls. That way each module can pass up a method/object that registers all its routes.
use actix_web::{get,Responder, App};
#[get("/user/hello")]
async fn index() -> impl Responder {
"Hello"
}
#[get("/user/world")]
async fn world() -> impl Responder {
"World"
}
pub fn home_router<T>(app: &App) -> &App
{
app.service(index);
return app;
}
However because AppEntry is not public in the module and App::new() returns App < AppEntry >. Also the where conditions for App are not generic so I can't build a generic method to make this work (that I know of).
I'm super new to Rust and curious if someone has any ideas how it could be possible to do something like this. Bonus points if you can add a prefix. I don't mind figuring it out if someone can lead this horse to water.

Related

Returning struct with unknown generic type

I'm working on a small project in Rust where I want to have an app factory.
pub fn init_routes(cfg: &mut web::ServiceConfig) {
cfg.service(index);
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let server = HttpServer::new(|| App::new().configure(init_routes));
server.bind(("127.0.0.1", HTTP_PORT))?.run().await
}
In this case, it's only App::new().configure(init_routes). When the application grows, I'd like to add more routes and so on. It's also easy for testing.
When I put it in a function, like the following snippet, it appears to be returning App<actix_web::app_service::AppEntry> where the generic type is private (AppEntry).
fn create_app() {
App::new().configure(init_routes)
}
I tried to just refer to -> App<_> with the Inferred type feature from Rust. This did not work. Can I create this app factory with the correct return type?
AppEntry implements ServiceFactory<ServiceRequest>, so you should be able to make use of impl Trait here:
use actix_web::dev::{ServiceFactory, ServiceRequest};
fn create_app() -> App<impl ServiceFactory<ServiceRequest>> {
App::new().configure(init_routes)
}
This won't help you if you actually need to name the type of the App somewhere, though.
Normally I'd be a bit wary of relying on a private type to implement a trait, in case a future version removes the implementation. But given that all of the other methods on App are bounded by that same trait, I don't think they could do this without it being a breaking change.

How can I pass structs from an Actix middleware to the handler?

I'm trying to write an authentication middleware for my Actix application. When validating the request in the middleware, I make a call to a database to retrieve the necessary user data to validate the incoming request. Once the request has been authorised, I want to be able to pass this user data to the handler as this will allow me to avoid having the query for the same data twice.
I can't find a solution for this. The best suggestion I could find so far was to "set a request extension". There doesn't seem to be any examples for this and there is also too little documentation around this to work out what to do here.
You can pass data from middleware (service) to handler via extensions. First of all you have to insert extension (in service).
For ServiceRequest struct is implemented HttpMessage witch hase extensions_mut() function. It must be mutable becouse you will be inserting new extension. It might look something like this:
req.extensions_mut().insert(user);
Then you have to implement FromRequest trait for your data structure.
impl FromRequest for User {
type Error = actix_web::Error;
type Future = futures::future::Ready<Result<Self, Self::Error>>;
type Config = ();
fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
match req.extensions().get::<User>() {
Some(user) => return ok(user.clone()),
None => return err(actix_web::error::ErrorBadRequest("ups..."))
};
}
}
Then you're ready to use it in handler.
pub async fn get_user_handler(user: User) {}

How to return closure from function in Rust language? [duplicate]

This question already has answers here:
Returning a closure from a function
(4 answers)
Closed 2 years ago.
I am pretty new to Rust language and trying to make with Actix web framework. Now I want to return following closure from one function
let list = || {
App::new()
// enable logger
.wrap(middleware::Logger::default())
.service(web::resource("/index.html").to(|| async { "Hello world!" }))
.service(web::resource("/").to(index::home))
.service(web::resource("/h2").to(index::home2))
};
So, I can consume that with
HttpServer::new(routes::list())
.bind("127.0.0.1:8080")?
.run()
.await
So, what will be the signature of Rust function will be?
This is what impl trait is for: the closure type itself doesn't have a name, but it allows you to say "function returns some type satisfying these trait bounds" without naming the type. So it should be
fn list() -> impl Fn() -> ???
Where ??? should be replaced by the return type. See "impl Trait and closures" section in the link for another example.
But note that there still must be a single return type, so you can't e.g. return one of several closures depending on some condition, their types are different!

Rust - Passing Trait Objects to Threads [duplicate]

This question already has answers here:
Sending trait objects between threads in Rust
(1 answer)
Sharing a struct with trait objects as properties across threads
(1 answer)
How to clone a struct storing a boxed trait object?
(3 answers)
How do I clone a HashMap containing a boxed trait object?
(1 answer)
Closed 3 years ago.
I've been struggling with this for a while now and just going in circles, so I'm hoping someone can point out where I'm going wrong.
I'm playing with Actix Web, and setting up my first handlers - which is a simple Healthcheck of the system. So what I've got is:
A Healthcheck trait defining a healthcheck
A HealthcheckHandler struct that implements the Handler trait (This is an Actix Web concept) and contains a HashMap
A function that builds an App instance for the healthcheck routes (This is an Actix Web concept) by taking a HashMap<String, &Healthcheck>
​
When I try to build this I get errors that the trait "cannot be sent between threads safely".
I've tried with &Healthcheck, Box<Healthcheck>, Box<Healthcheck + Send> based on another answer on here, and even Mutex<&Healthcheck> all without luck, but all with subtly different errors. It all seems to be around needing to implement some combinations of Sync, Send and/or Clone, but I'm not sure how to get around that here.
Any pointers to what I should to fix this?
​
Actual example code:
pub trait Healthcheck {
fn check(&self) -> Result<String, String>;
}
struct HealthcheckHandler {
handlers: HashMap<String, Box<Healthcheck>>,
}
pub fn build_app(handlers: HashMap<String, Box<Healthcheck>>) -> App<()> {
let handler = HealthcheckHandler {
handlers: handlers,
};
App::new()
.prefix("/health")
.resource("", |r| {
r.get().h(handler);
})
}
pub fn start(settings: HashMap<String, String>) {
let mut healthchecks: HashMap<String, Box<Healthcheck>> = HashMap::new();
let server = server::new(|| { // <-- This is where the errors happen. This closure is used to spawn threads.
vec![
build_app(healthchecks).middleware(middleware::Logger::default())
]
});
}
Cheers

Why isn't a Box automatically Sized? [duplicate]

This question already has answers here:
What does "Sized is not implemented" mean?
(2 answers)
Why is the `Sized` bound necessary in this trait?
(2 answers)
How do you create a Box<dyn Trait>, or a boxed unsized value in general?
(3 answers)
Closed 5 years ago.
I am trying to implement a server using Mio and a reactor pattern. I want my Reactor to handle both TcpListeners and TcpStreams, so abstracting over that is my real challenge here.
I have a trait ReAgent that implements various handlers for informing the Reactor about changes in status, while Reactor informs each individual ReAgent about events important to that ReAgent. In turn, I'll have two different ReAgent types, one for accepting (TcpListeners) which will spawn clients (TcpStreams) to pass back to the Reactor for event handling. A very standard Reactor pattern for multiple server endpoints; I've written half a dozen of these in C/C++ over my career. Eliding details about my TokenPool, etc., here's where my headache lies:
pub struct Reactor<'a> {
poll: Poll,
agents: HashMap<Token, Box<ReAgent + 'a>>,
tokens: TokenPool,
}
impl<'a> Reactor<'a> {
pub fn add_agent<R: ReAgent + 'a>(&mut self, mut agent: Box<R>) -> Result<()>
{
if let Some(next_token) = self.tokens.pop() {
agent.set_token(next_token);
self.agents.insert(agent.get_token(), agent);
return Ok(())
}
bail!(ErrorKind::ConnectionsExhausted)
}
}
//...
/// Received a Box<ReAgent> (a Client);
/// add and start conversation
Some(boxed_agent) => self.add_agent(boxed_agent)
When I compile this, I get:
Some(boxed_agent) => self.add_agent(boxed_agent)
^^^^^^^^^ `reagent::ReAgent` does not have a constant size known at compile-time
... which I don't get at all. It's a Box. A Box has a known constant size at compile time. That's the whole point here of using Box to support a dynamic type object, right? The client has a known size, it's a concrete implementation of ReAgent.
What am I missing?
I know I'll probably have to use a RefCell later, since I'm mutating the ReAgent to set its polling token; that's for later, I just want to get past this.

Resources