Updated metars with redis caching on invalid metars
This commit is contained in:
293
api/Cargo.lock
generated
293
api/Cargo.lock
generated
@@ -381,6 +381,7 @@ dependencies = [
|
|||||||
"futures-util",
|
"futures-util",
|
||||||
"geo-types",
|
"geo-types",
|
||||||
"log",
|
"log",
|
||||||
|
"moka",
|
||||||
"rand 0.9.0",
|
"rand 0.9.0",
|
||||||
"rand_chacha 0.9.0",
|
"rand_chacha 0.9.0",
|
||||||
"redis",
|
"redis",
|
||||||
@@ -421,6 +422,17 @@ dependencies = [
|
|||||||
"password-hash",
|
"password-hash",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-lock"
|
||||||
|
version = "3.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18"
|
||||||
|
dependencies = [
|
||||||
|
"event-listener",
|
||||||
|
"event-listener-strategy",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-trait"
|
name = "async-trait"
|
||||||
version = "0.1.87"
|
version = "0.1.87"
|
||||||
@@ -757,6 +769,24 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-channel"
|
||||||
|
version = "0.5.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-epoch"
|
||||||
|
version = "0.9.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-queue"
|
name = "crossbeam-queue"
|
||||||
version = "0.3.12"
|
version = "0.3.12"
|
||||||
@@ -1001,6 +1031,16 @@ dependencies = [
|
|||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "event-listener-strategy"
|
||||||
|
version = "0.5.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93"
|
||||||
|
dependencies = [
|
||||||
|
"event-listener",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "2.3.0"
|
version = "2.3.0"
|
||||||
@@ -1164,6 +1204,19 @@ dependencies = [
|
|||||||
"slab",
|
"slab",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generator"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cc6bd114ceda131d3b1d665eba35788690ad37f5916457286b32ab6fd3c438dd"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"rustversion",
|
||||||
|
"windows",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "generic-array"
|
name = "generic-array"
|
||||||
version = "0.14.7"
|
version = "0.14.7"
|
||||||
@@ -1504,7 +1557,7 @@ dependencies = [
|
|||||||
"iana-time-zone-haiku",
|
"iana-time-zone-haiku",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"windows-core",
|
"windows-core 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1820,6 +1873,28 @@ version = "0.4.27"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "loom"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"generator",
|
||||||
|
"scoped-tls",
|
||||||
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matchers"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
|
||||||
|
dependencies = [
|
||||||
|
"regex-automata 0.1.10",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "maybe-async"
|
name = "maybe-async"
|
||||||
version = "0.2.10"
|
version = "0.2.10"
|
||||||
@@ -1889,6 +1964,28 @@ dependencies = [
|
|||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "moka"
|
||||||
|
version = "0.12.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a9321642ca94a4282428e6ea4af8cc2ca4eac48ac7a6a4ea8f33f76d0ce70926"
|
||||||
|
dependencies = [
|
||||||
|
"async-lock",
|
||||||
|
"crossbeam-channel",
|
||||||
|
"crossbeam-epoch",
|
||||||
|
"crossbeam-utils",
|
||||||
|
"event-listener",
|
||||||
|
"futures-util",
|
||||||
|
"loom",
|
||||||
|
"parking_lot",
|
||||||
|
"portable-atomic",
|
||||||
|
"rustc_version",
|
||||||
|
"smallvec",
|
||||||
|
"tagptr",
|
||||||
|
"thiserror 1.0.69",
|
||||||
|
"uuid",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "native-tls"
|
name = "native-tls"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
@@ -1906,6 +2003,16 @@ dependencies = [
|
|||||||
"tempfile",
|
"tempfile",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nu-ansi-term"
|
||||||
|
version = "0.46.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
|
||||||
|
dependencies = [
|
||||||
|
"overload",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-bigint"
|
name = "num-bigint"
|
||||||
version = "0.4.6"
|
version = "0.4.6"
|
||||||
@@ -2038,6 +2145,12 @@ dependencies = [
|
|||||||
"hashbrown 0.14.5",
|
"hashbrown 0.14.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "overload"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking"
|
name = "parking"
|
||||||
version = "2.2.1"
|
version = "2.2.1"
|
||||||
@@ -2317,8 +2430,17 @@ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
"regex-automata",
|
"regex-automata 0.4.9",
|
||||||
"regex-syntax",
|
"regex-syntax 0.8.5",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||||
|
dependencies = [
|
||||||
|
"regex-syntax 0.6.29",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2329,7 +2451,7 @@ checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
"regex-syntax",
|
"regex-syntax 0.8.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2338,6 +2460,12 @@ version = "0.1.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a"
|
checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.6.29"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.8.5"
|
version = "0.8.5"
|
||||||
@@ -2584,6 +2712,12 @@ dependencies = [
|
|||||||
"parking_lot",
|
"parking_lot",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scoped-tls"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
@@ -2700,6 +2834,15 @@ dependencies = [
|
|||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sharded-slab"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shlex"
|
name = "shlex"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
@@ -3065,6 +3208,12 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tagptr"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.18.0"
|
version = "3.18.0"
|
||||||
@@ -3119,6 +3268,16 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thread_local"
|
||||||
|
version = "1.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.3.39"
|
version = "0.3.39"
|
||||||
@@ -3314,6 +3473,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
|
checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
"valuable",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-log"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"once_cell",
|
||||||
|
"tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-subscriber"
|
||||||
|
version = "0.3.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
|
||||||
|
dependencies = [
|
||||||
|
"matchers",
|
||||||
|
"nu-ansi-term",
|
||||||
|
"once_cell",
|
||||||
|
"regex",
|
||||||
|
"sharded-slab",
|
||||||
|
"smallvec",
|
||||||
|
"thread_local",
|
||||||
|
"tracing",
|
||||||
|
"tracing-core",
|
||||||
|
"tracing-log",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3412,6 +3601,12 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "valuable"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vcpkg"
|
name = "vcpkg"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
@@ -3545,6 +3740,38 @@ dependencies = [
|
|||||||
"wasite",
|
"wasite",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu",
|
||||||
|
"winapi-x86_64-pc-windows-gnu",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows"
|
||||||
|
version = "0.58.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6"
|
||||||
|
dependencies = [
|
||||||
|
"windows-core 0.58.0",
|
||||||
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-core"
|
name = "windows-core"
|
||||||
version = "0.52.0"
|
version = "0.52.0"
|
||||||
@@ -3554,6 +3781,41 @@ dependencies = [
|
|||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-core"
|
||||||
|
version = "0.58.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
|
||||||
|
dependencies = [
|
||||||
|
"windows-implement",
|
||||||
|
"windows-interface",
|
||||||
|
"windows-result 0.2.0",
|
||||||
|
"windows-strings 0.1.0",
|
||||||
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-implement"
|
||||||
|
version = "0.58.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-interface"
|
||||||
|
version = "0.58.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-link"
|
name = "windows-link"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -3566,11 +3828,20 @@ version = "0.4.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3"
|
checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-result",
|
"windows-result 0.3.1",
|
||||||
"windows-strings",
|
"windows-strings 0.3.1",
|
||||||
"windows-targets 0.53.0",
|
"windows-targets 0.53.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-result"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-result"
|
name = "windows-result"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
@@ -3580,6 +3851,16 @@ dependencies = [
|
|||||||
"windows-link",
|
"windows-link",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-strings"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
|
||||||
|
dependencies = [
|
||||||
|
"windows-result 0.2.0",
|
||||||
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-strings"
|
name = "windows-strings"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
|
|||||||
@@ -34,3 +34,4 @@ rand_chacha = "0.9.0"
|
|||||||
geo-types = "0.7.15"
|
geo-types = "0.7.15"
|
||||||
byteorder = "1.5.0"
|
byteorder = "1.5.0"
|
||||||
futures = "0.3.31"
|
futures = "0.3.31"
|
||||||
|
moka = { version = "0.12.10", features = ["future"] }
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use actix_web::web::Json;
|
use actix_web::web::Json;
|
||||||
|
use futures_util::try_join;
|
||||||
|
use moka::future::Cache;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::{Execute, Postgres, QueryBuilder};
|
use sqlx::{Execute, Postgres, QueryBuilder};
|
||||||
use crate::airports::model::airport_category::AirportCategory;
|
use crate::airports::model::airport_category::AirportCategory;
|
||||||
@@ -172,7 +174,7 @@ impl Airport {
|
|||||||
|
|
||||||
let metar_fut = async {
|
let metar_fut = async {
|
||||||
if metar {
|
if metar {
|
||||||
match Metar::find_all(&[icao]).await {
|
match Metar::find_all(&vec![icao.to_string()]).await {
|
||||||
Ok(m) => Some(m.into_iter().nth(0)),
|
Ok(m) => Some(m.into_iter().nth(0)),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::error!("{}", err);
|
log::error!("{}", err);
|
||||||
@@ -223,7 +225,7 @@ impl Airport {
|
|||||||
Some(m) => Some(m),
|
Some(m) => Some(m),
|
||||||
None => None,
|
None => None,
|
||||||
},
|
},
|
||||||
None => None
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
airport_row.map(|row| {
|
airport_row.map(|row| {
|
||||||
@@ -281,22 +283,49 @@ impl Airport {
|
|||||||
let airport_rows: Vec<AirportRow> = airport_query.fetch_all(pool).await?;
|
let airport_rows: Vec<AirportRow> = airport_query.fetch_all(pool).await?;
|
||||||
let mut airports: Vec<Airport> = airport_rows.into_iter().map(From::from).collect();
|
let mut airports: Vec<Airport> = airport_rows.into_iter().map(From::from).collect();
|
||||||
|
|
||||||
// Bulk update airports with runways and frequencies
|
if airports.is_empty() {
|
||||||
if !airports.is_empty() {
|
return Ok(airports);
|
||||||
let icaos: Vec<String> = airports.iter().map(|a| a.icao.clone()).collect();
|
|
||||||
let mut runway_map = Runway::select_all_map(icaos.clone()).await?;
|
|
||||||
let mut frequency_map = Frequency::select_all_map(icaos.clone()).await?;
|
|
||||||
let mut metar_map: HashMap<String, Metar> = HashMap::new();
|
|
||||||
if query.metars.unwrap_or_else(|| false) {
|
|
||||||
let icaos_list: Vec<&str> = icaos.iter().map(|x| &**x).collect();
|
|
||||||
let metars = Metar::find_all(&icaos_list).await?;
|
|
||||||
metar_map = metars.into_iter()
|
|
||||||
.map(|metar| (metar.station_id.clone(), metar))
|
|
||||||
.collect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bulk update airport sub-fields
|
||||||
|
let icaos: Vec<String> = airports.iter().map(|a| a.icao.clone()).collect();
|
||||||
|
|
||||||
|
let runway_future = Runway::select_all_map(icaos.clone());
|
||||||
|
let frequency_future = Frequency::select_all_map(icaos.clone());
|
||||||
|
let metar_future = if query.metars.unwrap_or(false) {
|
||||||
|
Some(Metar::find_all(&icaos))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let (runway_map, frequency_map, mut metars_opt) = match metar_future {
|
||||||
|
Some(future_metars) => {
|
||||||
|
let (runway_map, frequency_map, metars) =
|
||||||
|
try_join!(runway_future, frequency_future, future_metars)?;
|
||||||
|
(
|
||||||
|
runway_map,
|
||||||
|
frequency_map,
|
||||||
|
Some(
|
||||||
|
metars
|
||||||
|
.into_iter()
|
||||||
|
.map(|m| (m.station_id.clone(), m))
|
||||||
|
.collect::<HashMap<_, _>>(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let (runway_map, frequency_map) = try_join!(runway_future, frequency_future)?;
|
||||||
|
(runway_map, frequency_map, None)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
for airport in airports.iter_mut() {
|
for airport in airports.iter_mut() {
|
||||||
airport.runways = runway_map.remove(&airport.icao).unwrap_or_default();
|
airport.runways = runway_map.get(&airport.icao).cloned().unwrap_or_default();
|
||||||
airport.frequencies = frequency_map.remove(&airport.icao).unwrap_or_default();
|
airport.frequencies = frequency_map
|
||||||
|
.get(&airport.icao)
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_default();
|
||||||
|
if let Some(ref mut metar_map) = metars_opt {
|
||||||
airport.latest_metar = metar_map.remove(&airport.icao);
|
airport.latest_metar = metar_map.remove(&airport.icao);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use crate::error::ApiResult;
|
|||||||
|
|
||||||
const TABLE_NAME: &str = "frequencies";
|
const TABLE_NAME: &str = "frequencies";
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Frequency {
|
pub struct Frequency {
|
||||||
#[serde(rename = "id")]
|
#[serde(rename = "id")]
|
||||||
pub frequency_id: String,
|
pub frequency_id: String,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use crate::error::ApiResult;
|
|||||||
|
|
||||||
const TABLE_NAME: &str = "runways";
|
const TABLE_NAME: &str = "runways";
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Runway {
|
pub struct Runway {
|
||||||
#[serde(rename = "id")]
|
#[serde(rename = "id")]
|
||||||
pub runway_id: String,
|
pub runway_id: String,
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
use actix_cors::Cors;
|
use actix_cors::Cors;
|
||||||
use actix_web::{App, HttpServer, middleware::Logger};
|
use actix_web::{App, HttpServer, middleware::Logger, web};
|
||||||
use dotenv::from_filename;
|
use dotenv::from_filename;
|
||||||
|
use moka::future::Cache;
|
||||||
use crate::auth::hash;
|
use crate::auth::hash;
|
||||||
use crate::users::{User, ADMIN_ROLE};
|
use crate::users::{User, ADMIN_ROLE};
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ use crate::error::Error;
|
|||||||
use crate::{error::ApiResult, db};
|
use crate::{error::ApiResult, db};
|
||||||
use chrono::{DateTime, Datelike, Utc};
|
use chrono::{DateTime, Datelike, Utc};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
use moka::future::Cache;
|
||||||
|
use redis::{AsyncCommands, RedisResult};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use crate::db::redis_async_connection;
|
||||||
|
|
||||||
const TABLE_NAME: &str = "metars";
|
const TABLE_NAME: &str = "metars";
|
||||||
|
|
||||||
@@ -195,13 +198,39 @@ impl Default for Metar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, sqlx::FromRow, Debug)]
|
#[derive(Serialize, Deserialize, sqlx::FromRow, Debug)]
|
||||||
struct MetarDb {
|
struct MetarRow {
|
||||||
icao: String,
|
icao: String,
|
||||||
observation_time: DateTime<Utc>,
|
observation_time: DateTime<Utc>,
|
||||||
raw_text: String,
|
raw_text: String,
|
||||||
data: serde_json::Value,
|
data: serde_json::Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl MetarRow {
|
||||||
|
async fn insert(&self) -> ApiResult<()> {
|
||||||
|
let pool = db::pool();
|
||||||
|
sqlx::query(&format!(
|
||||||
|
r#"
|
||||||
|
INSERT INTO {} (
|
||||||
|
icao,
|
||||||
|
observation_time,
|
||||||
|
raw_text,
|
||||||
|
data
|
||||||
|
)
|
||||||
|
VALUES ($1, $2, $3, $4, $5)
|
||||||
|
"#,
|
||||||
|
TABLE_NAME,
|
||||||
|
))
|
||||||
|
.bind(self.icao.clone())
|
||||||
|
.bind(self.observation_time.clone())
|
||||||
|
.bind(self.raw_text.clone())
|
||||||
|
.bind(self.data.clone())
|
||||||
|
.execute(pool)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Metar {
|
impl Metar {
|
||||||
fn parse_multiple(metar_strings: &Vec<&str>) -> ApiResult<Vec<Self>> {
|
fn parse_multiple(metar_strings: &Vec<&str>) -> ApiResult<Vec<Self>> {
|
||||||
let mut metars: Vec<Metar> = vec![];
|
let mut metars: Vec<Metar> = vec![];
|
||||||
@@ -794,14 +823,17 @@ impl Metar {
|
|||||||
Ok(metar)
|
Ok(metar)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_missing_metar_icaos(db_metars: &Vec<Self>, station_icaos: &[&str]) -> Vec<String> {
|
async fn get_missing_metar_icaos(
|
||||||
|
db_metars: &Vec<Self>,
|
||||||
|
station_icaos: &Vec<String>,
|
||||||
|
) -> Vec<String> {
|
||||||
let mut missing_metar_icaos: Vec<String> = vec![];
|
let mut missing_metar_icaos: Vec<String> = vec![];
|
||||||
let current_time = chrono::Local::now().naive_local().and_utc().timestamp();
|
let current_time = chrono::Local::now().naive_local().and_utc().timestamp();
|
||||||
let db_metars_set: HashSet<&str> = db_metars
|
let db_metars_set: HashSet<&str> = db_metars
|
||||||
.iter()
|
.iter()
|
||||||
.map(|icao| icao.station_id.as_str())
|
.map(|icao| icao.station_id.as_str())
|
||||||
.collect();
|
.collect();
|
||||||
let station_icaos_set: HashSet<&str> = station_icaos.to_owned().into_iter().collect();
|
let station_icaos_set: HashSet<&str> = station_icaos.iter().map(|s| s.as_str()).collect();
|
||||||
for difference in db_metars_set.symmetric_difference(&station_icaos_set) {
|
for difference in db_metars_set.symmetric_difference(&station_icaos_set) {
|
||||||
missing_metar_icaos.push(difference.to_string());
|
missing_metar_icaos.push(difference.to_string());
|
||||||
}
|
}
|
||||||
@@ -865,14 +897,14 @@ impl Metar {
|
|||||||
Ok(metars)
|
Ok(metars)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_db(metar_db: MetarDb) -> ApiResult<Metar> {
|
fn from_db(metar_db: MetarRow) -> ApiResult<Metar> {
|
||||||
let metar: Metar = serde_json::from_value(metar_db.data)?;
|
let metar: Metar = serde_json::from_value(metar_db.data)?;
|
||||||
Ok(metar)
|
Ok(metar)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_db(&self) -> ApiResult<MetarDb> {
|
fn to_db(&self) -> ApiResult<MetarRow> {
|
||||||
let data = serde_json::to_value(self)?;
|
let data = serde_json::to_value(self)?;
|
||||||
Ok(MetarDb {
|
Ok(MetarRow {
|
||||||
icao: self.station_id.clone(),
|
icao: self.station_id.clone(),
|
||||||
observation_time: self.observation_time,
|
observation_time: self.observation_time,
|
||||||
raw_text: self.raw_text.clone(),
|
raw_text: self.raw_text.clone(),
|
||||||
@@ -880,13 +912,13 @@ impl Metar {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn find_all(icao_list: &[&str]) -> ApiResult<Vec<Self>> {
|
pub async fn find_all(icao_list: &Vec<String>) -> ApiResult<Vec<Self>> {
|
||||||
if icao_list.is_empty() {
|
if icao_list.is_empty() {
|
||||||
return Ok(Vec::new());
|
return Ok(Vec::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
let pool = db::pool();
|
let pool = db::pool();
|
||||||
let metar_dbs: Vec<MetarDb> = match sqlx::query_as::<_, MetarDb>(&format!(
|
let metar_rows: Vec<MetarRow> = sqlx::query_as::<_, MetarRow>(&format!(
|
||||||
r#"
|
r#"
|
||||||
SELECT DISTINCT ON (icao) * FROM {} WHERE icao = ANY($1) ORDER BY icao, observation_time DESC
|
SELECT DISTINCT ON (icao) * FROM {} WHERE icao = ANY($1) ORDER BY icao, observation_time DESC
|
||||||
"#,
|
"#,
|
||||||
@@ -894,28 +926,34 @@ impl Metar {
|
|||||||
))
|
))
|
||||||
.bind(icao_list)
|
.bind(icao_list)
|
||||||
.fetch_all(pool)
|
.fetch_all(pool)
|
||||||
.await
|
.await?;
|
||||||
{
|
let mut metars: Vec<Metar> = metar_rows
|
||||||
Ok(m) => m,
|
|
||||||
Err(err) => {
|
|
||||||
return Err(Error::new(
|
|
||||||
500,
|
|
||||||
format!("Unable to find METARs with input {:?}: {}", icao_list, err),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let mut metars: Vec<Metar> = metar_dbs
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|metar_db| Metar::from_db(metar_db).ok())
|
.filter_map(|metar_db| Metar::from_db(metar_db).ok())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
let mut conn = redis_async_connection().await?;
|
||||||
// Check for missing metars
|
// Check for missing metars
|
||||||
let missing_icao_list = Self::get_missing_metar_icaos(&metars, icao_list);
|
let missing_icao_list = Self::get_missing_metar_icaos(&metars, icao_list).await;
|
||||||
if !missing_icao_list.is_empty() {
|
if !missing_icao_list.is_empty() {
|
||||||
log::trace!("Retrieving missing METAR data for {:?}", missing_icao_list);
|
log::trace!("Retrieving missing METAR data for {:?}", missing_icao_list);
|
||||||
|
|
||||||
let missing_icao_list: Vec<&str> = missing_icao_list.iter().map(|s| s.as_str()).collect();
|
let mut updated_missing_icao_list: Vec<&str> = Vec::new();
|
||||||
let mut missing_icao_list = Self::get_remote_metars(&missing_icao_list)
|
for icao in &missing_icao_list {
|
||||||
|
let result: RedisResult<Option<bool>> = conn.get(icao).await;
|
||||||
|
match result {
|
||||||
|
Ok(Some(value)) => {
|
||||||
|
if value {
|
||||||
|
updated_missing_icao_list.push(icao);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(None) => {
|
||||||
|
updated_missing_icao_list.push(icao);
|
||||||
|
}
|
||||||
|
Err(err) => return Err(err.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut missing_icao_list = Self::get_remote_metars(&updated_missing_icao_list)
|
||||||
.await
|
.await
|
||||||
.unwrap_or_else(|err| {
|
.unwrap_or_else(|err| {
|
||||||
log::warn!("Unable to get remote METAR data; {}", err);
|
log::warn!("Unable to get remote METAR data; {}", err);
|
||||||
@@ -925,37 +963,28 @@ impl Metar {
|
|||||||
if missing_icao_list.len() > 0 {
|
if missing_icao_list.len() > 0 {
|
||||||
// Insert missing METARs
|
// Insert missing METARs
|
||||||
for missing_metar in &missing_icao_list {
|
for missing_metar in &missing_icao_list {
|
||||||
|
let _: RedisResult<()> = conn.set(&missing_metar.station_id, true).await;
|
||||||
missing_metar.insert().await?;
|
missing_metar.insert().await?;
|
||||||
}
|
}
|
||||||
metars.append(&mut missing_icao_list)
|
metars.append(&mut missing_icao_list)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Invalidate the still missing icaos
|
||||||
|
let still_missing_icao_list =
|
||||||
|
Self::get_missing_metar_icaos(&missing_icao_list, icao_list).await;
|
||||||
|
if !still_missing_icao_list.is_empty() {
|
||||||
|
for icao in still_missing_icao_list {
|
||||||
|
let _: RedisResult<()> = conn.set_ex(&icao, false, 3600).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(metars)
|
Ok(metars)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn insert(&self) -> ApiResult<()> {
|
pub async fn insert(&self) -> ApiResult<()> {
|
||||||
let pool = db::pool();
|
let metar: MetarRow = self.to_db()?;
|
||||||
let metar: MetarDb = self.to_db()?;
|
metar.insert().await?;
|
||||||
sqlx::query(&format!(
|
|
||||||
r#"
|
|
||||||
INSERT INTO {} (
|
|
||||||
icao,
|
|
||||||
observation_time,
|
|
||||||
raw_text,
|
|
||||||
data
|
|
||||||
)
|
|
||||||
VALUES ($1, $2, $3, $4)
|
|
||||||
"#,
|
|
||||||
TABLE_NAME,
|
|
||||||
))
|
|
||||||
.bind(metar.icao)
|
|
||||||
.bind(metar.observation_time)
|
|
||||||
.bind(metar.raw_text)
|
|
||||||
.bind(metar.data)
|
|
||||||
.execute(pool)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ async fn find_all(req: HttpRequest) -> HttpResponse {
|
|||||||
Some(i) => i,
|
Some(i) => i,
|
||||||
None => return HttpResponse::UnprocessableEntity().body("Missing icaos parameter"),
|
None => return HttpResponse::UnprocessableEntity().body("Missing icaos parameter"),
|
||||||
};
|
};
|
||||||
let icaos: Vec<&str> = icao_string.split(',').collect();
|
let icaos: Vec<String> = icao_string.split(',').map(|s| s.to_string()).collect();
|
||||||
|
|
||||||
let metars = match Metar::find_all(&icaos).await {
|
let metars = match Metar::find_all(&icaos).await {
|
||||||
Ok(a) => a,
|
Ok(a) => a,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ meta {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get {
|
get {
|
||||||
url: {{BASE_URL}}/airports?page=1&limit=1000&icaos=KHEF,KJYO,KMRB,KOKV&metars=true
|
url: {{BASE_URL}}/airports?page=1&limit=1000&metars=true
|
||||||
body: none
|
body: none
|
||||||
auth: none
|
auth: none
|
||||||
}
|
}
|
||||||
@@ -13,6 +13,7 @@ get {
|
|||||||
params:query {
|
params:query {
|
||||||
page: 1
|
page: 1
|
||||||
limit: 1000
|
limit: 1000
|
||||||
icaos: KHEF,KJYO,KMRB,KOKV
|
|
||||||
metars: true
|
metars: true
|
||||||
|
~icaos: 00AA
|
||||||
|
~icaos: KHEF,KJYO,KMRB,KOKV
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user