essential_builder_api/
endpoint.rs1use axum::{
4 extract::{Path, State},
5 response::IntoResponse,
6 Json,
7};
8use essential_builder_db as db;
9use essential_types::{solution::SolutionSet, ContentAddress};
10use std::sync::Arc;
11use thiserror::Error;
12
13#[derive(Debug, Error)]
15pub enum Error {
16 #[error("failed to decode from hex string: {0}")]
17 HexDecode(#[from] hex::FromHexError),
18 #[error("DB query failed: {0}")]
19 ConnPoolRusqlite(#[from] db::error::AcquireThenRusqliteError),
20 #[error("{0}")]
21 SystemTime(#[from] SystemTimeError),
22}
23
24#[derive(Debug, Error)]
26#[error("system time preceded `UNIX_EPOCH`")]
27pub struct SystemTimeError;
28
29impl IntoResponse for Error {
30 fn into_response(self) -> axum::response::Response {
31 use axum::http::StatusCode;
32 match self {
33 Error::ConnPoolRusqlite(e) => {
34 (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response()
35 }
36 Error::HexDecode(e) => (StatusCode::BAD_REQUEST, e.to_string()).into_response(),
37 Error::SystemTime(e) => {
38 (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response()
39 }
40 }
41 }
42}
43
44pub mod health_check {
46 pub const PATH: &str = "/";
47 pub async fn handler() {}
48}
49
50pub mod latest_solution_set_failures {
56 use essential_builder_types::SolutionSetFailure;
57 pub const MAX_LIMIT: u32 = 10;
58 use super::*;
59 pub const PATH: &str = "/latest-solution-set-failures/:solution_set_ca/:limit";
60 pub async fn handler(
61 State(state): State<crate::State>,
62 Path((solution_set_ca, limit)): Path<(String, u32)>,
63 ) -> Result<Json<Vec<SolutionSetFailure<'static>>>, Error> {
64 let solution_set_ca: ContentAddress = solution_set_ca.parse()?;
65 let limit = limit.min(MAX_LIMIT);
66 let failures = state
67 .conn_pool
68 .latest_solution_set_failures(solution_set_ca, limit)
69 .await?;
70 Ok(Json(failures))
71 }
72}
73
74pub mod list_solution_set_failures {
81 use super::*;
82 use essential_builder_types::SolutionSetFailure;
83 pub const PATH: &str = "/list-solution-set-failures/:start/:limit";
84 pub async fn handler(
85 State(state): State<crate::State>,
86 Path((offset, limit)): Path<(u32, u32)>,
87 ) -> Result<Json<Vec<SolutionSetFailure<'static>>>, Error> {
88 let failures = state
89 .conn_pool
90 .list_solution_set_failures(offset, limit)
91 .await?;
92 Ok(Json(failures))
93 }
94}
95
96pub mod submit_solution_set {
101 use super::*;
102 pub const PATH: &str = "/submit-solution-set";
103 pub async fn handler(
104 State(state): State<crate::State>,
105 Json(solution_set): Json<SolutionSet>,
106 ) -> Result<Json<ContentAddress>, Error> {
107 let solution_set = Arc::new(solution_set);
108 let timestamp = now_timestamp()?;
109 let solution_set_ca = state
110 .conn_pool
111 .insert_solution_set_submission(solution_set, timestamp)
112 .await?;
113 Ok(Json(solution_set_ca))
114 }
115}
116
117fn now_timestamp() -> Result<std::time::Duration, SystemTimeError> {
119 std::time::SystemTime::now()
120 .duration_since(std::time::UNIX_EPOCH)
121 .map_err(|_| SystemTimeError)
122}