Towerミドルウェアとの互換性

Salvoはtower-compat機能を通じて、Towerエコシステムとの互換性サポートを提供します。詳細なAPIについてはドキュメントを参照してください

Towerのコアコンセプト

Towerはサービス抽象化ライブラリで、主に2つのコアトレイトに基づいています:

Serviceトレイト

pub trait Service<Request> {
    type Response;
    type Error;
    type Future: Future<Output = Result<Self::Response, Self::Error>>;

    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>>;
    fn call(&mut self, req: Request) -> Self::Future;
}

Serviceはリクエストを処理してレスポンスを返す役割を担い、Salvoのハンドラーと類似しています。

Layerトレイト

pub trait Layer<S> {
    type Service;
    fn layer(&self, inner: S) -> Self::Service;
}

Layerはサービスをラップして追加機能を提供するために使用され、Salvoのミドルウェアと類似しています。

Salvoの互換性サポート

SalvoはTowerエコシステムとの互換性を実現するために、2つの重要なトレイト実装を提供します:

  • TowerLayerCompat:TowerのLayerをSalvoのHandlerに変換し、Hoop(ミドルウェア)として使用可能にします
  • TowerServiceCompat:TowerのServiceをSalvoのHandlerに変換します

使用例:

// TowerのRateLimitLayerを使用し、compat()メソッドでSalvo互換形式に変換
let limit = RateLimitLayer::new(5, Duration::from_secs(30)).compat();
let router = Router::new().hoop(limit).get(hello);

サンプルコード

main.rs
Cargo.toml
use salvo::prelude::*;
use tokio::time::Duration;
use tower::limit::RateLimitLayer;

#[handler]
async fn hello() -> &'static str {
    "Hello World"
}

#[tokio::main]
async fn main() {
    tracing_subscriber::fmt().init();

    let limit = RateLimitLayer::new(5, Duration::from_secs(30)).compat();
    let acceptor = TcpListener::new("0.0.0.0:8698").bind().await;
    let router = Router::new().hoop(limit).get(hello);
    Server::new(acceptor).serve(router).await;
}