首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >缺少特征`actix_service::Service` --> src/midleware.rs的泛型:57:8

缺少特征`actix_service::Service` --> src/midleware.rs的泛型:57:8
EN

Stack Overflow用户
提问于 2021-03-25 09:46:23
回答 1查看 357关注 0票数 1

我如何实现特征?在运行cargo build时,我得到了这个错误。我还注释掉了type Request = ServiceRequest;。这会对代码有什么影响?我在Cargo.toml中将actix-service更新为2.0.0-beta.2,然后构建失败。

代码语言:javascript
复制
error[E0107]: missing generics for trait `actix_service::Service`
  --> src/middleware.rs:57:8
   |
57 |     S: Service<Response = ServiceResponse<B>, Error = Error> + 'static,
   |        ^^^^^^^ expected 1 type argument
   |
note: trait defined here, with 1 type parameter: `Req`
  --> /home/samarpan/.cargo/registry/src/github.com-1ecc6299db9ec823/actix-service-2.0.0-beta.5/src/lib.rs:85:11
   |
85 | pub trait Service<Req> {
   |           ^^^^^^^ ---
help: use angle brackets to add missing type argument
   |
57 |     S: Service<Req><Response = ServiceResponse<B>, Error = Error> + 'static,
   |               ^^^^^

这是我的middleware.rs -

代码语言:javascript
复制
#![allow(clippy::type_complexity)]

use std::cell::RefCell;
use std::ops::{Deref, DerefMut};
use std::pin::Pin;
use std::rc::Rc;
use std::sync::Arc;
use std::task::{Context, Poll};

use futures::future::{ok, Ready};
use futures::Future;

use actix_service::{Service, Transform};
use actix_web::{
    dev::ServiceRequest, dev::ServiceResponse, Error, HttpMessage, HttpResponse, Result,
};

use casbin::prelude::{TryIntoAdapter, TryIntoModel};
use casbin::{CachedEnforcer, CoreApi, Result as CasbinResult};

#[cfg(feature = "runtime-tokio")]
use tokio::sync::RwLock;

#[cfg(feature = "runtime-async-std")]
use async_std::sync::RwLock;

#[derive(Clone)]
pub struct CasbinVals {
    pub subject: String,
    pub domain: Option<String>,
}

#[derive(Clone)]
pub struct CasbinService {
    enforcer: Arc<RwLock<CachedEnforcer>>,
}

impl CasbinService {
    pub async fn new<M: TryIntoModel, A: TryIntoAdapter>(m: M, a: A) -> CasbinResult<Self> {
        let enforcer: CachedEnforcer = CachedEnforcer::new(m, a).await?;
        Ok(CasbinService {
            enforcer: Arc::new(RwLock::new(enforcer)),
        })
    }

    pub fn get_enforcer(&mut self) -> Arc<RwLock<CachedEnforcer>> {
        self.enforcer.clone()
    }

    pub fn set_enforcer(e: Arc<RwLock<CachedEnforcer>>) -> CasbinService {
        CasbinService { enforcer: e }
    }
}

impl<S, B> Transform<S, B> for CasbinService
where
    S: Service<Response = ServiceResponse<B>, Error = Error> + 'static,
    S::Future: 'static,
    B: 'static,
{
    //type Request = ServiceRequest;
    type Response = ServiceResponse<B>;
    type Error = Error;
    type InitError = ();
    type Transform = CasbinMiddleware<S>;
    type Future = Ready<Result<Self::Transform, Self::InitError>>;

    fn new_transform(&self, service: S) -> Self::Future {
        ok(CasbinMiddleware {
            enforcer: self.enforcer.clone(),
            service: Rc::new(RefCell::new(service)),
        })
    }
}
impl Deref for CasbinService {
    type Target = Arc<RwLock<CachedEnforcer>>;

    fn deref(&self) -> &Self::Target {
        &self.enforcer
    }
}

impl DerefMut for CasbinService {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.enforcer
    }
}

pub struct CasbinMiddleware<S> {
    service: Rc<RefCell<S>>,
    enforcer: Arc<RwLock<CachedEnforcer>>,
}

impl<S, B> Service<B> for CasbinMiddleware<S>
where
    S: Service<Response = ServiceResponse<B>, Error = Error> + 'static,
    S::Future: 'static,
    B: 'static,
{
    //type Request = ServiceRequest;
    type Response = ServiceResponse<B>;
    type Error = Error;
    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;

    fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        self.service.poll_ready(cx)
    }

    fn call(&mut self, req: ServiceRequest) -> Self::Future {
        let cloned_enforcer = self.enforcer.clone();
        let mut srv = self.service.clone();

        Box::pin(async move {
            let path = req.path().to_string();
            let action = req.method().as_str().to_string();
            let option_vals = req.extensions().get::<CasbinVals>().map(|x| x.to_owned());
            let vals = match option_vals {
                Some(value) => value,
                None => {
                    return Ok(req.into_response(HttpResponse::Unauthorized().finish().into_body()))
                }
            };
            let subject = vals.subject.clone();

            if !vals.subject.is_empty() {
                if let Some(domain) = vals.domain {
                    let mut lock = cloned_enforcer.write().await;
                    match lock.enforce_mut(vec![subject, domain, path, action]) {
                        Ok(true) => {
                            drop(lock);
                            srv.call(req).await
                        }
                        Ok(false) => {
                            drop(lock);
                            Ok(req.into_response(HttpResponse::Forbidden().finish().into_body()))
                        }
                        Err(_) => {
                            drop(lock);
                            Ok(req.into_response(HttpResponse::BadGateway().finish().into_body()))
                        }
                    }
                } else {
                    let mut lock = cloned_enforcer.write().await;
                    match lock.enforce_mut(vec![subject, path, action]) {
                        Ok(true) => {
                            drop(lock);
                            srv.call(req).await
                        }
                        Ok(false) => {
                            drop(lock);
                            Ok(req.into_response(HttpResponse::Forbidden().finish().into_body()))
                        }
                        Err(_) => {
                            drop(lock);
                            Ok(req.into_response(HttpResponse::BadGateway().finish().into_body()))
                        }
                    }
                }
            } else {
                Ok(req.into_response(HttpResponse::Unauthorized().finish().into_body()))
            }
        })
    }
}

原始回购链接- https://github.com/casbin-rs/actix-casbin-auth

我的更改- https://github.com/smrpn/actix-casbin-auth/tree/feature/bumpactixweb

EN

回答 1

Stack Overflow用户

发布于 2021-03-26 04:00:52

Service特征有一个必需的泛型类型参数,但您没有设置它。我们在实现Service (通过将其从Service更改为Service<B>)和Transform (通过将其从Transform<S>更改为Transform<S, T>)时做到了这一点,但是在您使用Service作为特征界限(即S: Service<...>)的情况下,您并没有更改它。遵循其他也应该从S: Service<Request = ...>更改为S: Service<B, Request = ...>的更改。

请注意,这将修复您提到的错误,但不会修复其他错误。我不熟悉actix-service,但从我看到的保持代码与之前的一致来看,您应该将Transform<S>更改为Transform<S, ServiceRequest>,将Service更改为Service<ServiceRequest>,将S: Service<Response=...>更改为S: Service<ServiceRequest, Response=...>

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66791910

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档