scufflecloud_email/
services.rs1use std::net::SocketAddr;
2use std::sync::Arc;
3
4use anyhow::Context;
5use axum::Extension;
6use axum::http::StatusCode;
7use rustls::pki_types::pem::PemObject;
8use rustls::pki_types::{CertificateDer, PrivateKeyDer};
9use tower_http::trace::TraceLayer;
10
11mod email;
12
13#[derive(Debug)]
14pub struct EmailSvc<G> {
15 _phantom: std::marker::PhantomData<G>,
16}
17
18impl<G> Default for EmailSvc<G> {
19 fn default() -> Self {
20 Self {
21 _phantom: std::marker::PhantomData,
22 }
23 }
24}
25
26impl<G: email_traits::Global> scuffle_bootstrap::Service<G> for EmailSvc<G> {
27 async fn run(self, global: Arc<G>, ctx: scuffle_context::Context) -> anyhow::Result<()> {
28 let email_svc = pb::scufflecloud::email::v1::email_service_server::EmailServiceServer::new(EmailSvc::<G>::default());
30
31 let reflection_v1_svc = tonic_reflection::server::Builder::configure()
32 .register_encoded_file_descriptor_set(pb::ANNOTATIONS_PB)
33 .build_v1()?;
34 let reflection_v1alpha_svc = tonic_reflection::server::Builder::configure()
35 .register_encoded_file_descriptor_set(pb::ANNOTATIONS_PB)
36 .build_v1alpha()?;
37
38 let mut builder = tonic::service::Routes::builder();
39 builder.add_service(email_svc);
40 builder.add_service(reflection_v1_svc);
41 builder.add_service(reflection_v1alpha_svc);
42 let grpc_router = builder.routes().prepare().into_axum_router();
43
44 let router = axum::Router::new()
45 .merge(grpc_router)
46 .layer(TraceLayer::new_for_http())
47 .layer(Extension(Arc::clone(&global)))
48 .fallback(StatusCode::NOT_FOUND);
49
50 let root_cert =
52 CertificateDer::from_pem_slice(global.mtls_root_cert_pem()).context("failed to parse mTLS root cert")?;
53 let cert = CertificateDer::from_pem_slice(global.mtls_cert_pem()).context("failed to parse mTLS cert")?;
54 let private_key =
55 PrivateKeyDer::from_pem_slice(global.mtls_private_key_pem()).context("failed to parse mTLS private key")?;
56
57 let mut root_cert_store = rustls::RootCertStore::empty();
58 root_cert_store
59 .add(root_cert.clone())
60 .context("failed to add mTLS root cert to root cert store")?;
61 let cert_chain = vec![cert, root_cert];
62
63 let rustls_client_verifier = rustls::server::WebPkiClientVerifier::builder(Arc::new(root_cert_store))
64 .build()
65 .context("failed to create client cert verifier")?;
66 let rustls_server_config = rustls::ServerConfig::builder()
67 .with_client_cert_verifier(rustls_client_verifier)
68 .with_single_cert(cert_chain, private_key)
69 .context("failed to create rustls ServerConfig")?;
70
71 scuffle_http::HttpServer::builder()
72 .tower_make_service_with_addr(router.into_make_service_with_connect_info::<SocketAddr>())
73 .bind(global.service_bind())
74 .ctx(ctx)
75 .rustls_config(rustls_server_config)
76 .build()
77 .run()
78 .await?;
79
80 Ok(())
81 }
82}