mirror of
https://github.com/ellmau/adf-obdd.git
synced 2025-12-21 09:49:38 +01:00
Compare commits
1 Commits
46ad9eb3fa
...
a0ad716b28
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0ad716b28 |
@ -28,4 +28,4 @@ futures-util = "0.3.28"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
cors_for_local_development = []
|
cors_for_local_development = []
|
||||||
mock_long_computations = []
|
|
||||||
|
|||||||
@ -1,21 +1,18 @@
|
|||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
#[cfg(feature = "mock_long_computations")]
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use actix_identity::Identity;
|
use actix_identity::Identity;
|
||||||
use actix_web::rt::spawn;
|
use actix_web::rt::spawn;
|
||||||
use actix_web::rt::task::spawn_blocking;
|
use actix_web::rt::task::spawn_blocking;
|
||||||
use actix_web::rt::time::timeout;
|
use actix_web::rt::time::timeout;
|
||||||
use actix_web::{delete, get, post, put, web, HttpMessage, HttpRequest, HttpResponse, Responder};
|
use actix_web::{get, post, put, web, HttpMessage, HttpRequest, HttpResponse, Responder};
|
||||||
use adf_bdd::datatypes::adf::VarContainer;
|
use adf_bdd::datatypes::adf::VarContainer;
|
||||||
use adf_bdd::datatypes::{BddNode, Term, Var};
|
use adf_bdd::datatypes::{BddNode, Term, Var};
|
||||||
use futures_util::{FutureExt, TryStreamExt};
|
|
||||||
use mongodb::bson::doc;
|
use mongodb::bson::doc;
|
||||||
use mongodb::bson::{to_bson, Bson};
|
use mongodb::bson::{to_bson, Bson};
|
||||||
use mongodb::results::DeleteResult;
|
|
||||||
use names::{Generator, Name};
|
use names::{Generator, Name};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use futures_util::FutureExt;
|
||||||
|
|
||||||
use adf_bdd::adf::{Adf, DoubleLabeledGraph};
|
use adf_bdd::adf::{Adf, DoubleLabeledGraph};
|
||||||
use adf_bdd::adfbiodivine::Adf as BdAdf;
|
use adf_bdd::adfbiodivine::Adf as BdAdf;
|
||||||
@ -55,27 +52,7 @@ impl From<AcAndGraph> for Bson {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default, Deserialize, Serialize)]
|
type AcsAndGraphsOpt = Option<Vec<AcAndGraph>>;
|
||||||
pub(crate) enum OptionWithError<T> {
|
|
||||||
Some(T),
|
|
||||||
Error(String),
|
|
||||||
#[default]
|
|
||||||
None,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> OptionWithError<T> {
|
|
||||||
fn is_some(&self) -> bool {
|
|
||||||
matches!(self, Self::Some(_))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Serialize> From<OptionWithError<T>> for Bson {
|
|
||||||
fn from(source: OptionWithError<T>) -> Self {
|
|
||||||
to_bson(&source).expect("Serialization should work")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type AcsAndGraphsOpt = OptionWithError<Vec<AcAndGraph>>;
|
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Serialize)]
|
#[derive(Default, Deserialize, Serialize)]
|
||||||
pub(crate) struct AcsPerStrategy {
|
pub(crate) struct AcsPerStrategy {
|
||||||
@ -88,7 +65,7 @@ pub(crate) struct AcsPerStrategy {
|
|||||||
pub(crate) stable_nogood: AcsAndGraphsOpt,
|
pub(crate) stable_nogood: AcsAndGraphsOpt,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub(crate) struct VarContainerDb {
|
pub(crate) struct VarContainerDb {
|
||||||
names: Vec<String>,
|
names: Vec<String>,
|
||||||
mapping: HashMap<String, String>,
|
mapping: HashMap<String, String>,
|
||||||
@ -124,7 +101,7 @@ impl From<VarContainerDb> for VarContainer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub(crate) struct BddNodeDb {
|
pub(crate) struct BddNodeDb {
|
||||||
var: String,
|
var: String,
|
||||||
lo: String,
|
lo: String,
|
||||||
@ -153,7 +130,7 @@ impl From<BddNodeDb> for BddNode {
|
|||||||
|
|
||||||
type SimplifiedBdd = Vec<BddNodeDb>;
|
type SimplifiedBdd = Vec<BddNodeDb>;
|
||||||
|
|
||||||
#[derive(Clone, Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub(crate) struct SimplifiedAdf {
|
pub(crate) struct SimplifiedAdf {
|
||||||
pub(crate) ordering: VarContainerDb,
|
pub(crate) ordering: VarContainerDb,
|
||||||
pub(crate) bdd: SimplifiedBdd,
|
pub(crate) bdd: SimplifiedBdd,
|
||||||
@ -170,15 +147,13 @@ impl SimplifiedAdf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type SimplifiedAdfOpt = OptionWithError<SimplifiedAdf>;
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub(crate) struct AdfProblem {
|
pub(crate) struct AdfProblem {
|
||||||
pub(crate) name: String,
|
pub(crate) name: String,
|
||||||
pub(crate) username: String,
|
pub(crate) username: String,
|
||||||
pub(crate) code: String,
|
pub(crate) code: String,
|
||||||
pub(crate) parsing_used: Parsing,
|
pub(crate) parsing_used: Parsing,
|
||||||
pub(crate) adf: SimplifiedAdfOpt,
|
pub(crate) adf: SimplifiedAdf,
|
||||||
pub(crate) acs_per_strategy: AcsPerStrategy,
|
pub(crate) acs_per_strategy: AcsPerStrategy,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,26 +299,12 @@ async fn add_adf_problem(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let adf_problem: AdfProblem = AdfProblem {
|
let adf_problem_input_clone = adf_problem_input.clone();
|
||||||
name: problem_name.clone(),
|
|
||||||
username: username.clone(),
|
|
||||||
code: adf_problem_input.code.clone(),
|
|
||||||
parsing_used: adf_problem_input.parse_strategy,
|
|
||||||
adf: SimplifiedAdfOpt::None,
|
|
||||||
acs_per_strategy: AcsPerStrategy::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let result = adf_coll.insert_one(&adf_problem, None).await;
|
|
||||||
|
|
||||||
if let Err(err) = result {
|
|
||||||
return HttpResponse::InternalServerError()
|
|
||||||
.body(format!("Could not create Database entry. Error: {err}"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let username_clone = username.clone();
|
let username_clone = username.clone();
|
||||||
let problem_name_clone = problem_name.clone();
|
let problem_name_clone = problem_name.clone();
|
||||||
|
|
||||||
let adf_fut = timeout(
|
// TODO: change this: we want to return a response from the request whil the computation is running
|
||||||
|
let adf_res = timeout(
|
||||||
COMPUTE_TIME,
|
COMPUTE_TIME,
|
||||||
spawn_blocking(move || {
|
spawn_blocking(move || {
|
||||||
let running_info = RunningInfo {
|
let running_info = RunningInfo {
|
||||||
@ -358,14 +319,11 @@ async fn add_adf_problem(
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.insert(running_info.clone());
|
.insert(running_info.clone());
|
||||||
|
|
||||||
#[cfg(feature = "mock_long_computations")]
|
|
||||||
std::thread::sleep(Duration::from_secs(20));
|
|
||||||
|
|
||||||
let parser = AdfParser::default();
|
let parser = AdfParser::default();
|
||||||
parser.parse()(&adf_problem_input.code)
|
parser.parse()(&adf_problem_input_clone.code)
|
||||||
.map_err(|_| "ADF could not be parsed, double check your input!")?;
|
.map_err(|_| "ADF could not be parsed, double check your input!")?;
|
||||||
|
|
||||||
let lib_adf = match adf_problem_input.parse_strategy {
|
let lib_adf = match adf_problem_input_clone.parse_strategy {
|
||||||
Parsing::Naive => Adf::from_parser(&parser),
|
Parsing::Naive => Adf::from_parser(&parser),
|
||||||
Parsing::Hybrid => {
|
Parsing::Hybrid => {
|
||||||
let bd_adf = BdAdf::from_parser(&parser);
|
let bd_adf = BdAdf::from_parser(&parser);
|
||||||
@ -373,55 +331,49 @@ async fn add_adf_problem(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let ac_and_graph = AcAndGraph {
|
|
||||||
ac: lib_adf.ac.iter().map(|t| t.0.to_string()).collect(),
|
|
||||||
graph: lib_adf.into_double_labeled_graph(None),
|
|
||||||
};
|
|
||||||
|
|
||||||
app_state
|
app_state
|
||||||
.currently_running
|
.currently_running
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.remove(&running_info);
|
.remove(&running_info);
|
||||||
|
|
||||||
|
let ac_and_graph = AcAndGraph {
|
||||||
|
ac: lib_adf.ac.iter().map(|t| t.0.to_string()).collect(),
|
||||||
|
graph: lib_adf.into_double_labeled_graph(None),
|
||||||
|
};
|
||||||
|
|
||||||
Ok::<_, &str>((SimplifiedAdf::from_lib_adf(lib_adf), ac_and_graph))
|
Ok::<_, &str>((SimplifiedAdf::from_lib_adf(lib_adf), ac_and_graph))
|
||||||
}),
|
}),
|
||||||
);
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
spawn(adf_fut.then(move |adf_res| async move {
|
match adf_res {
|
||||||
let (adf, ac_and_graph): (SimplifiedAdfOpt, AcsAndGraphsOpt) = match adf_res {
|
Err(err) => HttpResponse::InternalServerError().body(err.to_string()),
|
||||||
Err(err) => (
|
Ok(Err(err)) => HttpResponse::InternalServerError().body(err.to_string()),
|
||||||
SimplifiedAdfOpt::Error(err.to_string()),
|
Ok(Ok(Err(err))) => HttpResponse::InternalServerError().body(err.to_string()),
|
||||||
AcsAndGraphsOpt::Error(err.to_string()),
|
Ok(Ok(Ok((adf, ac_and_graph)))) => {
|
||||||
),
|
let acs = AcsPerStrategy {
|
||||||
Ok(Err(err)) => (
|
parse_only: Some(vec![ac_and_graph]),
|
||||||
SimplifiedAdfOpt::Error(err.to_string()),
|
..Default::default()
|
||||||
AcsAndGraphsOpt::Error(err.to_string()),
|
};
|
||||||
),
|
|
||||||
Ok(Ok(Err(err))) => (
|
|
||||||
SimplifiedAdfOpt::Error(err.to_string()),
|
|
||||||
AcsAndGraphsOpt::Error(err.to_string()),
|
|
||||||
),
|
|
||||||
Ok(Ok(Ok((adf, ac_and_graph)))) => (
|
|
||||||
SimplifiedAdfOpt::Some(adf),
|
|
||||||
AcsAndGraphsOpt::Some(vec![ac_and_graph]),
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
let result = adf_coll
|
let adf_problem: AdfProblem = AdfProblem {
|
||||||
.update_one(
|
name: problem_name,
|
||||||
doc! { "name": problem_name, "username": username },
|
username,
|
||||||
doc! { "$set": { "adf": &adf, "acs_per_strategy.parse_only": &ac_and_graph } },
|
code: adf_problem_input.code,
|
||||||
None,
|
parsing_used: adf_problem_input.parse_strategy,
|
||||||
)
|
adf,
|
||||||
.await;
|
acs_per_strategy: acs,
|
||||||
|
};
|
||||||
|
|
||||||
if let Err(err) = result {
|
let result = adf_coll.insert_one(&adf_problem, None).await;
|
||||||
log::error!("{err}");
|
|
||||||
|
match result {
|
||||||
|
Ok(_) => HttpResponse::Ok().json(AdfProblemInfo::from_adf_prob_and_tasks(adf_problem, &HashSet::new())), // there should be no tasks running here
|
||||||
|
Err(err) => HttpResponse::InternalServerError().body(err.to_string()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}));
|
}
|
||||||
|
|
||||||
HttpResponse::Ok().body("Parsing started...")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
@ -463,18 +415,6 @@ async fn solve_adf_problem(
|
|||||||
Ok(Some(prob)) => prob,
|
Ok(Some(prob)) => prob,
|
||||||
};
|
};
|
||||||
|
|
||||||
let simp_adf: SimplifiedAdf = match adf_problem.adf {
|
|
||||||
SimplifiedAdfOpt::None => {
|
|
||||||
return HttpResponse::BadRequest().body("The ADF problem has not been parsed yet.")
|
|
||||||
}
|
|
||||||
SimplifiedAdfOpt::Error(err) => {
|
|
||||||
return HttpResponse::BadRequest().body(format!(
|
|
||||||
"The ADF problem could not be parsed. Update it and try again. Error: {err}"
|
|
||||||
))
|
|
||||||
}
|
|
||||||
SimplifiedAdfOpt::Some(adf) => adf,
|
|
||||||
};
|
|
||||||
|
|
||||||
let has_been_solved = match adf_problem_input.strategy {
|
let has_been_solved = match adf_problem_input.strategy {
|
||||||
Strategy::Complete => adf_problem.acs_per_strategy.complete.is_some(),
|
Strategy::Complete => adf_problem.acs_per_strategy.complete.is_some(),
|
||||||
Strategy::Ground => adf_problem.acs_per_strategy.ground.is_some(),
|
Strategy::Ground => adf_problem.acs_per_strategy.ground.is_some(),
|
||||||
@ -492,14 +432,16 @@ async fn solve_adf_problem(
|
|||||||
|
|
||||||
let username_clone = username.clone();
|
let username_clone = username.clone();
|
||||||
let problem_name_clone = problem_name.clone();
|
let problem_name_clone = problem_name.clone();
|
||||||
|
let strategy_clone = adf_problem_input.strategy.clone();
|
||||||
|
|
||||||
|
// TODO: change this: we want to return a response from the request whil the computation is running
|
||||||
let acs_and_graphs_fut = timeout(
|
let acs_and_graphs_fut = timeout(
|
||||||
COMPUTE_TIME,
|
COMPUTE_TIME,
|
||||||
spawn_blocking(move || {
|
spawn_blocking(move || {
|
||||||
let running_info = RunningInfo {
|
let running_info = RunningInfo {
|
||||||
username: username_clone,
|
username: username_clone,
|
||||||
adf_name: problem_name_clone,
|
adf_name: problem_name_clone,
|
||||||
task: Task::Solve(adf_problem_input.strategy),
|
task: Task::Solve(strategy_clone.clone()),
|
||||||
};
|
};
|
||||||
|
|
||||||
app_state
|
app_state
|
||||||
@ -508,20 +450,18 @@ async fn solve_adf_problem(
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.insert(running_info.clone());
|
.insert(running_info.clone());
|
||||||
|
|
||||||
#[cfg(feature = "mock_long_computations")]
|
|
||||||
std::thread::sleep(Duration::from_secs(20));
|
|
||||||
|
|
||||||
let mut adf: Adf = Adf::from_ord_nodes_and_ac(
|
let mut adf: Adf = Adf::from_ord_nodes_and_ac(
|
||||||
simp_adf.ordering.into(),
|
adf_problem.adf.ordering.into(),
|
||||||
simp_adf.bdd.into_iter().map(Into::into).collect(),
|
adf_problem.adf.bdd.into_iter().map(Into::into).collect(),
|
||||||
simp_adf
|
adf_problem
|
||||||
|
.adf
|
||||||
.ac
|
.ac
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|t| Term(t.parse().unwrap()))
|
.map(|t| Term(t.parse().unwrap()))
|
||||||
.collect(),
|
.collect(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let acs: Vec<Ac> = match adf_problem_input.strategy {
|
let acs: Vec<Ac> = match strategy_clone {
|
||||||
Strategy::Complete => adf.complete().collect(),
|
Strategy::Complete => adf.complete().collect(),
|
||||||
Strategy::Ground => vec![adf.grounded()],
|
Strategy::Ground => vec![adf.grounded()],
|
||||||
Strategy::Stable => adf.stable().collect(),
|
Strategy::Stable => adf.stable().collect(),
|
||||||
@ -554,27 +494,29 @@ async fn solve_adf_problem(
|
|||||||
);
|
);
|
||||||
|
|
||||||
spawn(acs_and_graphs_fut.then(move |acs_and_graphs_res| async move {
|
spawn(acs_and_graphs_fut.then(move |acs_and_graphs_res| async move {
|
||||||
let acs_and_graphs_enum: AcsAndGraphsOpt = match acs_and_graphs_res {
|
match acs_and_graphs_res {
|
||||||
Err(err) => AcsAndGraphsOpt::Error(err.to_string()),
|
// TODO: error states should somehow be set in the database since the status codes are irrelevant in this future
|
||||||
Ok(Err(err)) => AcsAndGraphsOpt::Error(err.to_string()),
|
Err(err) => HttpResponse::InternalServerError().body(err.to_string()),
|
||||||
Ok(Ok(acs_and_graphs)) => AcsAndGraphsOpt::Some(acs_and_graphs),
|
Ok(Err(err)) => HttpResponse::InternalServerError().body(err.to_string()),
|
||||||
|
Ok(Ok(acs_and_graphs)) => {
|
||||||
|
let result = adf_coll.update_one(doc! { "name": problem_name, "username": username }, match adf_problem_input.strategy {
|
||||||
|
Strategy::Complete => doc! { "$set": { "acs_per_strategy.complete": Some(&acs_and_graphs) } },
|
||||||
|
Strategy::Ground => doc! { "$set": { "acs_per_strategy.ground": Some(&acs_and_graphs) } },
|
||||||
|
Strategy::Stable => doc! { "$set": { "acs_per_strategy.stable": Some(&acs_and_graphs) } },
|
||||||
|
Strategy::StableCountingA => doc! { "$set": { "acs_per_strategy.stable_counting_a": Some(&acs_and_graphs) } },
|
||||||
|
Strategy::StableCountingB => doc! { "$set": { "acs_per_strategy.stable_counting_b": Some(&acs_and_graphs) } },
|
||||||
|
Strategy::StableNogood => doc! { "$set": { "acs_per_strategy.stable_nogood": Some(&acs_and_graphs) } },
|
||||||
|
}, None).await;
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(_) => HttpResponse::Ok().json(acs_and_graphs),
|
||||||
|
Err(err) => HttpResponse::InternalServerError().body(err.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = adf_coll.update_one(doc! { "name": problem_name, "username": username }, match adf_problem_input.strategy {
|
|
||||||
Strategy::Complete => doc! { "$set": { "acs_per_strategy.complete": &acs_and_graphs_enum } },
|
|
||||||
Strategy::Ground => doc! { "$set": { "acs_per_strategy.ground": &acs_and_graphs_enum } },
|
|
||||||
Strategy::Stable => doc! { "$set": { "acs_per_strategy.stable": &acs_and_graphs_enum } },
|
|
||||||
Strategy::StableCountingA => doc! { "$set": { "acs_per_strategy.stable_counting_a": &acs_and_graphs_enum } },
|
|
||||||
Strategy::StableCountingB => doc! { "$set": { "acs_per_strategy.stable_counting_b": &acs_and_graphs_enum } },
|
|
||||||
Strategy::StableNogood => doc! { "$set": { "acs_per_strategy.stable_nogood": &acs_and_graphs_enum } },
|
|
||||||
}, None).await;
|
|
||||||
|
|
||||||
if let Err(err) = result {
|
|
||||||
log::error!("{err}");
|
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
HttpResponse::Ok().body("Solving started...")
|
HttpResponse::Ok().body("Parsing started...")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/{problem_name}")]
|
#[get("/{problem_name}")]
|
||||||
@ -614,80 +556,3 @@ async fn get_adf_problem(
|
|||||||
&app_state.currently_running.lock().unwrap(),
|
&app_state.currently_running.lock().unwrap(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[delete("/{problem_name}")]
|
|
||||||
async fn delete_adf_problem(
|
|
||||||
app_state: web::Data<AppState>,
|
|
||||||
identity: Option<Identity>,
|
|
||||||
path: web::Path<String>,
|
|
||||||
) -> impl Responder {
|
|
||||||
let problem_name = path.into_inner();
|
|
||||||
let adf_coll: mongodb::Collection<AdfProblem> = app_state
|
|
||||||
.mongodb_client
|
|
||||||
.database(DB_NAME)
|
|
||||||
.collection(ADF_COLL);
|
|
||||||
|
|
||||||
let username = match identity.map(|id| id.id()) {
|
|
||||||
None => {
|
|
||||||
return HttpResponse::Unauthorized().body("You need to login to get an ADF problem.")
|
|
||||||
}
|
|
||||||
Some(Err(err)) => return HttpResponse::InternalServerError().body(err.to_string()),
|
|
||||||
Some(Ok(username)) => username,
|
|
||||||
};
|
|
||||||
|
|
||||||
match adf_coll
|
|
||||||
.delete_one(doc! { "name": &problem_name, "username": &username }, None)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(DeleteResult {
|
|
||||||
deleted_count: 0, ..
|
|
||||||
}) => HttpResponse::InternalServerError().body("Adf Problem could not be deleted."),
|
|
||||||
Ok(DeleteResult {
|
|
||||||
deleted_count: 1, ..
|
|
||||||
}) => HttpResponse::Ok().body("Adf Problem deleted."),
|
|
||||||
Ok(_) => {
|
|
||||||
unreachable!("delete_one removes at most one entry so all cases are covered already")
|
|
||||||
}
|
|
||||||
Err(err) => HttpResponse::InternalServerError().body(err.to_string()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/")]
|
|
||||||
async fn get_adf_problems_for_user(
|
|
||||||
app_state: web::Data<AppState>,
|
|
||||||
identity: Option<Identity>,
|
|
||||||
) -> impl Responder {
|
|
||||||
let adf_coll: mongodb::Collection<AdfProblem> = app_state
|
|
||||||
.mongodb_client
|
|
||||||
.database(DB_NAME)
|
|
||||||
.collection(ADF_COLL);
|
|
||||||
|
|
||||||
let username = match identity.map(|id| id.id()) {
|
|
||||||
None => {
|
|
||||||
return HttpResponse::Unauthorized().body("You need to login to get an ADF problem.")
|
|
||||||
}
|
|
||||||
Some(Err(err)) => return HttpResponse::InternalServerError().body(err.to_string()),
|
|
||||||
Some(Ok(username)) => username,
|
|
||||||
};
|
|
||||||
|
|
||||||
let adf_problem_cursor = match adf_coll.find(doc! { "username": &username }, None).await {
|
|
||||||
Err(err) => return HttpResponse::InternalServerError().body(err.to_string()),
|
|
||||||
Ok(cursor) => cursor,
|
|
||||||
};
|
|
||||||
|
|
||||||
let adf_problems: Vec<AdfProblemInfo> = match adf_problem_cursor
|
|
||||||
.map_ok(|adf_problem| {
|
|
||||||
AdfProblemInfo::from_adf_prob_and_tasks(
|
|
||||||
adf_problem,
|
|
||||||
&app_state.currently_running.lock().unwrap(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.try_collect()
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Err(err) => return HttpResponse::InternalServerError().body(err.to_string()),
|
|
||||||
Ok(probs) => probs,
|
|
||||||
};
|
|
||||||
|
|
||||||
HttpResponse::Ok().json(adf_problems)
|
|
||||||
}
|
|
||||||
|
|||||||
@ -17,10 +17,7 @@ mod adf;
|
|||||||
mod config;
|
mod config;
|
||||||
mod user;
|
mod user;
|
||||||
|
|
||||||
use adf::{
|
use adf::{add_adf_problem, solve_adf_problem};
|
||||||
add_adf_problem, delete_adf_problem, get_adf_problem, get_adf_problems_for_user,
|
|
||||||
solve_adf_problem,
|
|
||||||
};
|
|
||||||
use config::{AppState, ASSET_DIRECTORY, COOKIE_DURATION};
|
use config::{AppState, ASSET_DIRECTORY, COOKIE_DURATION};
|
||||||
use user::{
|
use user::{
|
||||||
create_username_index, delete_account, login, logout, register, update_user, user_info,
|
create_username_index, delete_account, login, logout, register, update_user, user_info,
|
||||||
@ -85,10 +82,7 @@ async fn main() -> std::io::Result<()> {
|
|||||||
.service(
|
.service(
|
||||||
web::scope("/adf")
|
web::scope("/adf")
|
||||||
.service(add_adf_problem)
|
.service(add_adf_problem)
|
||||||
.service(solve_adf_problem)
|
.service(solve_adf_problem),
|
||||||
.service(get_adf_problem)
|
|
||||||
.service(delete_adf_problem)
|
|
||||||
.service(get_adf_problems_for_user),
|
|
||||||
)
|
)
|
||||||
// this mus be last to not override anything
|
// this mus be last to not override anything
|
||||||
.service(fs::Files::new("/", ASSET_DIRECTORY).index_file("index.html"))
|
.service(fs::Files::new("/", ASSET_DIRECTORY).index_file("index.html"))
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user