我正在尝试在Rust中开发基于超级服务器的应用程序。有一个INI文件保存配置,如绑定IP,数据库等。
我不想解析每个请求的INI文件,可以保留配置数据直到服务器重新启动。如何将已解析数据的结构提供给请求处理程序?
我尝试了几种使用std::sync::Arc
的方法,但是到目前为止唯一可行的方法是使用static
,但是我想避免使用unsafe
块。
这是一个完整的(无效)示例:
Cargo.toml
[package]
name = "demo"
version = "0.1.0"
edition = "2018"
[dependencies]
hyper = "0.12"
rust-ini = "0.13"
demo.ini
[Demo]
value="some value"
src / main.rs
extern crate hyper;
extern crate ini;
use hyper::rt::{self, Future};
use hyper::service::service_fn_ok;
use hyper::{Body, Request, Response, Server};
use ini::Ini;
use std::sync::Arc;
pub struct Config {
pub value: String,
}
fn request_handler(req: Request<Body>, config: &Config) -> Response<Body> {
let user_agent = req.headers()["user-agent"].to_str().unwrap();
println!("user agent: {:?}", &user_agent);
println!("config value: {:?}", &config.value);
Response::new(Body::from(""))
}
fn read_ini(config_file: &str) -> Arc<Config> {
match Ini::load_from_file(config_file) {
Ok(c) => {
let demo_section = c.section(Some("Demo".to_owned())).unwrap();
let value = match demo_section.get("value") {
Some(v) => v,
None => {
println!("Error reading ini");
std::process::exit(-1)
}
};
Arc::<Config>::new(Config {
value: value.to_string(),
})
}
_ => {
eprintln!("CRITICAL: Could not open config file: {:?}", &config_file);
std::process::exit(-1)
}
}
}
fn main() {
let cfg = read_ini("demo.ini");
let addr = "127.0.0.1:3000".parse().unwrap();
let server = Server::bind(&addr)
.serve(|| service_fn_ok(move |req: Request<Body>| request_handler(req, &cfg.clone())))
.map_err(|e| println!("server error: {}", e));
rt::run(server);
}
错误
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
--> src/main.rs:49:16
|
49 | .serve(|| service_fn_ok(move |req: Request<Body>| request_handler(req, &cfg.clone())))
| ^^^^^^^^^^^^^^^^^-------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| | |
| | closure is `FnOnce` because it moves the variable `cfg` out of its environment
| this closure implements `FnOnce`, not `Fn`
答案 0 :(得分:4)
请仔细观察serve
中的两个关闭级别。
用service_fn_ok
定义的第二级闭包(传递给move
),即使在对{{1}的任何调用之前,也将尝试将唯一的实例cfg
移入其中}。
如果不进行克隆,则无法多次执行此移动,因此该闭包将仅实现clone()
。这是双向移动的情况:第二个闭包希望在只能允许一次执行的环境中接收资源。
为解决此问题,我们希望第一个闭包收到FnOnce
,并在每次都克隆它。
cfg