Skip to content

Commit 0b0ae59

Browse files
some fixes
1 parent 3fca6d8 commit 0b0ae59

File tree

8 files changed

+158
-79
lines changed

8 files changed

+158
-79
lines changed

.github/workflows/ci.yml

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,18 @@ jobs:
6666
npx wait-on http://localhost:8484/
6767
6868
- name: Validate service
69-
uses: geo-engine/ogc-validator@v1
69+
uses: geo-engine/ogc-validator@v2
7070
with:
7171
service-url: http://localhost:8484/
7272
ogc-api-processes: true
73-
ogc-api-processes-version: 1.3-teamengine-6.0.0-RC2
73+
ogc-api-processes-container-tag: 1.3-teamengine-6.0.0-RC2
7474
echoprocessid: echo
75+
# cf. <https://github.com/opengeospatial/ets-ogcapi-processes10/issues/106>
7576
ogc-api-processes-ignore: |-
76-
testJobCreationOp
7777
testJobCreationInputValidation
78-
testJobCreationRequest
7978
testJobCreationInputRef
80-
testJobList
79+
ogc-api-features: true
80+
ogc-api-features-container-tag: 1.9-teamengine-6.0.0-RC2
81+
ogc-api-features-ignore: |-
82+
featureOperation
83+
validateFeatureResponse

ogcapi-drivers/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ pub trait JobHandler: Send + Sync {
110110
}
111111

