Skip to main content

sms_web_actix/
lib.rs

1use actix_web::{web, HttpRequest, HttpResponse, Result};
2use bytes::Bytes;
3use sms_core::{Headers, InboundRegistry};
4use sms_web_generic::{HeaderConverter, ResponseConverter, WebhookProcessor};
5
6#[derive(Clone)]
7pub struct AppData {
8    pub registry: InboundRegistry,
9}
10
11/// Actix-web-specific header converter
12pub struct ActixHeaderConverter;
13
14impl HeaderConverter for ActixHeaderConverter {
15    type HeaderType = HttpRequest;
16
17    fn to_generic_headers(req: &Self::HeaderType) -> Headers {
18        req.headers()
19            .iter()
20            .map(|(k, v)| {
21                (
22                    k.as_str().to_string(),
23                    v.to_str().unwrap_or_default().to_string(),
24                )
25            })
26            .collect()
27    }
28}
29
30/// Actix-web-specific response converter
31pub struct ActixResponseConverter;
32
33impl ResponseConverter for ActixResponseConverter {
34    type ResponseType = HttpResponse;
35
36    fn from_webhook_response(response: sms_core::WebhookResponse) -> Self::ResponseType {
37        let mut builder = HttpResponse::build(
38            actix_web::http::StatusCode::from_u16(response.status.as_u16())
39                .unwrap_or(actix_web::http::StatusCode::INTERNAL_SERVER_ERROR),
40        );
41
42        builder
43            .content_type(response.content_type.as_str())
44            .body(response.body)
45    }
46}
47
48/// Unified webhook handler for Actix-web
49pub async fn unified_webhook(
50    path: web::Path<String>,
51    req: HttpRequest,
52    body: Bytes,
53    data: web::Data<AppData>,
54) -> Result<HttpResponse> {
55    let provider = path.into_inner();
56    let processor = WebhookProcessor::new(data.registry.clone());
57    let generic_headers = ActixHeaderConverter::to_generic_headers(&req);
58    let response = processor.process_webhook(&provider, generic_headers, &body);
59    Ok(ActixResponseConverter::from_webhook_response(response))
60}
61
62/// Helper function to configure Actix routes
63pub fn configure_routes(cfg: &mut web::ServiceConfig) {
64    cfg.route("/webhooks/{provider}", web::post().to(unified_webhook));
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70    use actix_web::{test, App};
71
72    #[actix_web::test]
73    async fn webhook_route_compiles() {
74        let registry = InboundRegistry::new();
75        let app_data = AppData { registry };
76
77        let _app = test::init_service(
78            App::new()
79                .app_data(web::Data::new(app_data))
80                .configure(configure_routes),
81        )
82        .await;
83    }
84}