From 8ef2b9e990a24f6eb5803fe91b666d85ac4b3ab5 Mon Sep 17 00:00:00 2001 From: Michael Mattig Date: Mon, 27 Apr 2026 16:54:04 +0000 Subject: [PATCH 1/2] try to improve release build time --- geoengine/Cargo.lock | 399 +------------------------------------------ geoengine/Cargo.toml | 5 +- 2 files changed, 4 insertions(+), 400 deletions(-) diff --git a/geoengine/Cargo.lock b/geoengine/Cargo.lock index ae178d80d..28a451e15 100644 --- a/geoengine/Cargo.lock +++ b/geoengine/Cargo.lock @@ -372,24 +372,6 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" -[[package]] -name = "aligned" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee4508988c62edf04abd8d92897fca0c2995d907ce1dfeaf369dac3716a40685" -dependencies = [ - "as-slice 0.2.1", -] - -[[package]] -name = "aligned-vec" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" -dependencies = [ - "equator", -] - [[package]] name = "alloc-no-stdlib" version = "2.0.4" @@ -509,17 +491,6 @@ dependencies = [ "derive_arbitrary", ] -[[package]] -name = "arg_enum_proc_macro" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "array-init" version = "2.1.0" @@ -532,12 +503,6 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" -[[package]] -name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - [[package]] name = "arrow" version = "58.0.0" @@ -786,15 +751,6 @@ dependencies = [ "stable_deref_trait", ] -[[package]] -name = "as-slice" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516" -dependencies = [ - "stable_deref_trait", -] - [[package]] name = "assert_cmd" version = "2.2.0" @@ -873,49 +829,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" -[[package]] -name = "av-scenechange" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f321d77c20e19b92c39e7471cf986812cbb46659d2af674adc4331ef3f18394" -dependencies = [ - "aligned", - "anyhow", - "arg_enum_proc_macro", - "arrayvec", - "log", - "num-rational", - "num-traits", - "pastey", - "rayon", - "thiserror 2.0.18", - "v_frame", - "y4m", -] - -[[package]] -name = "av1-grain" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8" -dependencies = [ - "anyhow", - "arrayvec", - "log", - "nom", - "num-rational", - "v_frame", -] - -[[package]] -name = "avif-serialize" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "375082f007bd67184fb9c0374614b29f9aaa604ec301635f72338bb65386a53d" -dependencies = [ - "arrayvec", -] - [[package]] name = "axum" version = "0.6.20" @@ -1023,12 +936,6 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" -[[package]] -name = "bit_field" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6" - [[package]] name = "bitflags" version = "1.3.2" @@ -1044,15 +951,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "bitstream-io" -version = "4.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60d4bd9d1db2c6bdf285e223a7fa369d5ce98ec767dec949c6ca62863ce61757" -dependencies = [ - "core2", -] - [[package]] name = "block-buffer" version = "0.9.0" @@ -1120,12 +1018,6 @@ dependencies = [ "serde", ] -[[package]] -name = "built" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4ad8f11f288f48ca24471bbd51ac257aaeaaa07adae295591266b792902ae64" - [[package]] name = "bumpalo" version = "3.20.2" @@ -1423,12 +1315,6 @@ dependencies = [ "walkdir", ] -[[package]] -name = "color_quant" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" - [[package]] name = "colorchoice" version = "1.0.4" @@ -1567,15 +1453,6 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" -[[package]] -name = "core2" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" -dependencies = [ - "memchr", -] - [[package]] name = "core_affinity" version = "0.8.3" @@ -2122,26 +1999,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "equator" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" -dependencies = [ - "equator-macro", -] - -[[package]] -name = "equator-macro" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "equivalent" version = "1.0.2" @@ -2169,21 +2026,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "exr" -version = "1.74.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4300e043a56aa2cb633c01af81ca8f699a321879a7854d3896a0ba89056363be" -dependencies = [ - "bit_field", - "half", - "lebe", - "miniz_oxide", - "rayon-core", - "smallvec", - "zune-inflate", -] - [[package]] name = "fallible-iterator" version = "0.2.0" @@ -2923,16 +2765,6 @@ dependencies = [ "polyval", ] -[[package]] -name = "gif" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5df2ba84018d80c213569363bdcd0c64e6933c67fe4c1d60ecf822971a3c35e" -dependencies = [ - "color_quant", - "weezl", -] - [[package]] name = "glob" version = "0.3.3" @@ -3076,7 +2908,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "634bd4d29cbf24424d0a4bfcbf80c6960129dc24424752a7d1d1390607023422" dependencies = [ - "as-slice 0.1.5", + "as-slice", "generic-array 0.14.7", "hash32 0.1.1", "stable_deref_trait", @@ -3579,38 +3411,12 @@ checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" dependencies = [ "bytemuck", "byteorder-lite", - "color_quant", - "exr", - "gif", - "image-webp", "moxcms", "num-traits", "png", - "qoi", - "ravif", - "rayon", - "rgb", "tiff", - "zune-core", - "zune-jpeg", ] -[[package]] -name = "image-webp" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3" -dependencies = [ - "byteorder-lite", - "quick-error", -] - -[[package]] -name = "imgref" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c5cedc30da3a610cac6b4ba17597bdf7152cf974e8aab3afb3d54455e371c8" - [[package]] name = "impl-more" version = "0.1.9" @@ -3678,17 +3484,6 @@ dependencies = [ "generic-array 0.14.7", ] -[[package]] -name = "interpolate_name" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "inventory" version = "0.3.22" @@ -3924,12 +3719,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" -[[package]] -name = "lebe" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" - [[package]] name = "lexical-core" version = "1.0.6" @@ -3999,16 +3788,6 @@ version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" -[[package]] -name = "libfuzzer-sys" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f12a681b7dd8ce12bff52488013ba614b869148d54dd79836ab85aafdd53f08d" -dependencies = [ - "arbitrary", - "cc", -] - [[package]] name = "libloading" version = "0.9.0" @@ -4106,15 +3885,6 @@ version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" -[[package]] -name = "loop9" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" -dependencies = [ - "imgref", -] - [[package]] name = "lru" version = "0.16.3" @@ -4179,16 +3949,6 @@ dependencies = [ "rawpointer", ] -[[package]] -name = "maybe-rayon" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" -dependencies = [ - "cfg-if", - "rayon", -] - [[package]] name = "md-5" version = "0.9.1" @@ -4318,12 +4078,6 @@ dependencies = [ "rawpointer", ] -[[package]] -name = "new_debug_unreachable" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - [[package]] name = "nix" version = "0.30.1" @@ -4337,21 +4091,6 @@ dependencies = [ "memoffset", ] -[[package]] -name = "nom" -version = "8.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" -dependencies = [ - "memchr", -] - -[[package]] -name = "noop_proc_macro" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" - [[package]] name = "notify" version = "8.2.0" @@ -4461,17 +4200,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" -[[package]] -name = "num-derive" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "num-integer" version = "0.1.46" @@ -4903,12 +4631,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "pastey" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" - [[package]] name = "pathdiff" version = "0.2.3" @@ -5351,25 +5073,6 @@ dependencies = [ "yansi", ] -[[package]] -name = "profiling" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" -dependencies = [ - "profiling-procmacros", -] - -[[package]] -name = "profiling-procmacros" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b" -dependencies = [ - "quote", - "syn", -] - [[package]] name = "proj" version = "0.28.0" @@ -5550,15 +5253,6 @@ version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5a041e753da8b807c9255f28de81879c78c876392ff2469cde94799b2896b9d" -[[package]] -name = "qoi" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" -dependencies = [ - "bytemuck", -] - [[package]] name = "quick-error" version = "2.0.1" @@ -5719,56 +5413,6 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" -[[package]] -name = "rav1e" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43b6dd56e85d9483277cde964fd1bdb0428de4fec5ebba7540995639a21cb32b" -dependencies = [ - "aligned-vec", - "arbitrary", - "arg_enum_proc_macro", - "arrayvec", - "av-scenechange", - "av1-grain", - "bitstream-io", - "built", - "cfg-if", - "interpolate_name", - "itertools 0.14.0", - "libc", - "libfuzzer-sys", - "log", - "maybe-rayon", - "new_debug_unreachable", - "noop_proc_macro", - "num-derive", - "num-traits", - "paste", - "profiling", - "rand 0.9.2", - "rand_chacha 0.9.0", - "simd_helpers", - "thiserror 2.0.18", - "v_frame", - "wasm-bindgen", -] - -[[package]] -name = "ravif" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e52310197d971b0f5be7fe6b57530dcd27beb35c1b013f29d66c1ad73fbbcc45" -dependencies = [ - "avif-serialize", - "imgref", - "loop9", - "quick-error", - "rav1e", - "rayon", - "rgb", -] - [[package]] name = "rawpointer" version = "0.2.1" @@ -5961,12 +5605,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "rgb" -version = "0.8.53" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4" - [[package]] name = "ring" version = "0.17.14" @@ -6636,15 +6274,6 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" -[[package]] -name = "simd_helpers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" -dependencies = [ - "quote", -] - [[package]] name = "simdutf8" version = "0.1.5" @@ -7823,17 +7452,6 @@ dependencies = [ "vsimd", ] -[[package]] -name = "v_frame" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2" -dependencies = [ - "aligned-vec", - "num-traits", - "wasm-bindgen", -] - [[package]] name = "v_htmlescape" version = "0.15.8" @@ -8577,12 +8195,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8aa498d22c9bbaf482329839bc5620c46be275a19a812e9a22a2b07529a642a" -[[package]] -name = "y4m" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448" - [[package]] name = "yaml-rust2" version = "0.10.4" @@ -8816,15 +8428,6 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9" -[[package]] -name = "zune-inflate" -version = "0.2.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" -dependencies = [ - "simd-adler32", -] - [[package]] name = "zune-jpeg" version = "0.5.12" diff --git a/geoengine/Cargo.toml b/geoengine/Cargo.toml index 3b41f7291..5c964b7c6 100644 --- a/geoengine/Cargo.toml +++ b/geoengine/Cargo.toml @@ -21,9 +21,10 @@ documentation = "https://docs.geoengine.io" repository = "https://github.com/geo-engine/geoengine" # Rust does not inline across crates if link-time optimization (LTO) is off, which it is by default. +# Thin LTO retains cross-crate optimization while avoiding the much slower full-LTO link step. # TODO: Maybe https://rust-lang.github.io/rust-clippy/stable/index.html#missing_inline_in_public_items is more suitable [profile.release] -lto = true +lto = "thin" [profile.ci] inherits = "test" @@ -116,7 +117,7 @@ geo = "0.32.0" geo-types = "0.7.18" # important for compatibility when linking expressions geojson = { version = "0.24", features = ["geo-types"] } httptest = "0.16" -image = "0.25" +image = { version = "0.25", default-features = false, features = ["png", "tiff"] } indoc = "2.0" itertools = "0.14" libloading = "0.9" From 98f9c4a0713e5b4c709316c436368d26f70ef74d Mon Sep 17 00:00:00 2001 From: Michael Mattig Date: Mon, 27 Apr 2026 17:37:33 +0000 Subject: [PATCH 2/2] feature gate apidocs --- .github/workflows/ci.yml | 68 ++++++++--- geoengine/services/Cargo.toml | 7 +- geoengine/services/src/api/handlers/ebv.rs | 11 +- geoengine/services/src/api/mod.rs | 1 + geoengine/services/src/bin/geoengine-cli.rs | 9 +- geoengine/services/src/cli/mod.rs | 2 + geoengine/services/src/server.rs | 118 +++++++++++++++++--- geoengine/services/src/util/server.rs | 10 +- 8 files changed, 186 insertions(+), 40 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6b29cc729..af48be684 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ on: workflow_dispatch: permissions: - contents: read + contents: read env: CARGO_TERM_COLOR: always @@ -65,7 +65,7 @@ jobs: geoengine-lint: name: "geoengine / lint" - + runs-on: ubuntu-24.04 container: quay.io/geoengine/devcontainer:latest @@ -130,7 +130,40 @@ jobs: key: ci_test_${{ matrix.build }} - name: Build run: just backend build "${{ matrix.build }}" - + + geoengine-release-feature-build: + name: "geoengine / release build (${{ matrix.profile_name }})" + + runs-on: ubuntu-24.04 + container: quay.io/geoengine/devcontainer:latest + + permissions: + contents: read + + strategy: + fail-fast: false + matrix: + include: + - profile_name: default-features + cargo_features: "" + - profile_name: api-docs + cargo_features: "--features api-docs" + + steps: + - name: Checkout code + uses: actions/checkout@v6 + - name: Init rustup toolchain + # somehow rustup show will take care to initialize the version based on the toolchain file + run: rustup show + - name: setup rust build cache + uses: Swatinem/rust-cache@v2 + with: + shared-key: "" + key: ci_release_feature_${{ matrix.profile_name }} + - name: Release build geoengine-server + working-directory: geoengine + run: cargo build --locked --release --bin geoengine-server ${{ matrix.cargo_features }} + python: runs-on: ubuntu-24.04 container: quay.io/geoengine/devcontainer:latest @@ -205,7 +238,7 @@ jobs: compression-level: 9 retention-days: 1 if-no-files-found: error - + www: runs-on: ubuntu-24.04 container: quay.io/geoengine/devcontainer:latest @@ -214,17 +247,16 @@ jobs: contents: read steps: - - name: Checkout code - uses: actions/checkout@v6 - - name: Install - run: just www install - - name: Check formatting and lints - run: just www lint - - name: Build - run: just www build - - name: Idempotency check - run: just common check-no-changes-in-git-repo - + - name: Checkout code + uses: actions/checkout@v6 + - name: Install + run: just www install + - name: Check formatting and lints + run: just www lint + - name: Build + run: just www build + - name: Idempotency check + run: just common check-no-changes-in-git-repo api-client-python: name: "api-client / python" @@ -331,7 +363,7 @@ jobs: - dashboards/ebv-analyzer - dashboards/ecometrics - dashboards/esg-indicator-service - + steps: - uses: actions/checkout@v6 - name: Install Dependencies @@ -340,7 +372,7 @@ jobs: run: just ui build ${{ matrix.app }} env: CI: true - + ui-test: name: "ui / test" runs-on: ubuntu-24.04 @@ -398,7 +430,7 @@ jobs: repository-coverage: name: "repository / coverage" - needs: + needs: - geoengine-test - python diff --git a/geoengine/services/Cargo.toml b/geoengine/services/Cargo.toml index 2f6af18f6..9982963fb 100644 --- a/geoengine/services/Cargo.toml +++ b/geoengine/services/Cargo.toml @@ -13,6 +13,11 @@ default-run = "geoengine-server" [lib] bench = false +[features] +default = [] +api-docs = [] +swagger-ui = ["api-docs", "dep:utoipa-swagger-ui"] + [[bin]] name = "geoengine-server" path = "src/bin/geoengine-server.rs" @@ -99,7 +104,7 @@ tracing-opentelemetry = { workspace = true } tracing-subscriber = { workspace = true } url = { workspace = true } utoipa = { workspace = true } -utoipa-swagger-ui = { workspace = true } +utoipa-swagger-ui = { workspace = true, optional = true } uuid = { workspace = true } validator = { workspace = true } walkdir = { workspace = true } diff --git a/geoengine/services/src/api/handlers/ebv.rs b/geoengine/services/src/api/handlers/ebv.rs index f08b5a65e..2d935c514 100644 --- a/geoengine/services/src/api/handlers/ebv.rs +++ b/geoengine/services/src/api/handlers/ebv.rs @@ -14,6 +14,7 @@ use crate::datasets::external::netcdfcf::{ use crate::error::Result; use crate::layers::storage::LayerProviderDb; use crate::tasks::{Task, TaskContext, TaskId, TaskManager, TaskStatus, TaskStatusInfo}; +#[cfg(feature = "api-docs")] use crate::util::apidoc::OpenApiServerInfo; use crate::{contexts::SessionContext, datasets::external::netcdfcf::NetCdfCfDataProvider}; use actix_web::{ @@ -27,13 +28,17 @@ use serde::{Deserialize, Serialize}; use std::path::PathBuf; use std::sync::Arc; use tracing::debug; +#[cfg(feature = "api-docs")] use utoipa::openapi::security::{HttpAuthScheme, HttpBuilder, SecurityScheme}; -use utoipa::{IntoParams, Modify, OpenApi, ToSchema}; +use utoipa::{IntoParams, ToSchema}; +#[cfg(feature = "api-docs")] +use utoipa::{Modify, OpenApi}; pub const EBV_OVERVIEW_TASK_TYPE: &str = "ebv-overview"; pub const EBV_MULTI_OVERVIEW_TASK_TYPE: &str = "ebv-multi-overview"; pub const EBV_REMOVE_OVERVIEW_TASK_TYPE: &str = "ebv-remove-overview"; +#[cfg(feature = "api-docs")] #[derive(OpenApi)] #[openapi( paths( @@ -56,8 +61,10 @@ pub const EBV_REMOVE_OVERVIEW_TASK_TYPE: &str = "ebv-remove-overview"; )] pub struct ApiDoc; +#[cfg(feature = "api-docs")] struct SecurityAddon; +#[cfg(feature = "api-docs")] impl Modify for SecurityAddon { fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) { let Some(components) = openapi.components.as_mut() else { @@ -79,8 +86,10 @@ impl Modify for SecurityAddon { } } +#[cfg(feature = "api-docs")] struct ApiDocInfo; +#[cfg(feature = "api-docs")] impl Modify for ApiDocInfo { fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) { openapi.info.title = "Geo Engine EBV API".to_string(); diff --git a/geoengine/services/src/api/mod.rs b/geoengine/services/src/api/mod.rs index 7fe2801e3..85bcefa90 100644 --- a/geoengine/services/src/api/mod.rs +++ b/geoengine/services/src/api/mod.rs @@ -1,3 +1,4 @@ +#[cfg(feature = "api-docs")] pub mod apidoc; pub mod handlers; pub mod model; diff --git a/geoengine/services/src/bin/geoengine-cli.rs b/geoengine/services/src/bin/geoengine-cli.rs index cad4045b2..ca0f9066e 100644 --- a/geoengine/services/src/bin/geoengine-cli.rs +++ b/geoengine/services/src/bin/geoengine-cli.rs @@ -1,9 +1,10 @@ use clap::{Parser, Subcommand}; use geoengine_services::cli::{ - CheckSuccessfulStartup, ExpressionToolchainFile, Heartbeat, OpenAPIGenerate, StacImport, - TileImport, check_heartbeat, check_successful_startup, output_openapi_json, - output_toolchain_file, stac_import, tile_import, + CheckSuccessfulStartup, ExpressionToolchainFile, Heartbeat, StacImport, TileImport, + check_heartbeat, check_successful_startup, output_toolchain_file, stac_import, tile_import, }; +#[cfg(feature = "api-docs")] +use geoengine_services::cli::{OpenAPIGenerate, output_openapi_json}; /// CLI for Geo Engine Utilities #[derive(Debug, Parser)] @@ -22,6 +23,7 @@ enum Commands { Heartbeat(Heartbeat), /// Outputs OpenAPI JSON + #[cfg(feature = "api-docs")] #[command(name = "openapi")] OpenAPI(OpenAPIGenerate), @@ -41,6 +43,7 @@ impl Commands { match self { Commands::CheckSuccessfulStartup(params) => check_successful_startup(params).await, Commands::Heartbeat(params) => check_heartbeat(params).await, + #[cfg(feature = "api-docs")] Commands::OpenAPI(params) => output_openapi_json(params).await, Commands::StacImport(params) => stac_import(params).await, Commands::TileImport(params) => tile_import(params).await, diff --git a/geoengine/services/src/cli/mod.rs b/geoengine/services/src/cli/mod.rs index e8ee25a1c..e0720bd76 100644 --- a/geoengine/services/src/cli/mod.rs +++ b/geoengine/services/src/cli/mod.rs @@ -1,6 +1,7 @@ mod check_successful_startup; mod expression_toolchain_file; mod heartbeat; +#[cfg(feature = "api-docs")] mod openapi; mod stac_import; mod tile_import; @@ -8,6 +9,7 @@ mod tile_import; pub use check_successful_startup::{CheckSuccessfulStartup, check_successful_startup}; pub use expression_toolchain_file::{ExpressionToolchainFile, output_toolchain_file}; pub use heartbeat::{Heartbeat, check_heartbeat}; +#[cfg(feature = "api-docs")] pub use openapi::{OpenAPIGenerate, output_openapi_json}; pub use stac_import::{StacImport, stac_import}; pub use tile_import::{TileImport, tile_import}; diff --git a/geoengine/services/src/server.rs b/geoengine/services/src/server.rs index 9d60ec57d..9ea3a86c0 100644 --- a/geoengine/services/src/server.rs +++ b/geoengine/services/src/server.rs @@ -1,3 +1,4 @@ +#[cfg(feature = "swagger-ui")] use crate::api::apidoc::ApiDoc; use crate::api::handlers; use crate::config::{self, get_config_element}; @@ -7,9 +8,11 @@ use crate::error::{Error, Result}; use crate::users::UserSession; use crate::util::middleware::OutputRequestId; use crate::util::postgres::DatabaseConnectionConfig; +#[cfg(feature = "swagger-ui")] +use crate::util::server::serve_openapi_json; use crate::util::server::{ CustomRootSpanBuilder, calculate_max_blocking_threads_per_worker, configure_extractors, - connection_init, log_server_info, render_404, render_405, serve_openapi_json, + connection_init, log_server_info, render_404, render_405, }; use actix_files::Files; use actix_web::{App, FromRequest, HttpServer, http, middleware, web}; @@ -21,7 +24,9 @@ use std::net::SocketAddr; use std::path::PathBuf; use tracing::info; use tracing_actix_web::TracingLogger; +#[cfg(feature = "swagger-ui")] use utoipa::OpenApi; +#[cfg(feature = "swagger-ui")] use utoipa_swagger_ui::SwaggerUi; async fn start( @@ -35,8 +40,29 @@ where C: ApplicationContext, C::Session: FromRequest, { - let wrapped_ctx = web::Data::new(app_ctx); + start_without_swagger( + static_files_dir, + bind_address, + api_prefix, + version_api, + app_ctx, + ) + .await +} +#[cfg(feature = "swagger-ui")] +async fn start_without_swagger( + static_files_dir: Option, + bind_address: SocketAddr, + api_prefix: String, + version_api: bool, + app_ctx: C, +) -> Result<(), Error> +where + C: ApplicationContext, + C::Session: FromRequest, +{ + let wrapped_ctx = web::Data::new(app_ctx); let openapi = ApiDoc::openapi(); HttpServer::new(move || { @@ -61,8 +87,8 @@ where web::get().to(crate::util::server::available_handler), ); + api = api.service(web::scope("/ebv").configure(handlers::ebv::init_ebv_routes::())); let mut api_urls = vec![]; - api = serve_openapi_json( api, &mut api_urls, @@ -72,21 +98,83 @@ where openapi.clone(), ); - // EBV endpoint - { - api = api.service(web::scope("/ebv").configure(handlers::ebv::init_ebv_routes::())); - - api = serve_openapi_json( - api, - &mut api_urls, - "EBV", - "../api-docs/ebv/openapi.json", - "/api-docs/ebv/openapi.json", - crate::api::handlers::ebv::ApiDoc::openapi(), + api = serve_openapi_json( + api, + &mut api_urls, + "EBV", + "../api-docs/ebv/openapi.json", + "/api-docs/ebv/openapi.json", + crate::api::handlers::ebv::ApiDoc::openapi(), + ); + + api = api.service(SwaggerUi::new("/swagger-ui/{_:.*}").urls(api_urls)); + + if version_api { + api = api.route( + "/info", + web::get().to(crate::util::server::server_info_handler), ); } - api = api.service(SwaggerUi::new("/swagger-ui/{_:.*}").urls(api_urls)); + if let Some(static_files_dir) = static_files_dir.clone() { + api = api.service(Files::new("/static", static_files_dir)); + } + + App::new() + .app_data(wrapped_ctx.clone()) + .wrap(OutputRequestId) + .wrap( + middleware::ErrorHandlers::default() + .handler(http::StatusCode::NOT_FOUND, render_404) + .handler(http::StatusCode::METHOD_NOT_ALLOWED, render_405), + ) + .wrap(TracingLogger::::new()) + .service(api) + }) + .worker_max_blocking_threads(calculate_max_blocking_threads_per_worker()) + .on_connect(connection_init) + .bind(bind_address)? + .run() + .await + .map_err(Into::into) +} + +#[cfg(not(feature = "swagger-ui"))] +async fn start_without_swagger( + static_files_dir: Option, + bind_address: SocketAddr, + api_prefix: String, + version_api: bool, + app_ctx: C, +) -> Result<(), Error> +where + C: ApplicationContext, + C::Session: FromRequest, +{ + let wrapped_ctx = web::Data::new(app_ctx); + + HttpServer::new(move || { + let mut api = web::scope(&api_prefix) + .configure(configure_extractors) + .configure(handlers::datasets::init_dataset_routes::) + .configure(handlers::layers::init_layer_routes::) + .configure(handlers::permissions::init_permissions_routes::) + .configure(handlers::plots::init_plot_routes::) + .configure(handlers::projects::init_project_routes::) + .configure(handlers::users::init_user_routes::) + .configure(handlers::spatial_references::init_spatial_reference_routes::) + .configure(handlers::upload::init_upload_routes::) + .configure(handlers::tasks::init_task_routes::) + .configure(handlers::wcs::init_wcs_routes::) + .configure(handlers::wfs::init_wfs_routes::) + .configure(handlers::wms::init_wms_routes::) + .configure(handlers::workflows::init_workflow_routes::) + .configure(handlers::machine_learning::init_ml_routes::) + .route( + "/available", + web::get().to(crate::util::server::available_handler), + ) + .service(web::scope("/ebv").configure(handlers::ebv::init_ebv_routes::())); if version_api { api = api.route( diff --git a/geoengine/services/src/util/server.rs b/geoengine/services/src/util/server.rs index 129d34054..f7f132af7 100644 --- a/geoengine/services/src/util/server.rs +++ b/geoengine/services/src/util/server.rs @@ -5,7 +5,9 @@ use actix_http::body::{BoxBody, EitherBody, MessageBody}; use actix_http::header::{HeaderName, HeaderValue}; use actix_http::uri::PathAndQuery; use actix_http::{Extensions, HttpMessage, StatusCode}; -use actix_web::dev::{ServiceFactory, ServiceRequest, ServiceResponse}; +#[cfg(feature = "swagger-ui")] +use actix_web::dev::ServiceFactory; +use actix_web::dev::{ServiceRequest, ServiceResponse}; use actix_web::error::{InternalError, JsonPayloadError, QueryPayloadError}; use actix_web::{HttpRequest, HttpResponse, http, middleware, web}; use futures::future::BoxFuture; @@ -18,7 +20,9 @@ use tracing::debug; use tracing::info; use tracing_actix_web::{RequestId, RootSpanBuilder}; use url::Url; -use utoipa::{ToSchema, openapi::OpenApi}; +use utoipa::ToSchema; +#[cfg(feature = "swagger-ui")] +use utoipa::openapi::OpenApi; /// Custom root span for web requests that paste a request id to all logs. pub struct CustomRootSpanBuilder; @@ -254,6 +258,7 @@ pub(crate) fn render_405( // this is a workaround to be able to serve swagger UI and the openapi.json behind a proxy (/api) // TODO: remove this when utoipa allows configuring the paths to serve the openapi.json and to include it in the swagger UI separately +#[cfg(feature = "swagger-ui")] pub fn serve_openapi_json< T: ServiceFactory, >( @@ -298,6 +303,7 @@ pub(crate) fn log_server_info() -> Result<()> { info!("External Address: {external_address} "); + #[cfg(feature = "swagger-ui")] info!( "API Documentation: {}", external_address.join("swagger-ui/")?