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
11pub 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
30pub 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
48pub 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
62pub 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}