Hello
I have the following struct:
// Wrapper for Config
#[derive(Clone)]
pub struct MyConfig {
pub config: std::collections::HashMap<String, String>,
}
impl MyConfig {
pub async fn get_config(mysql: &web::Data<MySQL>) -> std::collections::HashMap<String, String> {
let mut result = sqlx::query("SELECT config, value FROM config").fetch(&mysql.conn);
let mut config = std::collections::HashMap::new();
while let Some(row) = result.try_next().await.unwrap() {
config.insert(
row.try_get("config").unwrap(),
row.try_get("value").unwrap(),
);
}
config
}
pub async fn update(config: String, value: String, mysql: &web::Data<MySQL>) -> bool {
let result = sqlx::query("UPDATE config SET value=? WHERE config=?")
.bind(&value)
.bind(&config)
.execute(&mysql.conn)
.await;
match result {
Err(e) => {
println!(
"Error [in update() of struct MyConfig, main.rs]: {}",
e
);
false
}
Ok(r) => r.rows_affected() > 0,
}
}
}
This struct is used to get the configuration values from a database. I pass this configuration as app_data
in Actix-web.
let myconfig = web::Data::new(MyConfig {
config: MyConfig::get_config(&mysql).await,
});
...
.app_data(web::Data::clone(&myconfig))
This way I can access it everywhere using myconfig: web::Data<MyConfig>
in my route functions.
The problem is that the configuration can be updated. And when that happens the app_data
needs to be updated without the application needing to be restarted.
I don't know how to solve this. I thought of Mutex
. Like this:
let myconfig = web::Data::new(Mutex::new(MyConfig {
config: MyConfig::get_config(&mysql).await,
}));
in route functions:
myconfig: web::Data<Mutex<MyConfig>>,
I thought I could keep the configuration mutable. But the problem is that it is impossible to retrieve the value of a Mutex
.
I for example have this template:
#[derive(Template)]
#[template(path = "master-dashboard/config.html")]
pub struct Config {
pub config: web::Data<Mutex<MyConfig>>,
}
I try to pass my config to that using
let mut s = templates::master_dashboard::Config {
config: myconfig.lock().unwrap(),
};
Ok(HttpResponse::Ok()
.content_type("text/html")
.body(s.render().unwrap()))
This yields:
mismatched types expected struct `actix_web::web::Data<std::sync::Mutex<MyConfig>>` found struct `std::sync::MutexGuard<'_, MyConfig>`
How would I solve this issue?
EDIT:
This compiles:
let myconfig = web::Data::new(Mutex::new(MyConfig {
config: MyConfig::get_config(&mysql).await,
}));
#[derive(Template)]
#[template(path = "master-dashboard/config.html")]
pub struct Config {
pub config: web::Data<Mutex<MyConfig>>,
}
pub async fn config_update(
session: Session,
data: web::Form<UpdateConfigForm>,
mysql: web::Data<MySQL>,
myconfig: web::Data<Mutex<MyConfig>>,
) -> Result<HttpResponse> {
...
MyConfig::update(
"commission".to_string(),
data.commission.to_string(),
&mysql,
)
.await;
let mut x = myconfig.clone();
let mut myconfig = x.lock().unwrap();
myconfig.config = MyConfig::get_config(&mysql).await;
let mut s = templates::master_dashboard::Config {
config: myconfig,
};
Ok(HttpResponse::Ok()
.content_type("text/html")
.body(s.render().unwrap()))
}
But crashes my application when the update form is sent. My application won't run anymore.