demystify_web/
util.rs

1use std::{
2    collections::HashMap,
3    sync::{Arc, Mutex, OnceLock},
4};
5
6use anyhow::bail;
7use axum::{
8    http::StatusCode,
9    response::{IntoResponse, Response},
10};
11
12use axum_session::{Session, SessionNullPool};
13use demystify::problem::planner::PuzzlePlanner;
14use uuid::Uuid;
15
16// Make our own error that wraps `anyhow::Error`.
17pub struct AppError(anyhow::Error);
18
19// Tell axum how to convert `AppError` into a response.
20impl IntoResponse for AppError {
21    fn into_response(self) -> Response {
22        (
23            StatusCode::INTERNAL_SERVER_ERROR,
24            format!("Something went wrong: {}", self.0),
25        )
26            .into_response()
27    }
28}
29
30// This enables using `?` on functions that return `Result<_, anyhow::Error>` to turn them into
31// `Result<_, AppError>`. That way you don't need to do that manually.
32impl<E> From<E> for AppError
33where
34    E: Into<anyhow::Error>,
35{
36    fn from(err: E) -> Self {
37        Self(err.into())
38    }
39}
40
41fn solver_global(
42    uuid: Uuid,
43    set_solver: Option<Arc<Mutex<PuzzlePlanner>>>,
44) -> Option<Arc<Mutex<PuzzlePlanner>>> {
45    type GlobalPuzzleStorage = Mutex<HashMap<Uuid, Arc<Mutex<PuzzlePlanner>>>>;
46    static SOLVER: OnceLock<GlobalPuzzleStorage> = OnceLock::new();
47    let m = SOLVER.get_or_init(|| Mutex::new(HashMap::new()));
48
49    if let Some(solver) = set_solver {
50        m.lock().unwrap().insert(uuid, solver);
51        None
52    } else {
53        m.lock().unwrap().get(&uuid).cloned()
54    }
55}
56
57/// Get global solver from uuid
58pub fn get_solver_global(
59    session: &Session<SessionNullPool>,
60) -> anyhow::Result<Arc<Mutex<PuzzlePlanner>>> {
61    let uuid = session.get_session_id().uuid();
62    let solver = solver_global(uuid, None);
63    if let Some(solver) = solver {
64        Ok(solver)
65    } else {
66        bail!("No solver -- have you uploaded files?");
67    }
68}
69
70pub fn set_solver_global(session: &Session<SessionNullPool>, set_solver: PuzzlePlanner) {
71    let uuid = session.get_session_id().uuid();
72    solver_global(uuid, Some(Arc::new(Mutex::new(set_solver))));
73}