5 个版本
0.3.4 | 2024年6月26日 |
---|---|
0.3.3 | 2024年6月26日 |
0.3.1 | 2023年10月15日 |
0.2.2 | 2023年7月25日 |
0.2.1 | 2023年7月25日 |
463 在 Rust 模式 中
每月下载 59 次
84KB
1.5K SLoC
sod-actix-web
该包提供了通过 sod::Service
抽象,在 actix_web
上通过 Handler
实现的抽象。
处理器
ServiceHandler
充当一个 actix_web
Handler
,将请求调度到底层的 sod::AsyncService
或 sod::Service
实现。
服务 I/O
底层 AsyncService
的输入与 actix_web
中的本地 FromRequest
特性直接兼容。因此,一个 FromRequest
实现的元组可以作为 AsyncService
的输入处理。
底层 AsyncService
的输出必须实现来自 actix_web
的本地 Responder
特性。这意味着服务输出的所有类型都应与来自 actix_web
的所有输出类型兼容。这应包括简单的 String
或完整的 actix_web::HttpResponse
。
问候服务器示例
以下示例与默认的 actix_web
欢迎示例类似,但它使用此库提供的服务抽象
use actix_web::{web, App, HttpServer};
use sod::Service;
use sod_actix_web::ServiceHandler;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
struct GreetService;
impl Service for GreetService {
type Input = web::Path<String>;
type Output = String;
type Error = std::convert::Infallible;
fn process(&self, name: web::Path<String>) -> Result<Self::Output, Self::Error> {
Ok(format!("Hello {name}!"))
}
}
HttpServer::new(|| {
App::new().service(
web::resource("/greet/{name}").route(web::get().to(ServiceHandler::new(GreetService.into_async()))),
)
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
数学服务器示例
以下示例稍微复杂一些,展示了如何使用 AsyncService
和输入的元组
use std::{io::Error, io::ErrorKind};
use actix_web::{web, App, HttpServer};
use serde_derive::Deserialize;
use sod::{async_trait, AsyncService};
use sod_actix_web::ServiceHandler;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
#[derive(Debug, Deserialize)]
pub struct MathParams {
a: i64,
b: i64,
}
struct MathService;
#[async_trait]
impl AsyncService for MathService {
type Input = (web::Path<String>, web::Query<MathParams>);
type Output = String;
type Error = Error;
async fn process(
&self,
(func, params): (web::Path<String>, web::Query<MathParams>),
) -> Result<Self::Output, Self::Error> {
let value = match func.as_str() {
"add" => params.a + params.b,
"sub" => params.a - params.b,
"mul" => params.a * params.b,
"div" => params.a / params.b,
_ => return Err(Error::new(ErrorKind::Other, "invalid func")),
};
Ok(format!("{value}"))
}
}
HttpServer::new(|| {
App::new().service(
web::resource("/math/{func}").route(web::get().to(ServiceHandler::new(MathService))),
)
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
websockets
一个 actix_web
Handler
,它实例化 MutService
实现来处理单个会话。
会话工厂
WsSessionFactory
是此模块的入口点。它用于在客户端建立连接时创建会话服务,并充当一个 actix_web
Handler
。
WsSessionFactory
封装了用户需要定义的两个函数。
F: Fn(&HttpRequest) -> Result<S, Error> + 'static
- 用于生成会话服务的工厂,可以生成 Ok(Service
)、Ok(MutService
) 或 Err(Error
)。E: Fn(&mut S, S::Error)-> Result<(), S::Error>+ Unpin + 'static
- 错误处理器,用作回调来处理服务实现返回的错误。
Actix 配线
web::resource("/echo").route(web::get().to(WsSessionFactory::new(
|_req| Ok(EchoService),
|_service, err| println!("ERROR: {err}"),
))),
会话服务
会话服务工厂生成的底层会话 MutService
实现必须接受 WsSessionEvent
作为输入,并生成 Option<WsMessage>
作为输出。
WsSessionEvent
输入会通知会话会话生命周期事件和接收到的消息。Option<WsMessage>
输出可以选择向会话发送响应负载。
错误处理
WsSessionFactory
需要用户提供一个 Fn(&mut S, S::Error) -> Result<(), S::Error>
错误处理器函数,其中 S: MutService
或 S: Service
。由于 actix 在幕后使用异步线程池来处理 WebSocket 请求,Service
的 Err
结果无法在底层的 StreamHandler
外部传播。
用户完全可以通过错误处理器来处理服务返回的错误,而不是假设用户如何处理错误。当错误处理器返回 Ok(())
时,不会对底层的会话采取任何行动。当错误处理器返回 Err
时,会话将被关闭。
常见的错误处理器实现是记录错误并关闭会话
|_, err| {
log::error!("Session Error: {err}");
Err(err)
}
WsSendService
要在输入事件处理之外向会话生成消息,请使用初始 WsSessionEvent::Started
事件提供的 WsSendService
。您可以将 WsSendService
的所有权用于异步向服务外部生成消息,这将在会话关闭/关闭后返回一个 SendError
。
Ping/Pong
本框架会自动发送Pong响应,因此您可以在Ping/Pong响应的目的下忽略Ping请求。
回声示例
use std::convert::Infallible;
use actix_web::{web, App, HttpServer};
use sod::MutService;
use sod_actix_web::ws::{WsMessage, WsSessionEvent, WsSessionFactory};
#[actix_web::main]
async fn main() -> std::io::Result<()> {
struct EchoService;
impl MutService<WsSessionEvent> for EchoService {
type Output = Option<WsMessage>;
type Error = Infallible;
fn process(&mut self, event: WsSessionEvent) -> Result<Self::Output, Self::Error> {
Ok(match event {
WsSessionEvent::Started(_) => {
Some(WsMessage::Text("Welcome to EchoServer!".to_owned()))
}
WsSessionEvent::Message(message) => match message {
WsMessage::Binary(data) => Some(WsMessage::Binary(data)),
WsMessage::Text(text) => Some(WsMessage::Text(text)),
_ => None, // note: pongs are sent automatically
},
_ => None,
})
}
}
HttpServer::new(|| {
App::new().service(
web::resource("/echo").route(web::get().to(WsSessionFactory::new(
|_| Ok(EchoService),
|_, err| {
println!("ERROR: {err}");
Err(err)
},
))),
)
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
依赖项
约15–26MB
约460K SLoC