snarkify_sdk/
lib.rs

1#![doc = include_str!("../README.md")]
2#![allow(unstable_name_collisions)]
3
4use std::{env, io};
5
6use crate::prover::ProofHandler;
7use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer};
8use cloudevents::Event;
9use std::time::Duration;
10use tracing_subscriber::filter::{EnvFilter, LevelFilter};
11use tracing_subscriber::fmt::format::FmtSpan;
12
13pub mod datetime_serde;
14pub mod prover;
15
16/// Default payload limit for incoming requests, 10MB
17const DEFAULT_PAYLOAD_LIMIT_BYTES: usize = 10 * 1024 * 1024;
18const DEFAULT_PORT: u16 = 8080;
19const DEFAULT_WORKER_NUM: usize = 1;
20/// Default duration a server keeps a connection open waiting for additional requests.
21const DEFAULT_KEEP_ALIVE_TIMEOUT_SECONDS: u64 = 3600;
22
23#[actix_web::main]
24pub async fn run<T: ProofHandler + Send + 'static>() -> io::Result<()> {
25    tracing_subscriber::fmt()
26        .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
27        .with_env_filter(
28            EnvFilter::builder()
29                .with_default_directive(LevelFilter::INFO.into())
30                .from_env_lossy(),
31        )
32        .with_ansi(false)
33        .with_level(true)
34        .with_target(true)
35        .json()
36        .flatten_event(true)
37        .try_init()
38        .unwrap();
39
40    let port: u16 = env::var("PORT")
41        .ok()
42        .and_then(|port| port.parse().ok())
43        .unwrap_or(DEFAULT_PORT);
44    let keep_alive_timeout_seconds: u64 = env::var("KEEP_ALIVE_TIMEOUT_SECONDS")
45        .ok()
46        .and_then(|timeout| timeout.parse().ok())
47        .unwrap_or(DEFAULT_KEEP_ALIVE_TIMEOUT_SECONDS);
48
49    // Create the HTTP server
50    HttpServer::new(|| {
51        App::new()
52            .app_data(web::PayloadConfig::new(DEFAULT_PAYLOAD_LIMIT_BYTES))
53            .app_data(web::JsonConfig::default().limit(DEFAULT_PAYLOAD_LIMIT_BYTES))
54            .wrap(actix_web::middleware::Logger::default())
55            .route(
56                "/",
57                web::post().to(|req: HttpRequest, mut event: Event| async move {
58                    // Adding custom headers to the event
59                    for (header_name, header_value) in req.headers() {
60                        let header_name_lower = header_name.as_str().to_lowercase();
61                        if header_name_lower.eq(prover::READ_INPUT_FROM_URL_HEADER) {
62                            if let Ok(value) = header_value.to_str() {
63                                event.set_extension(header_name_lower.as_str(), value.to_string());
64                            }
65                        }
66                    }
67                    T::handle(event).await
68                }),
69            )
70            .route("/", web::get().to(HttpResponse::MethodNotAllowed))
71            .route("/health/{_:(readiness|liveness)}", web::get().to(HttpResponse::Ok))
72    })
73    .keep_alive(Duration::from_secs(keep_alive_timeout_seconds))
74    .bind(("0.0.0.0", port))?
75    .workers(
76        env::var("WORKER_NUM")
77            .ok()
78            .and_then(|worker_num| worker_num.parse().ok())
79            .unwrap_or(DEFAULT_WORKER_NUM),
80    )
81    .run()
82    .await
83}