112112
#[cfg(feature = "processes")]
113+
#[derive(Debug)]
113114
pub enum ProcessResult {
114115
NoSuchJob,
115116
NotReady,

ogcapi-drivers/src/postgres/job.rs

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ use super::Db;
1313
#[async_trait::async_trait]
1414
impl JobHandler for Db {
1515
async fn register(&self, job: &StatusInfo, response_mode: Response) -> anyhow::Result<String> {
16-
eprintln!("{}", serde_json::to_string_pretty(job).unwrap());
17-
eprintln!("{}", serde_json::to_string_pretty(&response_mode).unwrap());
1816
let (id,): (String,) = sqlx::query_as(
1917
r#"
2018
INSERT INTO meta.jobs(
@@ -150,24 +148,23 @@ impl JobHandler for Db {
150148
}
151149

152150
async fn results(&self, id: &str) -> anyhow::Result<ProcessResult> {
153-
let results: Option<(
154-
Option<sqlx::types::Json<HashMap<String, ExecuteResult>>>,
155-
sqlx::types::Json<Response>,
156-
)> = sqlx::query_as(
157-
r#"
151+
let results: Option<(Json<Option<HashMap<String, ExecuteResult>>>, Json<Response>)> = dbg!(
152+
sqlx::query_as(
153+
r#"
158154
SELECT results, to_jsonb(response)
159155
FROM meta.jobs
160156
WHERE job_id = $1
161157
"#,
162-
)
163-
.bind(id)
164-
.fetch_optional(&self.pool)
165-
.await?;
158+
)
159+
.bind(id)
160+
.fetch_optional(&self.pool)
161+
.await
162+
)?;
166163

167164
Ok(match results {
168165
None => ProcessResult::NoSuchJob,
169-
Some((None, _)) => ProcessResult::NotReady,
170-
Some((Some(Json(results)), Json(response_mode))) => ProcessResult::Results {
166+
Some((Json(None), _)) => ProcessResult::NotReady,
167+
Some((Json(Some(results)), Json(response_mode))) => ProcessResult::Results {
171168
results,
172169
response_mode,
173170
},

ogcapi-processes/src/echo.rs

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pub struct EchoInputs {
3636
// pub bounding_box_input: Option<BoundingBoxInput>,
3737
// pub images_input: Option<Vec<String>>,
3838
// pub feature_collection_input: Option<String>,
39+
pub pause: Option<u64>,
3940
}
4041

4142
#[derive(Deserialize, Serialize, Debug, JsonSchema)]
@@ -174,20 +175,50 @@ impl Processor for Echo {
174175
.title("Execution endpoint"),
175176
],
176177
},
177-
inputs: HashMap::from([(
178-
"stringInput".to_string(),
179-
InputDescription {
180-
description_type: DescriptionType {
181-
title: Some("String Literal Input Example".to_string()),
182-
description: Some(
183-
"This is an example of a STRING literal input.".to_string(),
184-
),
178+
inputs: HashMap::from([
179+
(
180+
"stringInput".to_string(),
181+
InputDescription {
182+
description_type: DescriptionType {
183+
title: Some("String Literal Input Example".to_string()),
184+
description: Some(
185+
"This is an example of a STRING literal input.".to_string(),
186+
),
187+
..Default::default()
188+
},
189+
schema: generator.root_schema_for::<StringInput>().to_value(),
185190
..Default::default()
186191
},
187-
schema: generator.root_schema_for::<StringInput>().to_value(),
188-
..Default::default()
189-
},
190-
)]),
192+
),
193+
(
194+
"doubleInput".to_string(),
195+
InputDescription {
196+
description_type: DescriptionType {
197+
title: Some("Double Literal Input Example".to_string()),
198+
description: Some(
199+
"This is an example of a DOUBLE literal input.".to_string(),
200+
),
201+
..Default::default()
202+
},
203+
schema: generator.root_schema_for::<f64>().to_value(),
204+
..Default::default()
205+
},
206+
),
207+
(
208+
"pause".to_string(),
209+
InputDescription {
210+
description_type: DescriptionType {
211+
title: Some("Pause Duration".to_string()),
212+
description: Some(
213+
"Optional pause duration in seconds before responding.".to_string(),
214+
),
215+
..Default::default()
216+
},
217+
schema: generator.root_schema_for::<u64>().to_value(),
218+
..Default::default()
219+
},
220+
),
221+
]),
191222
outputs: HashMap::from([(
192223
"stringOutput".to_string(),
193224
OutputDescription {
@@ -202,6 +233,10 @@ impl Processor for Echo {
202233
let value = serde_json::to_value(execute.inputs)?;
203234
let inputs: EchoInputs = serde_json::from_value(value)?;
204235

236+
if let Some(pause_duration) = inputs.pause {
237+
tokio::time::sleep(std::time::Duration::from_secs(pause_duration)).await;
238+
}
239+
205240
let output_values = EchoOutputs {
206241
string_output: inputs.string_input,
207242
double_output: inputs.double_input,

ogcapi-services/src/error.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use axum::{
66
use hyper::HeaderMap;
77

88
use ogcapi_types::common::{Exception, media_type::PROBLEM_JSON};
9+
use tracing::error;
910

1011
/// A common error type that can be used throughout the API.
1112
///
@@ -102,3 +103,25 @@ impl From<Error> for Exception {
102103
Exception::new(status.as_u16()).detail(message)
103104
}
104105
}
106+
107+
/// Helper function to read-lock a RwLock, recovering from poisoning if necessary.
108+
pub fn read_lock<T>(mutex: &std::sync::RwLock<T>) -> std::sync::RwLockReadGuard<'_, T> {
109+
match mutex.read() {
110+
Ok(guard) => guard,
111+
Err(poisoned) => {
112+
error!("Mutex was poisoned, attempting to recover.");
113+
poisoned.into_inner()
114+
}
115+
}
116+
}
117+
118+
/// Helper function to read-lock a RwLock, recovering from poisoning if necessary.
119+
pub fn write_lock<T>(mutex: &std::sync::RwLock<T>) -> std::sync::RwLockWriteGuard<'_, T> {
120+
match mutex.write() {
121+
Ok(guard) => guard,
122+
Err(poisoned) => {
123+
error!("Mutex was poisoned, attempting to recover.");
124+
poisoned.into_inner()
125+
}
126+
}
127+
}

ogcapi-services/src/processes.rs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
use crate::Error;
12
use axum::{
23
Json,
34
body::Body,
5+
extract::{FromRequest, Request},
46
http::{HeaderValue, StatusCode},
57
response::{IntoResponse, IntoResponseParts, Response, ResponseParts},
68
};
@@ -10,7 +12,7 @@ use mail_builder::headers::content_type::ContentType;
1012
use mail_builder::headers::text::Text;
1113
use mail_builder::mime::{BodyPart, MimePart};
1214
use ogcapi_types::{
13-
common::Link,
15+
common::{Exception, Link},
1416
processes::{ExecuteResult, InlineOrRefData, StatusInfo},
1517
};
1618
use std::borrow::Cow;
@@ -412,6 +414,38 @@ fn qualified_input_value_to_binary(
412414
}
413415
}
414416

417+
#[derive(Debug, Clone, Copy, Default)]
418+
#[must_use]
419+
pub struct ValidParams<T>(pub T);
420+
421+
impl<T, S> FromRequest<S> for ValidParams<T>
422+
where
423+
T: FromRequest<S>,
424+
T::Rejection: std::fmt::Display,
425+
S: Send + Sync,
426+
{
427+
type Rejection = Error;
428+
429+
async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection> {
430+
let json = T::from_request(req, state).await;
431+
432+
match json {
433+
Ok(value) => Ok(ValidParams(value)),
434+
Err(rejection) => {
435+
// let response_body = rejection.body_text();
436+
Err(Error::OgcApiException(
437+
Exception::new("InvalidParameterValue")
438+
.status(404)
439+
.title("InvalidParameterValue")
440+
.detail(format!(
441+
"The following parameters are not recognized: {rejection}",
442+
)),
443+
))
444+
}
445+
}
446+
}
447+
}
448+
415449
#[cfg(test)]
416450
mod tests {
417451
use std::collections::BTreeMap;

0 commit comments

Comments
 (0)