mirror of
https://github.com/maplibre/martin.git
synced 2024-12-19 21:01:45 +03:00
Clean up configuration system to use Clap (#415)
* Use latest Clap-derive (currently v4rc, but should be public within a few days) * reorganize configuration to streamline different config sources into one Config (using multiple ConfigBuilders)
This commit is contained in:
parent
c7ce464005
commit
47ed143d8f
180
Cargo.lock
generated
180
Cargo.lock
generated
@ -107,16 +107,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "actix-router"
|
name = "actix-router"
|
||||||
version = "0.5.0"
|
version = "0.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eb60846b52c118f2f04a56cc90880a274271c489b2498623d58176f8ca21fa80"
|
checksum = "d66ff4d247d2b160861fa2866457e85706833527840e4133f8f49aa423a38799"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytestring",
|
"bytestring",
|
||||||
"firestorm",
|
|
||||||
"http",
|
"http",
|
||||||
"log",
|
|
||||||
"regex",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -458,16 +457,44 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "3.2.21"
|
version = "3.2.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1ed5341b2301a26ab80be5cbdced622e80ed808483c52e45e3310a877d3b37d7"
|
checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"clap_lex",
|
"clap_lex 0.2.4",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"textwrap",
|
"textwrap",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "4.0.0-rc.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7233bf306993c874a6edc363281e83770889877c9d5ee7f656249c65d7e7aa62"
|
||||||
|
dependencies = [
|
||||||
|
"atty",
|
||||||
|
"bitflags",
|
||||||
|
"clap_derive",
|
||||||
|
"clap_lex 0.3.0",
|
||||||
|
"once_cell",
|
||||||
|
"strsim",
|
||||||
|
"termcolor",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_derive"
|
||||||
|
version = "4.0.0-rc.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "51eef4d62724bf369e9ca7458cfde0c55263708b4552020058fba384864e8c23"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro-error",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_lex"
|
name = "clap_lex"
|
||||||
version = "0.2.4"
|
version = "0.2.4"
|
||||||
@ -477,6 +504,15 @@ dependencies = [
|
|||||||
"os_str_bytes",
|
"os_str_bytes",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8"
|
||||||
|
dependencies = [
|
||||||
|
"os_str_bytes",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "convert_case"
|
name = "convert_case"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@ -485,9 +521,9 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cookie"
|
name = "cookie"
|
||||||
version = "0.16.0"
|
version = "0.16.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94d4706de1b0fa5b132270cddffa8585166037822e260a944fe161acd137ca05"
|
checksum = "344adc371239ef32293cb1c4fe519592fcf21206c79c02854320afcdf3ab4917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"time",
|
"time",
|
||||||
@ -522,7 +558,7 @@ dependencies = [
|
|||||||
"atty",
|
"atty",
|
||||||
"cast",
|
"cast",
|
||||||
"ciborium",
|
"ciborium",
|
||||||
"clap",
|
"clap 3.2.22",
|
||||||
"criterion-plot",
|
"criterion-plot",
|
||||||
"futures",
|
"futures",
|
||||||
"itertools",
|
"itertools",
|
||||||
@ -620,27 +656,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
version = "0.10.3"
|
version = "0.10.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506"
|
checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"block-buffer",
|
"block-buffer",
|
||||||
"crypto-common",
|
"crypto-common",
|
||||||
"subtle",
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "docopt"
|
|
||||||
version = "1.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7f3f119846c823f9eafcf953a8f6ffb6ed69bf6240883261a7f13b634579a51f"
|
|
||||||
dependencies = [
|
|
||||||
"lazy_static",
|
|
||||||
"regex",
|
|
||||||
"serde",
|
|
||||||
"strsim",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.8.0"
|
version = "1.8.0"
|
||||||
@ -675,12 +699,6 @@ version = "0.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
|
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "firestorm"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2c5f6c2c942da57e2aaaa84b8a521489486f14e75e7fa91dab70aba913975f98"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flate2"
|
name = "flate2"
|
||||||
version = "1.0.24"
|
version = "1.0.24"
|
||||||
@ -862,6 +880,12 @@ version = "0.12.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.1.19"
|
version = "0.1.19"
|
||||||
@ -946,9 +970,9 @@ checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jobserver"
|
name = "jobserver"
|
||||||
version = "0.1.24"
|
version = "0.1.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa"
|
checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
@ -976,9 +1000,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.132"
|
version = "0.2.133"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"
|
checksum = "c0f80d65747a3e43d1596c7c5492d95d5edddaabd45a7fcdb02b95f644164966"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "local-channel"
|
name = "local-channel"
|
||||||
@ -1000,9 +1024,9 @@ checksum = "e34f76eb3611940e0e7d53a9aaa4e6a3151f69541a282fd0dad5571420c53ff1"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
version = "0.4.8"
|
version = "0.4.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9f80bf5aacaf25cbfc8210d1cfb718f2bf3b11c4c54e5afe36c236853a8ec390"
|
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"scopeguard",
|
"scopeguard",
|
||||||
@ -1030,8 +1054,8 @@ dependencies = [
|
|||||||
"bb8",
|
"bb8",
|
||||||
"bb8-postgres",
|
"bb8-postgres",
|
||||||
"cargo-husky",
|
"cargo-husky",
|
||||||
|
"clap 4.0.0-rc.3",
|
||||||
"criterion",
|
"criterion",
|
||||||
"docopt",
|
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"itertools",
|
"itertools",
|
||||||
"log",
|
"log",
|
||||||
@ -1051,9 +1075,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "md-5"
|
name = "md-5"
|
||||||
version = "0.10.4"
|
version = "0.10.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "66b48670c893079d3c2ed79114e3644b7004df1c361a4e0ad52e2e6940d07c3d"
|
checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
@ -1130,9 +1154,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.14.0"
|
version = "1.15.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0"
|
checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oorandom"
|
name = "oorandom"
|
||||||
@ -1362,10 +1386,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro-error"
|
||||||
version = "1.0.43"
|
version = "1.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
|
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-error-attr",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error-attr"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.44"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7bd7356a8122b6c4a24a82b278680c73357984ca2fc79a0f9fa6dea7dced7c58"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
@ -1402,9 +1450,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_core"
|
name = "rand_core"
|
||||||
version = "0.6.3"
|
version = "0.6.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom",
|
||||||
]
|
]
|
||||||
@ -1497,18 +1545,18 @@ checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.144"
|
version = "1.0.145"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860"
|
checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.144"
|
version = "1.0.145"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00"
|
checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -1574,9 +1622,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha1"
|
name = "sha1"
|
||||||
version = "0.10.4"
|
version = "0.10.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "006769ba83e921b3085caa8334186b00cf92b4cb1a6cf4632fbccc8eff5c7549"
|
checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cpufeatures",
|
"cpufeatures",
|
||||||
@ -1585,9 +1633,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha2"
|
name = "sha2"
|
||||||
version = "0.10.5"
|
version = "0.10.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf9db03534dff993187064c4e0c05a5708d2a9728ace9a8959b77bedf415dac5"
|
checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cpufeatures",
|
"cpufeatures",
|
||||||
@ -1658,9 +1706,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.99"
|
version = "1.0.101"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13"
|
checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -1678,9 +1726,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "textwrap"
|
name = "textwrap"
|
||||||
version = "0.15.0"
|
version = "0.15.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
|
checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tilejson"
|
name = "tilejson"
|
||||||
@ -1738,9 +1786,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.21.0"
|
version = "1.21.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "89797afd69d206ccd11fb0ea560a44bbb87731d020670e79416d442919257d42"
|
checksum = "0020c875007ad96677dcc890298f4b942882c5d4eb7cc8f439fc3bf813dc9c95"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"bytes",
|
"bytes",
|
||||||
@ -1840,24 +1888,24 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.3"
|
version = "1.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf"
|
checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-normalization"
|
name = "unicode-normalization"
|
||||||
version = "0.1.21"
|
version = "0.1.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6"
|
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"tinyvec",
|
"tinyvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unsafe-libyaml"
|
name = "unsafe-libyaml"
|
||||||
version = "0.2.2"
|
version = "0.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "931179334a56395bcf64ba5e0ff56781381c1a5832178280c7d7f91d1679aeb0"
|
checksum = "c1e5fa573d8ac5f1a856f8d7be41d390ee973daf97c806b2c1a465e4e1406e68"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
|
@ -24,7 +24,7 @@ actix-web = "4"
|
|||||||
async-trait = "0.1"
|
async-trait = "0.1"
|
||||||
bb8 = "0.8"
|
bb8 = "0.8"
|
||||||
bb8-postgres = "0.8"
|
bb8-postgres = "0.8"
|
||||||
docopt = "1"
|
clap = { version = "4.0.0-rc", features = ["derive"] }
|
||||||
env_logger = "0.9"
|
env_logger = "0.9"
|
||||||
itertools = "0.10"
|
itertools = "0.10"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
22
README.md
22
README.md
@ -427,27 +427,27 @@ martin --config config.yaml
|
|||||||
You can find an example of a configuration file [here](https://github.com/maplibre/martin/blob/main/tests/config.yaml).
|
You can find an example of a configuration file [here](https://github.com/maplibre/martin/blob/main/tests/config.yaml).
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# The socket address to bind [default: 0.0.0.0:3000]
|
|
||||||
listen_addresses: '0.0.0.0:3000'
|
|
||||||
|
|
||||||
# Database connection string
|
# Database connection string
|
||||||
connection_string: 'postgres://postgres@localhost:5432/db'
|
connection_string: 'postgres://postgres@localhost:5432/db'
|
||||||
|
|
||||||
# Maximum connections pool size [default: 20]
|
# Trust invalid certificates. This introduces significant vulnerabilities, and should only be used as a last resort.
|
||||||
pool_size: 20
|
danger_accept_invalid_certs: false
|
||||||
|
|
||||||
|
# If a spatial table has SRID 0, then this SRID will be used as a fallback
|
||||||
|
default_srid: 4326
|
||||||
|
|
||||||
# Connection keep alive timeout [default: 75]
|
# Connection keep alive timeout [default: 75]
|
||||||
keep_alive: 75
|
keep_alive: 75
|
||||||
|
|
||||||
|
# The socket address to bind [default: 0.0.0.0:3000]
|
||||||
|
listen_addresses: '0.0.0.0:3000'
|
||||||
|
|
||||||
|
# Maximum connections pool size [default: 20]
|
||||||
|
pool_size: 20
|
||||||
|
|
||||||
# Number of web server workers
|
# Number of web server workers
|
||||||
worker_processes: 8
|
worker_processes: 8
|
||||||
|
|
||||||
# If a spatial table has SRID 0, then this default SRID will be used as a fallback
|
|
||||||
default_srid: 4326
|
|
||||||
|
|
||||||
# Trust invalid certificates. This introduces significant vulnerabilities, and should only be used as a last resort.
|
|
||||||
danger_accept_invalid_certs: false
|
|
||||||
|
|
||||||
# Associative arrays of table sources
|
# Associative arrays of table sources
|
||||||
table_sources:
|
table_sources:
|
||||||
public.table_source:
|
public.table_source:
|
||||||
|
275
src/bin/main.rs
275
src/bin/main.rs
@ -1,211 +1,109 @@
|
|||||||
use std::{env, io};
|
use std::{env, io};
|
||||||
|
|
||||||
use actix_web::dev::Server;
|
use actix_web::dev::Server;
|
||||||
use docopt::Docopt;
|
use clap::Parser;
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
use martin::config::{read_config, Config, ConfigBuilder};
|
use martin::config::{read_config, ConfigBuilder};
|
||||||
use martin::db::{check_postgis_version, get_connection, setup_connection_pool, Pool};
|
use martin::db::configure_db_source;
|
||||||
use martin::function_source::get_function_sources;
|
use martin::server;
|
||||||
use martin::table_source::get_table_sources;
|
|
||||||
use martin::{prettify_error, server};
|
|
||||||
use serde::Deserialize;
|
|
||||||
|
|
||||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
const REQUIRED_POSTGIS_VERSION: &str = ">= 2.4.0";
|
|
||||||
|
|
||||||
pub const USAGE: &str = "
|
#[derive(Parser, Debug)]
|
||||||
Martin - PostGIS Mapbox Vector Tiles server.
|
#[command(about, version)]
|
||||||
|
|
||||||
Usage:
|
|
||||||
martin [options] [<connection>]
|
|
||||||
martin -h | --help
|
|
||||||
martin -v | --version
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-h --help Show this screen.
|
|
||||||
-v --version Show version.
|
|
||||||
--config=<path> Path to config file.
|
|
||||||
--keep-alive=<n> Connection keep alive timeout [default: 75].
|
|
||||||
--listen-addresses=<n> The socket address to bind [default: 0.0.0.0:3000].
|
|
||||||
--default-srid=<n> If a spatial table has SRID 0, then this default SRID will be used as a fallback.
|
|
||||||
--pool-size=<n> Maximum connections pool size [default: 20].
|
|
||||||
--workers=<n> Number of web server workers.
|
|
||||||
--ca-root-file=<path> Loads trusted root certificates from a file. The file should contain a sequence of PEM-formatted CA certificates.
|
|
||||||
--danger-accept-invalid-certs Trust invalid certificates. This introduces significant vulnerabilities, and should only be used as a last resort.
|
|
||||||
--watch [IGNORED] This flag is no longer supported, and will be ignored.
|
|
||||||
";
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
pub arg_connection: Option<String>,
|
/// Database connection string
|
||||||
pub flag_config: Option<String>,
|
pub connection: Option<String>,
|
||||||
pub flag_help: bool,
|
/// Path to config file.
|
||||||
pub flag_keep_alive: Option<usize>,
|
#[arg(short, long)]
|
||||||
pub flag_listen_addresses: Option<String>,
|
pub config: Option<String>,
|
||||||
pub flag_pool_size: Option<u32>,
|
/// Loads trusted root certificates from a file. The file should contain a sequence of PEM-formatted CA certificates.
|
||||||
pub flag_watch: bool,
|
#[arg(long)]
|
||||||
pub flag_version: bool,
|
pub ca_root_file: Option<String>,
|
||||||
pub flag_workers: Option<usize>,
|
/// Trust invalid certificates. This introduces significant vulnerabilities, and should only be used as a last resort.
|
||||||
pub flag_default_srid: Option<i32>,
|
#[arg(long)]
|
||||||
pub flag_ca_root_file: Option<String>,
|
pub danger_accept_invalid_certs: bool,
|
||||||
pub flag_danger_accept_invalid_certs: bool,
|
/// If a spatial table has SRID 0, then this default SRID will be used as a fallback.
|
||||||
|
#[arg(short, long)]
|
||||||
|
pub default_srid: Option<i32>,
|
||||||
|
#[arg(help = format!("Connection keep alive timeout. [DEFAULT: {}]", ConfigBuilder::KEEP_ALIVE_DEFAULT),
|
||||||
|
short, long)]
|
||||||
|
pub keep_alive: Option<usize>,
|
||||||
|
#[arg(help = format!("The socket address to bind. [DEFAULT: {}]", ConfigBuilder::LISTEN_ADDRESSES_DEFAULT),
|
||||||
|
short, long)]
|
||||||
|
pub listen_addresses: Option<String>,
|
||||||
|
#[arg(help = format!("Maximum connections pool size [DEFAULT: {}]", ConfigBuilder::POOL_SIZE_DEFAULT),
|
||||||
|
short, long)]
|
||||||
|
pub pool_size: Option<u32>,
|
||||||
|
/// Scan for new sources on sources list requests
|
||||||
|
#[arg(short, long, hide = true)]
|
||||||
|
pub watch: bool,
|
||||||
|
/// Number of web server workers
|
||||||
|
#[arg(short = 'W', long)]
|
||||||
|
pub workers: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn generate_config(args: Args, pool: &Pool) -> io::Result<Config> {
|
impl From<Args> for ConfigBuilder {
|
||||||
let connection_string = args.arg_connection.clone().ok_or_else(|| {
|
fn from(args: Args) -> Self {
|
||||||
io::Error::new(
|
if args.watch {
|
||||||
io::ErrorKind::Other,
|
warn!("The --watch flag is no longer supported, and will be ignored");
|
||||||
"Database connection string is not set",
|
}
|
||||||
)
|
if env::var_os("WATCH_MODE").is_some() {
|
||||||
})?;
|
warn!(
|
||||||
|
"The WATCH_MODE environment variable is no longer supported, and will be ignored"
|
||||||
let mut connection = get_connection(pool).await?;
|
|
||||||
let table_sources = get_table_sources(&mut connection, &args.flag_default_srid).await?;
|
|
||||||
let function_sources = get_function_sources(&mut connection).await?;
|
|
||||||
|
|
||||||
let config = ConfigBuilder {
|
|
||||||
connection_string,
|
|
||||||
keep_alive: args.flag_keep_alive,
|
|
||||||
listen_addresses: args.flag_listen_addresses,
|
|
||||||
default_srid: args.flag_default_srid,
|
|
||||||
pool_size: args.flag_pool_size,
|
|
||||||
worker_processes: args.flag_workers,
|
|
||||||
table_sources: Some(table_sources),
|
|
||||||
function_sources: Some(function_sources),
|
|
||||||
ca_root_file: None,
|
|
||||||
danger_accept_invalid_certs: Some(args.flag_danger_accept_invalid_certs),
|
|
||||||
};
|
|
||||||
|
|
||||||
let config = config.finalize();
|
|
||||||
Ok(config)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn setup_from_config(file_name: String) -> io::Result<(Config, Pool)> {
|
|
||||||
let config = read_config(&file_name).map_err(|e| prettify_error!(e, "Can't read config"))?;
|
|
||||||
|
|
||||||
let pool = setup_connection_pool(
|
|
||||||
&config.connection_string,
|
|
||||||
&config.ca_root_file,
|
|
||||||
Some(config.pool_size),
|
|
||||||
config.danger_accept_invalid_certs,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.map_err(|e| prettify_error!(e, "Can't setup connection pool"))?;
|
|
||||||
|
|
||||||
if let Some(table_sources) = &config.table_sources {
|
|
||||||
for table_source in table_sources.values() {
|
|
||||||
info!(
|
|
||||||
r#"Found "{}" table source with "{}" column ({}, SRID={})"#,
|
|
||||||
table_source.id,
|
|
||||||
table_source.geometry_column,
|
|
||||||
table_source
|
|
||||||
.geometry_type
|
|
||||||
.as_ref()
|
|
||||||
.unwrap_or(&"null".to_string()),
|
|
||||||
table_source.srid
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(function_sources) = &config.function_sources {
|
ConfigBuilder {
|
||||||
for function_source in function_sources.values() {
|
connection_string: args.connection.or_else(|| {
|
||||||
info!("Found {} function source", function_source.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
info!("Connected to {}", config.connection_string);
|
|
||||||
|
|
||||||
Ok((config, pool))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn setup_from_args(args: Args) -> io::Result<(Config, Pool)> {
|
|
||||||
let connection_string = args.arg_connection.clone().ok_or_else(|| {
|
|
||||||
io::Error::new(
|
|
||||||
io::ErrorKind::Other,
|
|
||||||
"Database connection string is not set",
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
info!("Connecting to database");
|
|
||||||
let pool = setup_connection_pool(
|
|
||||||
&connection_string,
|
|
||||||
&args.flag_ca_root_file,
|
|
||||||
args.flag_pool_size,
|
|
||||||
args.flag_danger_accept_invalid_certs,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.map_err(|e| prettify_error!(e, "Can't setup connection pool"))?;
|
|
||||||
|
|
||||||
info!("Scanning database");
|
|
||||||
let config = generate_config(args, &pool)
|
|
||||||
.await
|
|
||||||
.map_err(|e| prettify_error!(e, "Can't generate config"))?;
|
|
||||||
|
|
||||||
Ok((config, pool))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_env(args: Args) -> Args {
|
|
||||||
let arg_connection = args.arg_connection.or_else(|| {
|
|
||||||
env::var_os("DATABASE_URL").and_then(|connection| connection.into_string().ok())
|
env::var_os("DATABASE_URL").and_then(|connection| connection.into_string().ok())
|
||||||
});
|
}),
|
||||||
|
ca_root_file: args.ca_root_file.or_else(|| {
|
||||||
let flag_default_srid = args.flag_default_srid.or_else(|| {
|
env::var_os("CA_ROOT_FILE").and_then(|connection| connection.into_string().ok())
|
||||||
|
}),
|
||||||
|
danger_accept_invalid_certs: if args.danger_accept_invalid_certs
|
||||||
|
|| env::var_os("DANGER_ACCEPT_INVALID_CERTS").is_some()
|
||||||
|
{
|
||||||
|
Some(true)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
default_srid: args.default_srid.or_else(|| {
|
||||||
env::var_os("DEFAULT_SRID").and_then(|srid| {
|
env::var_os("DEFAULT_SRID").and_then(|srid| {
|
||||||
srid.into_string()
|
srid.into_string()
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|srid| srid.parse::<i32>().ok())
|
.and_then(|srid| srid.parse::<i32>().ok())
|
||||||
})
|
})
|
||||||
});
|
}),
|
||||||
|
keep_alive: args.keep_alive,
|
||||||
let flag_ca_root_file = args.flag_ca_root_file.or_else(|| {
|
listen_addresses: args.listen_addresses,
|
||||||
env::var_os("CA_ROOT_FILE").and_then(|connection| connection.into_string().ok())
|
pool_size: args.pool_size,
|
||||||
});
|
worker_processes: args.workers,
|
||||||
|
table_sources: None,
|
||||||
let flag_danger_accept_invalid_certs = args.flag_danger_accept_invalid_certs
|
function_sources: None,
|
||||||
|| env::var_os("DANGER_ACCEPT_INVALID_CERTS").is_some();
|
|
||||||
|
|
||||||
if args.flag_watch {
|
|
||||||
warn!("The --watch flag is no longer supported, and will be ignored");
|
|
||||||
}
|
}
|
||||||
if env::var_os("WATCH_MODE").is_some() {
|
|
||||||
warn!("The WATCH_MODE environment variable is no longer supported, and will be ignored");
|
|
||||||
}
|
|
||||||
|
|
||||||
Args {
|
|
||||||
arg_connection,
|
|
||||||
flag_default_srid,
|
|
||||||
flag_ca_root_file,
|
|
||||||
flag_danger_accept_invalid_certs,
|
|
||||||
..args
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn start(args: Args) -> io::Result<Server> {
|
async fn start(args: Args) -> io::Result<Server> {
|
||||||
info!("Starting martin v{VERSION}");
|
info!("Starting Martin v{VERSION}");
|
||||||
|
|
||||||
let (config, pool) = match args.flag_config {
|
let mut config = if let Some(ref config_file_name) = args.config {
|
||||||
Some(config_file_name) => {
|
|
||||||
info!("Using {config_file_name}");
|
info!("Using {config_file_name}");
|
||||||
setup_from_config(config_file_name).await?
|
let cfg = read_config(config_file_name)?;
|
||||||
}
|
let mut builder = ConfigBuilder::from(args);
|
||||||
None => {
|
builder.merge(cfg);
|
||||||
info!("Config is not set");
|
builder.finalize()?
|
||||||
setup_from_args(args).await?
|
} else {
|
||||||
}
|
info!("Config file is not specified");
|
||||||
|
ConfigBuilder::from(args).finalize()?
|
||||||
};
|
};
|
||||||
|
|
||||||
let matches = check_postgis_version(REQUIRED_POSTGIS_VERSION, &pool)
|
let pool = configure_db_source(&mut config).await?;
|
||||||
.await
|
|
||||||
.map_err(|e| prettify_error!(e, "Can't check PostGIS version"))?;
|
|
||||||
|
|
||||||
if !matches {
|
|
||||||
std::process::exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
let listen_addresses = config.listen_addresses.clone();
|
let listen_addresses = config.listen_addresses.clone();
|
||||||
let server = server::new(pool, config);
|
let server = server::new(pool, config);
|
||||||
info!("Martin has been started on {listen_addresses}.");
|
|
||||||
|
|
||||||
|
info!("Martin has been started on {listen_addresses}.");
|
||||||
Ok(server)
|
Ok(server)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,28 +111,7 @@ async fn start(args: Args) -> io::Result<Server> {
|
|||||||
async fn main() -> io::Result<()> {
|
async fn main() -> io::Result<()> {
|
||||||
let env = env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "martin=info");
|
let env = env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "martin=info");
|
||||||
env_logger::Builder::from_env(env).init();
|
env_logger::Builder::from_env(env).init();
|
||||||
|
match start(Args::parse()).await {
|
||||||
let args = Docopt::new(USAGE)
|
|
||||||
.and_then(|d| d.help(false).deserialize::<Args>())
|
|
||||||
.map_err(|e| prettify_error!(e, "Can't parse CLI arguments"))?;
|
|
||||||
|
|
||||||
let args = parse_env(args);
|
|
||||||
|
|
||||||
if args.flag_help {
|
|
||||||
println!("{USAGE}");
|
|
||||||
std::process::exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if args.flag_version {
|
|
||||||
println!("v{VERSION}");
|
|
||||||
std::process::exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if args.flag_danger_accept_invalid_certs {
|
|
||||||
warn!("Danger accept invalid certs enabled. You should think very carefully before using this option. If invalid certificates are trusted, any certificate for any site will be trusted for use. This includes expired certificates. This introduces significant vulnerabilities, and should only be used as a last resort.");
|
|
||||||
}
|
|
||||||
|
|
||||||
match start(args).await {
|
|
||||||
Ok(server) => server.await,
|
Ok(server) => server.await,
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
error!("{error}");
|
error!("{error}");
|
||||||
|
107
src/config.rs
107
src/config.rs
@ -5,63 +5,100 @@ use std::io::prelude::*;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::function_source::FunctionSources;
|
use crate::function_source::FunctionSources;
|
||||||
|
use crate::prettify_error;
|
||||||
use crate::table_source::TableSources;
|
use crate::table_source::TableSources;
|
||||||
use crate::utils::prettify_error;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize)]
|
#[derive(Clone, Debug, Serialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub pool_size: u32,
|
|
||||||
pub keep_alive: usize,
|
|
||||||
pub default_srid: Option<i32>,
|
|
||||||
pub worker_processes: usize,
|
|
||||||
pub listen_addresses: String,
|
|
||||||
pub connection_string: String,
|
pub connection_string: String,
|
||||||
pub table_sources: Option<TableSources>,
|
|
||||||
pub function_sources: Option<FunctionSources>,
|
|
||||||
pub ca_root_file: Option<String>,
|
pub ca_root_file: Option<String>,
|
||||||
pub danger_accept_invalid_certs: bool,
|
pub danger_accept_invalid_certs: bool,
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
pub struct ConfigBuilder {
|
|
||||||
pub pool_size: Option<u32>,
|
|
||||||
pub keep_alive: Option<usize>,
|
|
||||||
pub default_srid: Option<i32>,
|
pub default_srid: Option<i32>,
|
||||||
pub worker_processes: Option<usize>,
|
pub keep_alive: usize,
|
||||||
pub listen_addresses: Option<String>,
|
pub listen_addresses: String,
|
||||||
pub connection_string: String,
|
pub pool_size: u32,
|
||||||
|
pub worker_processes: usize,
|
||||||
|
pub use_dynamic_sources: bool,
|
||||||
pub table_sources: Option<TableSources>,
|
pub table_sources: Option<TableSources>,
|
||||||
pub function_sources: Option<FunctionSources>,
|
pub function_sources: Option<FunctionSources>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct ConfigBuilder {
|
||||||
|
pub connection_string: Option<String>,
|
||||||
pub ca_root_file: Option<String>,
|
pub ca_root_file: Option<String>,
|
||||||
pub danger_accept_invalid_certs: Option<bool>,
|
pub danger_accept_invalid_certs: Option<bool>,
|
||||||
|
pub default_srid: Option<i32>,
|
||||||
|
pub keep_alive: Option<usize>,
|
||||||
|
pub listen_addresses: Option<String>,
|
||||||
|
pub pool_size: Option<u32>,
|
||||||
|
pub worker_processes: Option<usize>,
|
||||||
|
pub table_sources: Option<TableSources>,
|
||||||
|
pub function_sources: Option<FunctionSources>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update empty option in place with a non-empty value from the second option.
|
||||||
|
fn set_option<T>(first: &mut Option<T>, second: Option<T>) {
|
||||||
|
if first.is_none() && second.is_some() {
|
||||||
|
*first = second;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConfigBuilder {
|
impl ConfigBuilder {
|
||||||
pub fn finalize(self) -> Config {
|
pub const KEEP_ALIVE_DEFAULT: usize = 75;
|
||||||
Config {
|
pub const LISTEN_ADDRESSES_DEFAULT: &'static str = "0.0.0.0:3000";
|
||||||
pool_size: self.pool_size.unwrap_or(20),
|
pub const POOL_SIZE_DEFAULT: u32 = 20;
|
||||||
keep_alive: self.keep_alive.unwrap_or(75),
|
|
||||||
|
pub fn merge(&mut self, other: ConfigBuilder) -> &mut Self {
|
||||||
|
set_option(&mut self.connection_string, other.connection_string);
|
||||||
|
set_option(&mut self.ca_root_file, other.ca_root_file);
|
||||||
|
set_option(
|
||||||
|
&mut self.danger_accept_invalid_certs,
|
||||||
|
other.danger_accept_invalid_certs,
|
||||||
|
);
|
||||||
|
set_option(&mut self.default_srid, other.default_srid);
|
||||||
|
set_option(&mut self.keep_alive, other.keep_alive);
|
||||||
|
set_option(&mut self.listen_addresses, other.listen_addresses);
|
||||||
|
set_option(&mut self.pool_size, other.pool_size);
|
||||||
|
set_option(&mut self.worker_processes, other.worker_processes);
|
||||||
|
set_option(&mut self.table_sources, other.table_sources);
|
||||||
|
set_option(&mut self.function_sources, other.function_sources);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Apply defaults to the config, and validate if there is a connection string
|
||||||
|
pub fn finalize(self) -> io::Result<Config> {
|
||||||
|
let connection_string = self.connection_string.ok_or_else(|| {
|
||||||
|
io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
"Database connection string is not set",
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
Ok(Config {
|
||||||
|
connection_string,
|
||||||
|
ca_root_file: self.ca_root_file,
|
||||||
|
danger_accept_invalid_certs: self.danger_accept_invalid_certs.unwrap_or_default(),
|
||||||
default_srid: self.default_srid,
|
default_srid: self.default_srid,
|
||||||
worker_processes: self.worker_processes.unwrap_or_else(num_cpus::get),
|
keep_alive: self.keep_alive.unwrap_or(Self::KEEP_ALIVE_DEFAULT),
|
||||||
listen_addresses: self
|
listen_addresses: self
|
||||||
.listen_addresses
|
.listen_addresses
|
||||||
.unwrap_or_else(|| "0.0.0.0:3000".to_owned()),
|
.unwrap_or_else(|| Self::LISTEN_ADDRESSES_DEFAULT.to_owned()),
|
||||||
connection_string: self.connection_string,
|
pool_size: self.pool_size.unwrap_or(Self::POOL_SIZE_DEFAULT),
|
||||||
|
worker_processes: self.worker_processes.unwrap_or_else(num_cpus::get),
|
||||||
|
use_dynamic_sources: self.table_sources.is_none() && self.function_sources.is_none(),
|
||||||
table_sources: self.table_sources,
|
table_sources: self.table_sources,
|
||||||
function_sources: self.function_sources,
|
function_sources: self.function_sources,
|
||||||
ca_root_file: self.ca_root_file,
|
})
|
||||||
danger_accept_invalid_certs: self.danger_accept_invalid_certs.unwrap_or(false),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_config(file_name: &str) -> io::Result<Config> {
|
/// Read config from a file
|
||||||
let mut file = File::open(file_name)?;
|
pub fn read_config(file_name: &str) -> io::Result<ConfigBuilder> {
|
||||||
|
let mut file = File::open(file_name)
|
||||||
|
.map_err(|e| prettify_error!(e, "Unable to open config file '{}'", file_name))?;
|
||||||
let mut contents = String::new();
|
let mut contents = String::new();
|
||||||
file.read_to_string(&mut contents)?;
|
file.read_to_string(&mut contents)
|
||||||
|
.map_err(|e| prettify_error!(e, "Unable to read config file '{}'", file_name))?;
|
||||||
let config_builder: ConfigBuilder = serde_yaml::from_str(contents.as_str())
|
serde_yaml::from_str(contents.as_str())
|
||||||
.map_err(|e| prettify_error!(e, "Can't read config file"))?;
|
.map_err(|e| prettify_error!(e, "Error parsing config file '{}'", file_name))
|
||||||
|
|
||||||
Ok(config_builder.finalize())
|
|
||||||
}
|
}
|
||||||
|
81
src/db.rs
81
src/db.rs
@ -1,9 +1,12 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use crate::config::Config;
|
||||||
|
use crate::function_source::get_function_sources;
|
||||||
|
use crate::table_source::get_table_sources;
|
||||||
use bb8::PooledConnection;
|
use bb8::PooledConnection;
|
||||||
use bb8_postgres::{tokio_postgres, PostgresConnectionManager};
|
use bb8_postgres::{tokio_postgres, PostgresConnectionManager};
|
||||||
use log::{error, info};
|
use log::info;
|
||||||
use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode};
|
use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode};
|
||||||
use postgres_openssl::MakeTlsConnector;
|
use postgres_openssl::MakeTlsConnector;
|
||||||
use semver::{Version, VersionReq};
|
use semver::{Version, VersionReq};
|
||||||
@ -14,6 +17,8 @@ pub type ConnectionManager = PostgresConnectionManager<MakeTlsConnector>;
|
|||||||
pub type Pool = bb8::Pool<ConnectionManager>;
|
pub type Pool = bb8::Pool<ConnectionManager>;
|
||||||
pub type Connection<'a> = PooledConnection<'a, ConnectionManager>;
|
pub type Connection<'a> = PooledConnection<'a, ConnectionManager>;
|
||||||
|
|
||||||
|
const REQUIRED_POSTGIS_VERSION: &str = ">= 2.4.0";
|
||||||
|
|
||||||
fn make_tls_connector(
|
fn make_tls_connector(
|
||||||
ca_root_file: &Option<String>,
|
ca_root_file: &Option<String>,
|
||||||
danger_accept_invalid_certs: bool,
|
danger_accept_invalid_certs: bool,
|
||||||
@ -36,7 +41,7 @@ fn make_tls_connector(
|
|||||||
pub async fn setup_connection_pool(
|
pub async fn setup_connection_pool(
|
||||||
connection_string: &str,
|
connection_string: &str,
|
||||||
ca_root_file: &Option<String>,
|
ca_root_file: &Option<String>,
|
||||||
pool_size: Option<u32>,
|
pool_size: u32,
|
||||||
danger_accept_invalid_certs: bool,
|
danger_accept_invalid_certs: bool,
|
||||||
) -> io::Result<Pool> {
|
) -> io::Result<Pool> {
|
||||||
let config = tokio_postgres::config::Config::from_str(connection_string)
|
let config = tokio_postgres::config::Config::from_str(connection_string)
|
||||||
@ -48,7 +53,7 @@ pub async fn setup_connection_pool(
|
|||||||
let manager = PostgresConnectionManager::new(config, tls_connector);
|
let manager = PostgresConnectionManager::new(config, tls_connector);
|
||||||
|
|
||||||
let pool = Pool::builder()
|
let pool = Pool::builder()
|
||||||
.max_size(pool_size.unwrap_or(20))
|
.max_size(pool_size)
|
||||||
.build(manager)
|
.build(manager)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| prettify_error!(e, "Can't build connection pool"))?;
|
.map_err(|e| prettify_error!(e, "Can't build connection pool"))?;
|
||||||
@ -65,7 +70,7 @@ pub async fn get_connection(pool: &Pool) -> io::Result<Connection<'_>> {
|
|||||||
Ok(connection)
|
Ok(connection)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn select_postgis_version(pool: &Pool) -> io::Result<String> {
|
async fn select_postgis_version(pool: &Pool) -> io::Result<String> {
|
||||||
let connection = get_connection(pool).await?;
|
let connection = get_connection(pool).await?;
|
||||||
|
|
||||||
let version = connection
|
let version = connection
|
||||||
@ -77,23 +82,69 @@ pub async fn select_postgis_version(pool: &Pool) -> io::Result<String> {
|
|||||||
Ok(version)
|
Ok(version)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn check_postgis_version(
|
async fn validate_postgis_version(pool: &Pool) -> io::Result<()> {
|
||||||
required_postgis_version: &str,
|
|
||||||
pool: &Pool,
|
|
||||||
) -> io::Result<bool> {
|
|
||||||
let postgis_version = select_postgis_version(pool).await?;
|
let postgis_version = select_postgis_version(pool).await?;
|
||||||
|
let req = VersionReq::parse(REQUIRED_POSTGIS_VERSION)
|
||||||
let req = VersionReq::parse(required_postgis_version)
|
|
||||||
.map_err(|e| prettify_error!(e, "Can't parse required PostGIS version"))?;
|
.map_err(|e| prettify_error!(e, "Can't parse required PostGIS version"))?;
|
||||||
|
|
||||||
let version = Version::parse(postgis_version.as_str())
|
let version = Version::parse(postgis_version.as_str())
|
||||||
.map_err(|e| prettify_error!(e, "Can't parse database PostGIS version"))?;
|
.map_err(|e| prettify_error!(e, "Can't parse database PostGIS version"))?;
|
||||||
|
if req.matches(&version) {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(io::Error::new(io::ErrorKind::Other, format!("Martin requires PostGIS {REQUIRED_POSTGIS_VERSION}, current version is {postgis_version}")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let matches = req.matches(&version);
|
pub async fn configure_db_source(mut config: &mut Config) -> io::Result<Pool> {
|
||||||
|
info!("Connecting to database");
|
||||||
|
let pool = setup_connection_pool(
|
||||||
|
&config.connection_string,
|
||||||
|
&config.ca_root_file,
|
||||||
|
config.pool_size,
|
||||||
|
config.danger_accept_invalid_certs,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
if !matches {
|
validate_postgis_version(&pool).await?;
|
||||||
error!("Martin requires PostGIS {required_postgis_version}, current version is {postgis_version}");
|
|
||||||
|
let info_prefix = if config.use_dynamic_sources {
|
||||||
|
info!("Automatically detecting table and function sources");
|
||||||
|
let mut connection = get_connection(&pool).await?;
|
||||||
|
|
||||||
|
let sources = get_table_sources(&mut connection, config.default_srid).await?;
|
||||||
|
if sources.is_empty() {
|
||||||
|
info!("No table sources found");
|
||||||
|
} else {
|
||||||
|
config.table_sources = Some(sources);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(matches)
|
let sources = get_function_sources(&mut connection).await?;
|
||||||
|
if sources.is_empty() {
|
||||||
|
info!("No function sources found");
|
||||||
|
} else {
|
||||||
|
config.function_sources = Some(sources);
|
||||||
|
}
|
||||||
|
|
||||||
|
"Found"
|
||||||
|
} else {
|
||||||
|
"Loaded"
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(table_sources) = &config.table_sources {
|
||||||
|
for table_source in table_sources.values() {
|
||||||
|
info!(
|
||||||
|
r#"{info_prefix} "{}" table source with "{}" column ({}, SRID={})"#,
|
||||||
|
table_source.id,
|
||||||
|
table_source.geometry_column,
|
||||||
|
table_source.geometry_type.as_deref().unwrap_or("null"),
|
||||||
|
table_source.srid
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(function_sources) = &config.function_sources {
|
||||||
|
for function_source in function_sources.values() {
|
||||||
|
info!("{info_prefix} {} function source", function_source.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(pool)
|
||||||
}
|
}
|
||||||
|
@ -166,7 +166,7 @@ pub async fn make_pool() -> Pool {
|
|||||||
let connection_string: String = env::var("DATABASE_URL").unwrap();
|
let connection_string: String = env::var("DATABASE_URL").unwrap();
|
||||||
info!("Connecting to {connection_string}");
|
info!("Connecting to {connection_string}");
|
||||||
|
|
||||||
let pool = setup_connection_pool(&connection_string, &None, Some(1), false)
|
let pool = setup_connection_pool(&connection_string, &None, 1, false)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
info!("Connected to {connection_string}");
|
info!("Connected to {connection_string}");
|
||||||
|
@ -2,7 +2,6 @@ use std::collections::HashMap;
|
|||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use log::info;
|
|
||||||
use postgres::types::Type;
|
use postgres::types::Type;
|
||||||
use postgres_protocol::escape::escape_identifier;
|
use postgres_protocol::escape::escape_identifier;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -139,8 +138,6 @@ pub async fn get_function_sources(conn: &mut Connection<'_>) -> Result<FunctionS
|
|||||||
let function: String = row.get("routine_name");
|
let function: String = row.get("routine_name");
|
||||||
let id = format!("{schema}.{function}");
|
let id = format!("{schema}.{function}");
|
||||||
|
|
||||||
info!("Found {id} function source");
|
|
||||||
|
|
||||||
let source = FunctionSource {
|
let source = FunctionSource {
|
||||||
id: id.clone(),
|
id: id.clone(),
|
||||||
schema,
|
schema,
|
||||||
@ -153,9 +150,5 @@ pub async fn get_function_sources(conn: &mut Connection<'_>) -> Result<FunctionS
|
|||||||
sources.insert(id, Box::new(source));
|
sources.insert(id, Box::new(source));
|
||||||
}
|
}
|
||||||
|
|
||||||
if sources.is_empty() {
|
|
||||||
info!("No function sources found");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(sources)
|
Ok(sources)
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet};
|
|||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use log::{info, warn};
|
use log::warn;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tilejson::{tilejson, Bounds, TileJSON};
|
use tilejson::{tilejson, Bounds, TileJSON};
|
||||||
|
|
||||||
@ -188,7 +188,7 @@ static DEFAULT_CLIP_GEOM: bool = true;
|
|||||||
|
|
||||||
pub async fn get_table_sources(
|
pub async fn get_table_sources(
|
||||||
conn: &mut Connection<'_>,
|
conn: &mut Connection<'_>,
|
||||||
default_srid: &Option<i32>,
|
default_srid: Option<i32>,
|
||||||
) -> Result<TableSources, io::Error> {
|
) -> Result<TableSources, io::Error> {
|
||||||
let mut sources = HashMap::new();
|
let mut sources = HashMap::new();
|
||||||
let mut duplicate_source_ids = HashSet::new();
|
let mut duplicate_source_ids = HashSet::new();
|
||||||
@ -202,35 +202,25 @@ pub async fn get_table_sources(
|
|||||||
let schema: String = row.get("f_table_schema");
|
let schema: String = row.get("f_table_schema");
|
||||||
let table: String = row.get("f_table_name");
|
let table: String = row.get("f_table_name");
|
||||||
let geometry_column: String = row.get("f_geometry_column");
|
let geometry_column: String = row.get("f_geometry_column");
|
||||||
|
|
||||||
let mut srid: i32 = row.get("srid");
|
|
||||||
let geometry_type: String = row.get("type");
|
|
||||||
|
|
||||||
let id = format!("{schema}.{table}");
|
let id = format!("{schema}.{table}");
|
||||||
let explicit_id = format!("{schema}.{table}.{geometry_column}");
|
let explicit_id = format!("{schema}.{table}.{geometry_column}");
|
||||||
|
|
||||||
if sources.contains_key(&id) {
|
if sources.contains_key(&id) {
|
||||||
duplicate_source_ids.insert(id.to_owned());
|
duplicate_source_ids.insert(id.clone());
|
||||||
} else {
|
|
||||||
info!(
|
|
||||||
r#"Found "{id}" table source with "{geometry_column}" column ({geometry_type}, SRID={srid})"#
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut srid: i32 = row.get("srid");
|
||||||
if srid == 0 {
|
if srid == 0 {
|
||||||
match default_srid {
|
if let Some(default_srid) = default_srid {
|
||||||
Some(default_srid) => {
|
|
||||||
warn!(r#""{id}" has SRID 0, using the provided default SRID {default_srid}"#);
|
warn!(r#""{id}" has SRID 0, using the provided default SRID {default_srid}"#);
|
||||||
srid = *default_srid;
|
srid = default_srid;
|
||||||
}
|
} else {
|
||||||
None => {
|
|
||||||
warn!(
|
warn!(
|
||||||
r#""{id}" has SRID 0, skipping. To use this table source, you must specify the SRID using the config file or provide the default SRID"#
|
r#""{id}" has SRID 0, skipping. To use this table source, you must specify the SRID using the config file or provide the default SRID"#
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let bounds_query = utils::get_source_bounds(&id, srid as u32, &geometry_column);
|
let bounds_query = utils::get_source_bounds(&id, srid as u32, &geometry_column);
|
||||||
|
|
||||||
@ -266,10 +256,6 @@ pub async fn get_table_sources(
|
|||||||
sources.insert(explicit_id, Box::new(explicit_source));
|
sources.insert(explicit_id, Box::new(explicit_source));
|
||||||
}
|
}
|
||||||
|
|
||||||
if sources.is_empty() {
|
|
||||||
info!("No table sources found");
|
|
||||||
}
|
|
||||||
|
|
||||||
if !duplicate_source_ids.is_empty() {
|
if !duplicate_source_ids.is_empty() {
|
||||||
let sources = duplicate_source_ids
|
let sources = duplicate_source_ids
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -1,24 +1,24 @@
|
|||||||
---
|
---
|
||||||
# The socket address to bind [default: 0.0.0.0:3000]
|
|
||||||
listen_addresses: '0.0.0.0:3000'
|
|
||||||
|
|
||||||
# Database connection string
|
# Database connection string
|
||||||
connection_string: 'postgres://postgres@localhost:5432/db'
|
connection_string: 'postgres://postgres@localhost:5432/db'
|
||||||
|
|
||||||
# Maximum connections pool size [default: 20]
|
# Trust invalid certificates. This introduces significant vulnerabilities, and should only be used as a last resort.
|
||||||
pool_size: 20
|
danger_accept_invalid_certs: false
|
||||||
|
|
||||||
# Connection keep alive timeout [default: 75]
|
|
||||||
keep_alive: 75
|
|
||||||
|
|
||||||
# Number of web server workers
|
|
||||||
worker_processes: 8
|
|
||||||
|
|
||||||
# If a spatial table has SRID 0, then this SRID will be used as a fallback
|
# If a spatial table has SRID 0, then this SRID will be used as a fallback
|
||||||
default_srid: 4326
|
default_srid: 4326
|
||||||
|
|
||||||
# Trust invalid certificates. This introduces significant vulnerabilities, and should only be used as a last resort.
|
# Connection keep alive timeout [default: 75]
|
||||||
danger_accept_invalid_certs: false
|
keep_alive: 75
|
||||||
|
|
||||||
|
# The socket address to bind [default: 0.0.0.0:3000]
|
||||||
|
listen_addresses: '0.0.0.0:3000'
|
||||||
|
|
||||||
|
# Maximum connections pool size [default: 20]
|
||||||
|
pool_size: 20
|
||||||
|
|
||||||
|
# Number of web server workers
|
||||||
|
worker_processes: 8
|
||||||
|
|
||||||
# Associative arrays of table sources
|
# Associative arrays of table sources
|
||||||
table_sources:
|
table_sources:
|
||||||
|
@ -14,7 +14,7 @@ async fn test_get_table_sources_ok() {
|
|||||||
|
|
||||||
let pool = dev::make_pool().await;
|
let pool = dev::make_pool().await;
|
||||||
let mut connection = pool.get().await.unwrap();
|
let mut connection = pool.get().await.unwrap();
|
||||||
let table_sources = get_table_sources(&mut connection, &None).await.unwrap();
|
let table_sources = get_table_sources(&mut connection, None).await.unwrap();
|
||||||
|
|
||||||
log::info!("table_sources = {table_sources:#?}");
|
log::info!("table_sources = {table_sources:#?}");
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ async fn test_table_source_tilejson_ok() {
|
|||||||
|
|
||||||
let pool = dev::make_pool().await;
|
let pool = dev::make_pool().await;
|
||||||
let mut connection = pool.get().await.unwrap();
|
let mut connection = pool.get().await.unwrap();
|
||||||
let table_sources = get_table_sources(&mut connection, &None).await.unwrap();
|
let table_sources = get_table_sources(&mut connection, None).await.unwrap();
|
||||||
|
|
||||||
let table_source = table_sources.get("public.table_source").unwrap();
|
let table_source = table_sources.get("public.table_source").unwrap();
|
||||||
let tilejson = table_source.get_tilejson().await.unwrap();
|
let tilejson = table_source.get_tilejson().await.unwrap();
|
||||||
@ -69,7 +69,7 @@ async fn test_table_source_tile_ok() {
|
|||||||
|
|
||||||
let pool = dev::make_pool().await;
|
let pool = dev::make_pool().await;
|
||||||
let mut connection = pool.get().await.unwrap();
|
let mut connection = pool.get().await.unwrap();
|
||||||
let table_sources = get_table_sources(&mut connection, &None).await.unwrap();
|
let table_sources = get_table_sources(&mut connection, None).await.unwrap();
|
||||||
|
|
||||||
let table_source = table_sources.get("public.table_source").unwrap();
|
let table_source = table_sources.get("public.table_source").unwrap();
|
||||||
let tile = table_source
|
let tile = table_source
|
||||||
@ -86,7 +86,7 @@ async fn test_table_source_srid_ok() {
|
|||||||
|
|
||||||
let pool = dev::make_pool().await;
|
let pool = dev::make_pool().await;
|
||||||
let mut connection = pool.get().await.unwrap();
|
let mut connection = pool.get().await.unwrap();
|
||||||
let table_sources = get_table_sources(&mut connection, &Some(900913))
|
let table_sources = get_table_sources(&mut connection, Some(900913))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -113,7 +113,7 @@ async fn test_table_source_multiple_geom_ok() {
|
|||||||
|
|
||||||
let pool = dev::make_pool().await;
|
let pool = dev::make_pool().await;
|
||||||
let mut connection = pool.get().await.unwrap();
|
let mut connection = pool.get().await.unwrap();
|
||||||
let table_sources = get_table_sources(&mut connection, &None).await.unwrap();
|
let table_sources = get_table_sources(&mut connection, None).await.unwrap();
|
||||||
|
|
||||||
assert!(table_sources.contains_key("public.table_source_multiple_geom"));
|
assert!(table_sources.contains_key("public.table_source_multiple_geom"));
|
||||||
let table_source_multiple_geom = table_sources
|
let table_source_multiple_geom = table_sources
|
||||||
|
Loading…
Reference in New Issue
Block a user