Пожизненная проблема с Actix Web - PullRequest
0 голосов
/ 25 ноября 2018

Я внедряю промежуточное ПО с Actix-web, и у меня возникла проблема с временем жизни, которую я не смог выяснить.

extern crate actix_web;

use actix_web::actix::{Actor, Addr, Context, System};
use actix_web::middleware::Middleware;
use actix_web::{http, server, App, HttpRequest, Responder};
use std::collections::HashMap;

pub struct CacheActor {
    caches: HashMap<String, String>,
}

impl CacheActor {
    pub fn new() -> Self {
        CacheActor {
            caches: HashMap::new(),
        }
    }
}

impl Actor for CacheActor {
    type Context = Context<Self>;
}

fn create_resource(req: HttpRequest, addr: &Addr<CacheActor>) -> impl Responder {
    unimplemented!();
    format!("Unimplemented")
}

fn list_resources(req: HttpRequest, addr: &Addr<CacheActor>) -> impl Responder {
    unimplemented!();
    format!("Unimplemented")
}

pub trait TusMiddlewareTrait {
    fn with_tus(self, addr: &Addr<CacheActor>) -> App;
}

impl TusMiddlewareTrait for App {
    fn with_tus(self, addr: &Addr<CacheActor>) -> App {
        self.route("/files", http::Method::GET, |req| list_resources(req, addr))
            .route("/files", http::Method::POST, |req| {
                create_resource(req, addr)
            })
    }
}

fn main() {
    let system = System::new("Example");
    let cache_addr = CacheActor::new().start();

    server::new(|| App::new().with_tus(&cache_addr))
        .bind("127.0.0.1:8080")
        .unwrap()
        .run();

    system.run();
}

Я получаю следующую ошибку:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/tus/middleware.rs:84:49
   |
84 |             .route("/files", http::Method::GET, |req| list_resources(req, addr))
   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 81:5...
  --> src/tus/middleware.rs:81:5
   |
81 | /     fn with_tus(self, addr: &actix::Addr<cache::CacheActor>) -> App {
82 | |         self.middleware(TusMiddleware)
83 | |             .route("/files", http::Method::OPTIONS, tus_information)
84 | |             .route("/files", http::Method::GET, |req| list_resources(req, addr))
...  |
87 | |             })
88 | |     }
   | |_____^
   = note: ...so that the types are compatible:
           expected &&actix::address::Addr<tus::cache::CacheActor>
              found &&actix::address::Addr<tus::cache::CacheActor>
   = note: but, the lifetime must be valid for the static lifetime...

Что касается того, что я понимаю, я передаю cache_addr как ссылку на функцию with_tus.Внутри каждого закрытия в route, addr также есть ссылка.

Я не понимаю, почему компилятор сказал the lifetime cannot outlive the anonymous lifetime #1.Из того, что я могу сказать, это то, что cache_addr по-прежнему переживает закрытиеСрок службы должен составлять до system.run() строки.Может кто-то просветить меня?

Редактировать :

Я обновил код выше до MCVE (по крайней мере до такой степени, что достаточно просто скопировать весь код и запуститьсборка груза при сохранении того же сообщения об ошибке).Я не могу запустить его на ржавой площадке.На данный момент он не поддерживает actix ящик.Я попытался уменьшить это дальше, но это дает мне другую ошибку.Извините, я довольно новичок в Rust.

У меня два вопроса, мне нравится понимать, что говорит мне ошибка.Во-вторых, мне нравится знать, как правильно сделать это с actix, поэтому пример кода зависит от actix.

1 Ответ

0 голосов
/ 28 ноября 2018

Посмотрите на App::route подпись :

pub fn route<T, F, R>(self, path: &str, method: Method, f: F) -> App<S> 
where
    F: WithFactory<T, S, R>,
    R: Responder + 'static,
    T: FromRequest<S> + 'static,

F универсальный зависит от T и R, которые в свою очередь имеют 'static срок службы.

Ваше закрытие фиксирует &Addr<CacheActor>, что оно недопустимо в течение 'static времени жизни, и это приводит к ошибке.

Я вижу возможность использовать App "Состояние",непосредственно из документов :

Состояние приложения используется всеми маршрутами и ресурсами в одном приложении.При использовании субъекта http доступ к состоянию можно получить с помощью HttpRequest :: state () только для чтения, но внутреннюю изменчивость с помощью RefCell можно использовать для достижения изменчивости состояния.Состояние также доступно для предикатов и промежуточных программ сопоставления маршрутов.

В этом случае должно быть что-то вроде:

extern crate actix_web;

use actix_web::actix::{Actor, Addr, Context, System};
use actix_web::{http, server, App, HttpRequest, HttpResponse, Result};
use std::collections::HashMap;
use actix_web::dev::Handler;

#[derive(Clone)]
pub struct CacheActor {
    caches: HashMap<String, String>,
}

impl CacheActor {
    pub fn new() -> Self {
        CacheActor {
            caches: HashMap::new(),
        }
    }
}

impl Actor for CacheActor {
    type Context = Context<Self>;
}

impl<S> Handler<S> for CacheActor {
    type Result = String;

    fn handle(&self, _req: &HttpRequest<S>) -> Self::Result {
        unimplemented!();
    }
}

fn list_resources(req: &HttpRequest<Addr<CacheActor>>) -> Result<HttpResponse> {
    Ok(HttpResponse::Found()
        .header(http::header::LOCATION, format!("hello {}", req.path()))
        .finish())
}

fn main() {
    let system = System::new("Example");

    server::new(|| {
        let cache_addr = CacheActor::new().start();
        App::with_state(cache_addr)
            .resource("/world", |r| r.method(http::Method::GET).f(list_resources))
    })
    .bind("127.0.0.1:8080")
    .unwrap()
    .run();

    system.run();
}
...