Skip to content

Commit

Permalink
Merge pull request #20 from georust/v0.2
Browse files Browse the repository at this point in the history
Prepare v0.2
  • Loading branch information
b4l authored May 12, 2024
2 parents 3f64fad + 158f2fd commit afecd9c
Show file tree
Hide file tree
Showing 30 changed files with 1,932 additions and 1,194 deletions.
2,790 changes: 1,745 additions & 1,045 deletions Cargo.lock

Large diffs are not rendered by default.

12 changes: 11 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[workspace]
resolver = "2"

members = [
"ogcapi",
Expand All @@ -13,4 +14,13 @@ default-members = ["ogcapi"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/georust/ogcapi"
edition = "2021"
rust-version = "1.66"

[workspace.dependencies]
anyhow = "1.0.82"
geojson = "0.24.1"
log = "0.4.21"
serde = "1.0.197"
serde_json = "1.0.115"
serde_qs = "0.13.0"
thiserror = "1.0.58"
url = "2.5.0"
2 changes: 1 addition & 1 deletion LICENSE-APACHE
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work.
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright 2022 Camptocamp SA
Copyright 2024 The GeoRust Project Developers

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion LICENSE-MIT
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2022 Camptocamp SA
Copyright (c) 2024 The GeoRust Project Developers

Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
Expand Down
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@

[OGC API](https://ogcapi.ogc.org/) building blocks implemented in [Rust](https://www.rust-lang.org/)

## Project Outline

The code is organized in four modules, respectively crates:

| Module / Crate | Description |
| ----------------- | --------------- |
| `ogcapi-types` | Types as defined in various OGC API standards as well as STAC with `serde` support. |
| `ogcapi-client` | Client to access HTTP endpoints of OGC API services as well as STAC wrapping `reqwest` |
| `ogcapi-services` | Server implementation of various OGC API services based on `axum`. |
| `ogcapi-drivers` | Drivers for different data provider backends, currently mainly PostgreSQL with PostGIS through `sqlx`. |

These modules are reexported within the `ogcapi` crate.

## Quick Start

This will take a while and use quite some disk space
Expand Down Expand Up @@ -74,7 +87,7 @@ Navigate to <http://localhost:8080/teamengine/> to execute the test suite. For d

## Example Project

STAC enabled OGC API Features: <https://github.com/camptocamp/oapi-poc>
Based on this project, a STAC enabled OGC API Features service has successfully been setup. You can find the code from the prove of concept [here](https://github.com/camptocamp/oapi-poc)

## License

Expand Down
20 changes: 9 additions & 11 deletions ogcapi-client/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
[package]
name = "ogcapi-client"
version = "0.1.0"
version = "0.2.0"
description = "Client to access OGC API Feature and STAC endpoints."
license.workspace = true
repository.workspace = true
edition.workspace = true
rust-version.workspace = true

[features]
default = []
stac = ["ogcapi-types/stac"]

[dependencies]
log = "0.4.17"
geojson = "0.24.0"
once_cell = "1.16.0"
reqwest = { version = "0.11.13", default-features = false, features = ["json", "blocking", "rustls-tls", "hyper-rustls"] }
serde = { version = "1.0.151", features = ["derive"] }
serde_json = "1.0.91"
serde_qs = "0.10.1"
thiserror = "1.0.38"
url = { version = "2.3.1", features = ["serde"] }
geojson = { workspace = true }
log = { workspace = true }
reqwest = { version = "0.12.3", default-features = false, features = ["json", "blocking", "rustls-tls"] }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
serde_qs = { workspace = true }
thiserror = { workspace = true }
url = { workspace = true, features = ["serde"] }

ogcapi-types = { path = "../ogcapi-types" }
12 changes: 8 additions & 4 deletions ogcapi-client/src/client.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use once_cell::sync::OnceCell;
use std::cell::OnceCell;

use reqwest::{
blocking::Client as ReqwestClient,
header::{HeaderMap, HeaderValue, USER_AGENT},
Expand Down Expand Up @@ -78,9 +79,12 @@ impl Client {

/// Returns the landing page or the root catalog.
pub fn root(&self) -> Result<LandingPage, Error> {
let root = self
.root
.get_or_try_init(|| self.fetch::<LandingPage>(self.endpoint.as_ref()))?;
let root = if let Some(root) = self.root.get() {
root
} else {
let root = self.fetch::<LandingPage>(self.endpoint.as_ref())?;
self.root.get_or_init(|| root)
};
Ok(root.clone())
}

Expand Down
2 changes: 1 addition & 1 deletion ogcapi-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//!
//! # Example
//!
//! ```rust, no_run
//! ```rust, ignore
//! use ogcapi_client::Client;
//! use ogcapi_types::common::Bbox;
//! use ogcapi_types::stac::SearchParams;
Expand Down
23 changes: 11 additions & 12 deletions ogcapi-drivers/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
[package]
name = "ogcapi-drivers"
version = "0.1.3"
version = "0.2.0"
description = "Driver traits and implementations"
license.workspace = true
repository.workspace = true
edition.workspace = true
rust-version.workspace = true

include = ["/src", "/migrations"]

Expand All @@ -15,15 +14,15 @@ stac = ["ogcapi-types/stac"]
postgres = ["sqlx", "rink-core", "url"]

[dependencies]
anyhow = "1.0.68"
aws-config = { version = "0.52.0", optional = true }
aws-sdk-s3 = { version = "0.22.0", optional = true }
async-trait = "0.1.60"
http = "0.2.8"
rink-core = { version = "0.6.2", optional = true }
serde_json = "1.0.91"
sqlx = { version = "0.6.2", optional = true, features = ["runtime-tokio-rustls", "postgres", "json", "migrate"] }
tokio = { version = "1.23.0", features = ["full"] }
url = { version = "2.3.1", optional = true }
anyhow = { workspace = true }
aws-config = { version = "1.2.0", optional = true, features = ["behavior-version-latest"] }
aws-sdk-s3 = { version = "1.23.0", optional = true, features = ["behavior-version-latest"] }
async-trait = "0.1.80"
http = "1.1.0"
rink-core = { version = "0.8.0", optional = true, features = ["bundle-files"] }
serde_json = { workspace = true }
sqlx = { version = "0.7.4", optional = true, features = ["runtime-tokio-rustls", "postgres", "json", "migrate"] }
tokio = { version = "1.37.0", features = ["full"] }
url = { workspace = true, optional = true }

ogcapi-types = { path = "../ogcapi-types" }
16 changes: 8 additions & 8 deletions ogcapi-drivers/src/postgres/collection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,40 +23,40 @@ impl CollectionTransactions for Db {
"#,
collection.id
))
.execute(&mut tx)
.execute(&mut *tx)
.await?;

sqlx::query(&format!(
r#"CREATE INDEX ON items."{}" USING btree (collection)"#,
collection.id
))
.execute(&mut tx)
.execute(&mut *tx)
.await?;

sqlx::query(&format!(
r#"CREATE INDEX ON items."{}" USING gin (properties)"#,
collection.id
))
.execute(&mut tx)
.execute(&mut *tx)
.await?;

sqlx::query(&format!(
r#"CREATE INDEX ON items."{}" USING gist (geom)"#,
collection.id
))
.execute(&mut tx)
.execute(&mut *tx)
.await?;

sqlx::query("SELECT UpdateGeometrySRID('items', $1, 'geom', $2)")
.bind(&collection.id)
.bind(collection.storage_crs.clone().unwrap_or_default().as_srid())
.execute(&mut tx)
.execute(&mut *tx)
.await?;

sqlx::query("INSERT INTO meta.collections ( id, collection ) VALUES ( $1, $2 )")
.bind(&collection.id)
.bind(sqlx::types::Json(collection))
.execute(&mut tx)
.execute(&mut *tx)
.await?;

tx.commit().await?;
Expand Down Expand Up @@ -93,12 +93,12 @@ impl CollectionTransactions for Db {
let mut tx = self.pool.begin().await?;

sqlx::query(&format!(r#"DROP TABLE IF EXISTS items."{}""#, id))
.execute(&mut tx)
.execute(&mut *tx)
.await?;

sqlx::query("DELETE FROM meta.collections WHERE id = $1")
.bind(id)
.fetch_optional(&mut tx)
.fetch_optional(&mut *tx)
.await?;

tx.commit().await?;
Expand Down
6 changes: 3 additions & 3 deletions ogcapi-drivers/src/postgres/stac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ impl StacSeach for Db {
WHERE collection ->> 'type' = 'Collection'
"#,
)
.fetch_all(&mut tx)
.fetch_all(&mut *tx)
.await?;

if let Some(collections) = &query.collections {
Expand Down Expand Up @@ -130,7 +130,7 @@ impl StacSeach for Db {
WHERE {conditions}
"#,
))
.fetch_one(&mut tx)
.fetch_one(&mut *tx)
.await?;

// FETCH
Expand Down Expand Up @@ -158,7 +158,7 @@ impl StacSeach for Db {
.map_or_else(|| String::from("NULL"), |l| l.to_string()),
query.offset.unwrap_or(0)
))
.fetch_one(&mut tx)
.fetch_one(&mut *tx)
.await?;

tx.commit().await?;
Expand Down
6 changes: 3 additions & 3 deletions ogcapi-drivers/src/s3/collection.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use aws_sdk_s3::{error::GetObjectErrorKind, types::SdkError};
use aws_sdk_s3::{error::SdkError, operation::get_object::GetObjectError};

use ogcapi_types::common::{media_type::JSON, Collection, Collections, Query};

Expand Down Expand Up @@ -35,8 +35,8 @@ impl CollectionTransactions for S3 {
&r.body.collect().await?.into_bytes(),
)?)),
Err(e) => match e {
SdkError::ServiceError(err) => match err.err().kind {
GetObjectErrorKind::NoSuchKey(_) => Ok(None),
SdkError::ServiceError(err) => match err.err() {
GetObjectError::NoSuchKey(_) => Ok(None),
_ => Err(anyhow::Error::new(err.into_err())),
},
_ => Err(anyhow::Error::new(e)),
Expand Down
6 changes: 3 additions & 3 deletions ogcapi-drivers/src/s3/feature.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use aws_sdk_s3::{error::GetObjectErrorKind, types::SdkError};
use aws_sdk_s3::{error::SdkError, operation::get_object::GetObjectError};

use ogcapi_types::{
common::{media_type::GEO_JSON, Crs},
Expand Down Expand Up @@ -46,8 +46,8 @@ impl FeatureTransactions for S3 {
&r.body.collect().await?.into_bytes(),
)?)),
Err(e) => match e {
SdkError::ServiceError(err) => match err.err().kind {
GetObjectErrorKind::NoSuchKey(_) => Ok(None),
SdkError::ServiceError(err) => match err.err() {
GetObjectError::NoSuchKey(_) => Ok(None),
_ => Err(anyhow::Error::new(err.into_err())),
},
_ => Err(anyhow::Error::new(e)),
Expand Down
31 changes: 21 additions & 10 deletions ogcapi-drivers/src/s3/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ mod collection;
mod feature;

use aws_sdk_s3::{
error::{DeleteObjectError, GetObjectError, PutObjectError},
output::{DeleteObjectOutput, GetObjectOutput, PutObjectOutput},
types::SdkError,
Client, Endpoint,
error::SdkError,
operation::{
delete_object::{DeleteObjectError, DeleteObjectOutput},
get_object::{GetObjectError, GetObjectOutput},
put_object::{PutObjectError, PutObjectOutput},
},
Client, Config,
};

pub use aws_sdk_s3::types::ByteStream;
pub use aws_sdk_s3::primitives::ByteStream;

/// S3 driver
#[derive(Clone)]
Expand All @@ -23,15 +26,23 @@ impl S3 {
pub async fn new() -> Self {
let config = if let Ok(endpoint) = std::env::var("AWS_CUSTOM_ENDPOINT") {
// Use custom enpoint if specified in `AWS_CUSTOM_ENDPOINT` environment variable
aws_config::from_env()
.endpoint_resolver(Endpoint::immutable(&endpoint).unwrap())
.load()
println!("Setup client with custom endpoint: {endpoint}");
aws_config::load_from_env()
.await
.into_builder()
.endpoint_url(&endpoint)
.build()
} else {
aws_config::from_env().load().await
aws_config::load_from_env().await
};

S3::new_with(Client::new(&config)).await
// force path style addressing to work with minio
let config = Config::from(&config)
.to_builder()
.force_path_style(true)
.build();

S3::new_with(Client::from_conf(config)).await
}

pub async fn new_with(client: Client) -> Self {
Expand Down
Loading

0 comments on commit afecd9c

Please sign in to comment.