Hello I want to pass the following AppState.
pub struct AppState {
clients: Vec<Client>,
}
This is how I the server:
async fn launch_server(app_config: CmkClientServerConfig) -> std::io::Result<()> {
HttpServer::new(|| App::new()
.data(Config::default().realm("Restricted area"))
.data(AppState {
clients: app_config.clients
})
.app_data(web::PayloadConfig::new(1000000))
.service(web::resource("/").route(web::post().to(index))))
.bind("127.0.0.1:8080")?
.workers(1)
.run()
.await
}
The Client entity struct I want to pass:
#[derive(Serialize, Deserialize, Debug)]
pub struct Client {
pub id: String,
pub password: String,
}
I hope it is clear what I am trying to accomplish. Now to my Problem. Compiler says:
the trait bound
entities::CmkClientServerConfig: std::clone::Clone
is not satisfied in `[closure@src/server.rs:25:21: 31:66 app_config:entities::CmkClientServerConfig]
Maybe this thing needs to be cloned because of async execution. So added "#[derive(Clone)]" to CmkClientServerConfig struct and the Client struct.
Then a get this error message:
error[E0507]: cannot move out of `app_config.clients`, as `app_config` is a captured variable in an `Fn` closure
--> src/server.rs:29:22
|
23 | async fn launch_server(app_config: CmkClientServerConfig) -> std::io::Result<()> {
| ---------- captured outer variable
...
29 | clients: app_config.clients
| ^^^^^^^^^^^^^^^^^^ move occurs because `app_config.clients` has type `std::vec::Vec<entities::Client>`, which does not implement the `Copy` trait
error[E0507]: cannot move out of `app_config.clients`, as `app_config` is a captured variable in an `Fn` closure
--> src/server.rs:29:22
|
23 | async fn launch_server(app_config: CmkClientServerConfig) -> std::io::Result<()> {
| ---------- captured outer variable
...
29 | clients: app_config.clients
| ^^^^^^^^^^^^^^^^^^ move occurs because `app_config.clients` has type `std::vec::Vec<entities::Client>`, which does not implement the `Copy` trait
My question is how to do it correctly, how can I make a clone possible.
Thanks for your help.
Both the API docs and the Get Started docs explain:
HttpServer
accepts an application factory rather than an application instance. AnHttpServer
constructs an application instance for each thread. Therefore, application data must be constructed multiple times. If you want to share data between different threads, a shareable object should be used, e.g.Send + Sync
.
If your clients
list is only initialized on server start and otherwise stays immutable then you can just clone it in your app factory function, but if it's suppose to be mutable then you must wrap it in a Arc<Mutex<T>>
so that it can safely be cloned, shared, and mutated across the multiple threads running your app.
If the clients
list does not change then update your client to derive
the Clone
trait:
#[derive(Serialize, Deserialize, Debug, Clone)] // Clone added here
pub struct Client {
pub id: String,
pub password: String,
}
And then update your app factory function to move
your app_config
into itself so you can repeatedly call clone
on clients
:
async fn launch_server(app_config: CmkClientServerConfig) -> std::io::Result<()> {
HttpServer::new(move || App::new() // move added here
.data(Config::default().realm("Restricted area"))
.data(AppState {
clients: app_config.clients.clone() // clone() added here
})
.app_data(web::PayloadConfig::new(1000000))
.service(web::resource("/").route(web::post().to(index))))
.bind("127.0.0.1:8080")?
.workers(1)
.run()
.await
}