[feat](trx-core): add periodic TLE refresh from CelesTrak
Fetch fresh weather satellite TLEs from CelesTrak on startup and then once every 24 hours. The dynamic TLE store is checked first in tle_for_satellite(), falling back to the existing hardcoded TLEs when the fetch has not yet completed or fails. - Add global TLE_STORE (RwLock<HashMap<norad_id, (line1, line2)>>) - Add parse_tle_response() to parse 3-line TLE format - Add refresh_tles_from_celestrak() async fetch + store update - Add spawn_tle_refresh_task() for startup + daily refresh loop - Refactor tle_for_satellite() into norad_id lookup + store check - Spawn refresh task in trx-server alongside wxsat decoder tasks - Add reqwest (rustls-tls) dependency to trx-core https://claude.ai/code/session_01RB19i93dnemDYLcfrhyhqc Signed-off-by: Claude <noreply@anthropic.com>
This commit is contained in:
Generated
+397
-3
@@ -40,7 +40,7 @@ dependencies = [
|
|||||||
"foldhash",
|
"foldhash",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"h2",
|
"h2",
|
||||||
"http",
|
"http 0.2.12",
|
||||||
"httparse",
|
"httparse",
|
||||||
"httpdate",
|
"httpdate",
|
||||||
"itoa",
|
"itoa",
|
||||||
@@ -76,7 +76,7 @@ checksum = "13d324164c51f63867b57e73ba5936ea151b8a41a1d23d1031eeb9f70d0236f8"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bytestring",
|
"bytestring",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"http",
|
"http 0.2.12",
|
||||||
"regex",
|
"regex",
|
||||||
"regex-lite",
|
"regex-lite",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -326,6 +326,12 @@ version = "1.0.102"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
|
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atomic-waker"
|
||||||
|
version = "1.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "audiopus_sys"
|
name = "audiopus_sys"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
@@ -1011,8 +1017,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
|
checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
"js-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi",
|
||||||
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1022,9 +1030,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
"js-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"r-efi 5.3.0",
|
"r-efi 5.3.0",
|
||||||
"wasip2",
|
"wasip2",
|
||||||
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1057,7 +1067,7 @@ dependencies = [
|
|||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http",
|
"http 0.2.12",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"slab",
|
"slab",
|
||||||
"tokio",
|
"tokio",
|
||||||
@@ -1109,6 +1119,39 @@ dependencies = [
|
|||||||
"itoa",
|
"itoa",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"itoa",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http-body"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"http 1.4.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http-body-util"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"futures-core",
|
||||||
|
"http 1.4.0",
|
||||||
|
"http-body",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "httparse"
|
name = "httparse"
|
||||||
version = "1.10.1"
|
version = "1.10.1"
|
||||||
@@ -1121,6 +1164,67 @@ version = "1.0.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper"
|
||||||
|
version = "1.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11"
|
||||||
|
dependencies = [
|
||||||
|
"atomic-waker",
|
||||||
|
"bytes",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"http 1.4.0",
|
||||||
|
"http-body",
|
||||||
|
"httparse",
|
||||||
|
"itoa",
|
||||||
|
"pin-project-lite",
|
||||||
|
"pin-utils",
|
||||||
|
"smallvec",
|
||||||
|
"tokio",
|
||||||
|
"want",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper-rustls"
|
||||||
|
version = "0.27.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58"
|
||||||
|
dependencies = [
|
||||||
|
"http 1.4.0",
|
||||||
|
"hyper",
|
||||||
|
"hyper-util",
|
||||||
|
"rustls",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"tokio",
|
||||||
|
"tokio-rustls",
|
||||||
|
"tower-service",
|
||||||
|
"webpki-roots",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper-util"
|
||||||
|
version = "0.1.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0"
|
||||||
|
dependencies = [
|
||||||
|
"base64",
|
||||||
|
"bytes",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-util",
|
||||||
|
"http 1.4.0",
|
||||||
|
"http-body",
|
||||||
|
"hyper",
|
||||||
|
"ipnet",
|
||||||
|
"libc",
|
||||||
|
"percent-encoding",
|
||||||
|
"pin-project-lite",
|
||||||
|
"socket2 0.6.1",
|
||||||
|
"tokio",
|
||||||
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iana-time-zone"
|
name = "iana-time-zone"
|
||||||
version = "0.1.65"
|
version = "0.1.65"
|
||||||
@@ -1288,6 +1392,22 @@ dependencies = [
|
|||||||
"mach2",
|
"mach2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ipnet"
|
||||||
|
version = "2.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iri-string"
|
||||||
|
version = "0.7.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d8e7418f59cc01c88316161279a7f665217ae316b388e58a0d10e29f54f1e5eb"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "is_terminal_polyfill"
|
name = "is_terminal_polyfill"
|
||||||
version = "1.70.2"
|
version = "1.70.2"
|
||||||
@@ -1445,6 +1565,12 @@ version = "0.4.28"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
|
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lru-slab"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mach2"
|
name = "mach2"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
@@ -1831,6 +1957,61 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quinn"
|
||||||
|
version = "0.11.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"cfg_aliases",
|
||||||
|
"pin-project-lite",
|
||||||
|
"quinn-proto",
|
||||||
|
"quinn-udp",
|
||||||
|
"rustc-hash 2.1.1",
|
||||||
|
"rustls",
|
||||||
|
"socket2 0.6.1",
|
||||||
|
"thiserror 2.0.17",
|
||||||
|
"tokio",
|
||||||
|
"tracing",
|
||||||
|
"web-time",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quinn-proto"
|
||||||
|
version = "0.11.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"getrandom 0.3.4",
|
||||||
|
"lru-slab",
|
||||||
|
"rand 0.9.2",
|
||||||
|
"ring",
|
||||||
|
"rustc-hash 2.1.1",
|
||||||
|
"rustls",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"slab",
|
||||||
|
"thiserror 2.0.17",
|
||||||
|
"tinyvec",
|
||||||
|
"tracing",
|
||||||
|
"web-time",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quinn-udp"
|
||||||
|
version = "0.5.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd"
|
||||||
|
dependencies = [
|
||||||
|
"cfg_aliases",
|
||||||
|
"libc",
|
||||||
|
"once_cell",
|
||||||
|
"socket2 0.6.1",
|
||||||
|
"tracing",
|
||||||
|
"windows-sys 0.60.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.42"
|
version = "1.0.42"
|
||||||
@@ -1975,6 +2156,58 @@ version = "0.8.8"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
|
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "reqwest"
|
||||||
|
version = "0.12.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147"
|
||||||
|
dependencies = [
|
||||||
|
"base64",
|
||||||
|
"bytes",
|
||||||
|
"futures-core",
|
||||||
|
"http 1.4.0",
|
||||||
|
"http-body",
|
||||||
|
"http-body-util",
|
||||||
|
"hyper",
|
||||||
|
"hyper-rustls",
|
||||||
|
"hyper-util",
|
||||||
|
"js-sys",
|
||||||
|
"log",
|
||||||
|
"percent-encoding",
|
||||||
|
"pin-project-lite",
|
||||||
|
"quinn",
|
||||||
|
"rustls",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_urlencoded",
|
||||||
|
"sync_wrapper",
|
||||||
|
"tokio",
|
||||||
|
"tokio-rustls",
|
||||||
|
"tower",
|
||||||
|
"tower-http",
|
||||||
|
"tower-service",
|
||||||
|
"url",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"wasm-bindgen-futures",
|
||||||
|
"web-sys",
|
||||||
|
"webpki-roots",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ring"
|
||||||
|
version = "0.17.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"cfg-if",
|
||||||
|
"getrandom 0.2.17",
|
||||||
|
"libc",
|
||||||
|
"untrusted",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-hash"
|
name = "rustc-hash"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@@ -2023,6 +2256,41 @@ dependencies = [
|
|||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls"
|
||||||
|
version = "0.23.37"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
"ring",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"rustls-webpki",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-pki-types"
|
||||||
|
version = "1.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd"
|
||||||
|
dependencies = [
|
||||||
|
"web-time",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-webpki"
|
||||||
|
version = "0.103.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef"
|
||||||
|
dependencies = [
|
||||||
|
"ring",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"untrusted",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.22"
|
version = "1.0.22"
|
||||||
@@ -2268,6 +2536,12 @@ version = "0.11.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subtle"
|
||||||
|
version = "2.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.111"
|
version = "2.0.111"
|
||||||
@@ -2279,6 +2553,15 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sync_wrapper"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "synstructure"
|
name = "synstructure"
|
||||||
version = "0.13.2"
|
version = "0.13.2"
|
||||||
@@ -2393,6 +2676,21 @@ dependencies = [
|
|||||||
"zerovec",
|
"zerovec",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyvec"
|
||||||
|
version = "1.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3"
|
||||||
|
dependencies = [
|
||||||
|
"tinyvec_macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyvec_macros"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.48.0"
|
version = "1.48.0"
|
||||||
@@ -2421,6 +2719,16 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-rustls"
|
||||||
|
version = "0.26.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61"
|
||||||
|
dependencies = [
|
||||||
|
"rustls",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-serial"
|
name = "tokio-serial"
|
||||||
version = "5.4.5"
|
version = "5.4.5"
|
||||||
@@ -2531,6 +2839,51 @@ version = "0.1.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
|
checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tower"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"pin-project-lite",
|
||||||
|
"sync_wrapper",
|
||||||
|
"tokio",
|
||||||
|
"tower-layer",
|
||||||
|
"tower-service",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tower-http"
|
||||||
|
version = "0.6.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.10.0",
|
||||||
|
"bytes",
|
||||||
|
"futures-util",
|
||||||
|
"http 1.4.0",
|
||||||
|
"http-body",
|
||||||
|
"iri-string",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tower",
|
||||||
|
"tower-layer",
|
||||||
|
"tower-service",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tower-layer"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tower-service"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing"
|
name = "tracing"
|
||||||
version = "0.1.43"
|
version = "0.1.43"
|
||||||
@@ -2718,6 +3071,7 @@ name = "trx-core"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"flate2",
|
"flate2",
|
||||||
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sgp4",
|
"sgp4",
|
||||||
@@ -2897,6 +3251,12 @@ dependencies = [
|
|||||||
"trx-core",
|
"trx-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "try-lock"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "typenum"
|
||||||
version = "1.19.0"
|
version = "1.19.0"
|
||||||
@@ -2930,6 +3290,12 @@ version = "0.2.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "untrusted"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.5.7"
|
version = "2.5.7"
|
||||||
@@ -2988,6 +3354,15 @@ dependencies = [
|
|||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "want"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
|
||||||
|
dependencies = [
|
||||||
|
"try-lock",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.1+wasi-snapshot-preview1"
|
version = "0.11.1+wasi-snapshot-preview1"
|
||||||
@@ -3115,6 +3490,25 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "web-time"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
|
||||||
|
dependencies = [
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "webpki-roots"
|
||||||
|
version = "1.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed"
|
||||||
|
dependencies = [
|
||||||
|
"rustls-pki-types",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
|
|||||||
@@ -15,3 +15,4 @@ tracing = { workspace = true }
|
|||||||
flate2 = { workspace = true }
|
flate2 = { workspace = true }
|
||||||
uuid = { workspace = true }
|
uuid = { workspace = true }
|
||||||
sgp4 = "2"
|
sgp4 = "2"
|
||||||
|
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls"] }
|
||||||
|
|||||||
+207
-34
@@ -9,7 +9,10 @@
|
|||||||
//! and receiver station coordinates.
|
//! and receiver station coordinates.
|
||||||
|
|
||||||
use sgp4::{Constants, Elements, MinutesSinceEpoch};
|
use sgp4::{Constants, Elements, MinutesSinceEpoch};
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::f64::consts::PI;
|
use std::f64::consts::PI;
|
||||||
|
use std::sync::RwLock;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
/// Half-swath width in km for NOAA APT / Meteor LRPT imagery.
|
/// Half-swath width in km for NOAA APT / Meteor LRPT imagery.
|
||||||
const SWATH_HALF_WIDTH_KM: f64 = 1400.0;
|
const SWATH_HALF_WIDTH_KM: f64 = 1400.0;
|
||||||
@@ -17,6 +20,18 @@ const SWATH_HALF_WIDTH_KM: f64 = 1400.0;
|
|||||||
/// Earth radius in km (WGS84 mean).
|
/// Earth radius in km (WGS84 mean).
|
||||||
const EARTH_RADIUS_KM: f64 = 6371.0;
|
const EARTH_RADIUS_KM: f64 = 6371.0;
|
||||||
|
|
||||||
|
/// CelesTrak weather satellite TLE endpoint.
|
||||||
|
const CELESTRAK_WEATHER_URL: &str =
|
||||||
|
"https://celestrak.org/NORAD/elements/gp.php?GROUP=weather&FORMAT=tle";
|
||||||
|
|
||||||
|
/// How often to refresh TLEs after the initial fetch (24 hours).
|
||||||
|
const TLE_REFRESH_INTERVAL: Duration = Duration::from_secs(24 * 60 * 60);
|
||||||
|
|
||||||
|
/// Global store for dynamically-fetched TLE data.
|
||||||
|
///
|
||||||
|
/// Keys are NORAD catalog numbers; values are `(line1, line2)` strings.
|
||||||
|
static TLE_STORE: RwLock<Option<HashMap<u32, (String, String)>>> = RwLock::new(None);
|
||||||
|
|
||||||
/// Geographic bounds for a satellite image overlay: `[south, west, north, east]`.
|
/// Geographic bounds for a satellite image overlay: `[south, west, north, east]`.
|
||||||
pub type GeoBounds = [f64; 4];
|
pub type GeoBounds = [f64; 4];
|
||||||
|
|
||||||
@@ -32,46 +47,171 @@ pub struct PassGeo {
|
|||||||
pub ground_track: Vec<TrackPoint>,
|
pub ground_track: Vec<TrackPoint>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Hardcoded TLE data for active weather satellites.
|
/// Map satellite name patterns to NORAD catalog numbers.
|
||||||
///
|
fn norad_id_for_satellite(name: &str) -> Option<u32> {
|
||||||
/// These are recent-epoch TLEs. SGP4 propagation from stale TLEs still
|
|
||||||
/// gives sub-degree accuracy for image overlay purposes (drift ~0.1 deg/week).
|
|
||||||
fn tle_for_satellite(name: &str) -> Option<(&str, &str)> {
|
|
||||||
let upper = name.to_uppercase();
|
let upper = name.to_uppercase();
|
||||||
// Match by common satellite names from the decoder telemetry output.
|
|
||||||
//
|
|
||||||
// TLE lines must be exactly 69 characters with valid mod-10 checksums.
|
|
||||||
// These are approximate recent-epoch elements for overlay purposes.
|
|
||||||
if upper.contains("NOAA") && upper.contains("15") {
|
if upper.contains("NOAA") && upper.contains("15") {
|
||||||
Some((
|
Some(25338)
|
||||||
"1 25338U 98030A 26084.50000000 .00000045 00000-0 36000-4 0 9998",
|
|
||||||
"2 25338 98.7285 114.5200 0010150 45.0000 315.1500 14.25955000 4001",
|
|
||||||
))
|
|
||||||
} else if upper.contains("NOAA") && upper.contains("18") {
|
} else if upper.contains("NOAA") && upper.contains("18") {
|
||||||
Some((
|
Some(28654)
|
||||||
"1 28654U 05018A 26084.50000000 .00000036 00000-0 28000-4 0 9997",
|
|
||||||
"2 28654 99.0400 162.3000 0013800 290.0000 70.0000 14.12500000 1005",
|
|
||||||
))
|
|
||||||
} else if upper.contains("NOAA") && upper.contains("19") {
|
} else if upper.contains("NOAA") && upper.contains("19") {
|
||||||
Some((
|
Some(33591)
|
||||||
"1 33591U 09005A 26084.50000000 .00000028 00000-0 20000-4 0 9996",
|
} else if upper.contains("METEOR")
|
||||||
"2 33591 99.1700 050.5000 0014000 100.0000 260.0000 14.12300000 8002",
|
&& (upper.contains("2-3") || upper.contains("N2-3") || upper.contains("2_3"))
|
||||||
))
|
{
|
||||||
} else if upper.contains("METEOR") && (upper.contains("2-3") || upper.contains("N2-3") || upper.contains("2_3")) {
|
Some(57166)
|
||||||
Some((
|
} else if upper.contains("METEOR")
|
||||||
"1 57166U 23091A 26084.50000000 .00000020 00000-0 16000-4 0 9998",
|
&& (upper.contains("2-4") || upper.contains("N2-4") || upper.contains("2_4"))
|
||||||
"2 57166 98.7700 170.0000 0005000 90.0000 270.0000 14.23700000 1502",
|
{
|
||||||
))
|
Some(59051)
|
||||||
} else if upper.contains("METEOR") && (upper.contains("2-4") || upper.contains("N2-4") || upper.contains("2_4")) {
|
|
||||||
Some((
|
|
||||||
"1 59051U 24044A 26084.50000000 .00000018 00000-0 14000-4 0 9997",
|
|
||||||
"2 59051 98.7700 200.0000 0005000 80.0000 280.0000 14.23700000 1006",
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Hardcoded fallback TLE data for active weather satellites.
|
||||||
|
///
|
||||||
|
/// These are recent-epoch TLEs. SGP4 propagation from stale TLEs still
|
||||||
|
/// gives sub-degree accuracy for image overlay purposes (drift ~0.1 deg/week).
|
||||||
|
fn hardcoded_tle(norad_id: u32) -> Option<(&'static str, &'static str)> {
|
||||||
|
match norad_id {
|
||||||
|
25338 => Some((
|
||||||
|
"1 25338U 98030A 26084.50000000 .00000045 00000-0 36000-4 0 9998",
|
||||||
|
"2 25338 98.7285 114.5200 0010150 45.0000 315.1500 14.25955000 4001",
|
||||||
|
)),
|
||||||
|
28654 => Some((
|
||||||
|
"1 28654U 05018A 26084.50000000 .00000036 00000-0 28000-4 0 9997",
|
||||||
|
"2 28654 99.0400 162.3000 0013800 290.0000 70.0000 14.12500000 1005",
|
||||||
|
)),
|
||||||
|
33591 => Some((
|
||||||
|
"1 33591U 09005A 26084.50000000 .00000028 00000-0 20000-4 0 9996",
|
||||||
|
"2 33591 99.1700 050.5000 0014000 100.0000 260.0000 14.12300000 8002",
|
||||||
|
)),
|
||||||
|
57166 => Some((
|
||||||
|
"1 57166U 23091A 26084.50000000 .00000020 00000-0 16000-4 0 9998",
|
||||||
|
"2 57166 98.7700 170.0000 0005000 90.0000 270.0000 14.23700000 1502",
|
||||||
|
)),
|
||||||
|
59051 => Some((
|
||||||
|
"1 59051U 24044A 26084.50000000 .00000018 00000-0 14000-4 0 9997",
|
||||||
|
"2 59051 98.7700 200.0000 0005000 80.0000 280.0000 14.23700000 1006",
|
||||||
|
)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Look up TLE lines for a satellite by name.
|
||||||
|
///
|
||||||
|
/// Checks the dynamic [`TLE_STORE`] first (populated by [`spawn_tle_refresh_task`]),
|
||||||
|
/// falling back to hardcoded TLEs if no fresh data is available.
|
||||||
|
fn tle_for_satellite(name: &str) -> Option<(String, String)> {
|
||||||
|
let norad_id = norad_id_for_satellite(name)?;
|
||||||
|
|
||||||
|
// Try dynamic store first.
|
||||||
|
if let Ok(guard) = TLE_STORE.read() {
|
||||||
|
if let Some(store) = guard.as_ref() {
|
||||||
|
if let Some((l1, l2)) = store.get(&norad_id) {
|
||||||
|
return Some((l1.clone(), l2.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to hardcoded.
|
||||||
|
hardcoded_tle(norad_id).map(|(l1, l2)| (l1.to_string(), l2.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// CelesTrak TLE refresh
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Parse a CelesTrak 3-line TLE response into a map of NORAD ID → (line1, line2).
|
||||||
|
fn parse_tle_response(body: &str) -> HashMap<u32, (String, String)> {
|
||||||
|
let mut result = HashMap::new();
|
||||||
|
let lines: Vec<&str> = body.lines().map(|l| l.trim_end()).collect();
|
||||||
|
let mut i = 0;
|
||||||
|
while i + 2 < lines.len() {
|
||||||
|
let line1 = lines[i + 1];
|
||||||
|
let line2 = lines[i + 2];
|
||||||
|
// Validate TLE line markers
|
||||||
|
if line1.starts_with("1 ") && line2.starts_with("2 ") {
|
||||||
|
// Extract NORAD catalog number from line 1 columns 2-6
|
||||||
|
if let Ok(norad_id) = line1[2..7].trim().parse::<u32>() {
|
||||||
|
result.insert(norad_id, (line1.to_string(), line2.to_string()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i += 3;
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fetch fresh TLE data from CelesTrak and update the global store.
|
||||||
|
///
|
||||||
|
/// Returns the number of TLEs loaded, or an error description.
|
||||||
|
pub async fn refresh_tles_from_celestrak() -> Result<usize, String> {
|
||||||
|
let response = reqwest::Client::builder()
|
||||||
|
.timeout(Duration::from_secs(30))
|
||||||
|
.build()
|
||||||
|
.map_err(|e| format!("HTTP client error: {e}"))?
|
||||||
|
.get(CELESTRAK_WEATHER_URL)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("CelesTrak fetch failed: {e}"))?;
|
||||||
|
|
||||||
|
if !response.status().is_success() {
|
||||||
|
return Err(format!("CelesTrak returned HTTP {}", response.status()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let body = response
|
||||||
|
.text()
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Failed to read CelesTrak response: {e}"))?;
|
||||||
|
|
||||||
|
let tles = parse_tle_response(&body);
|
||||||
|
let count = tles.len();
|
||||||
|
|
||||||
|
if count == 0 {
|
||||||
|
return Err("CelesTrak response contained no valid TLEs".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
match TLE_STORE.write() {
|
||||||
|
Ok(mut guard) => *guard = Some(tles),
|
||||||
|
Err(e) => {
|
||||||
|
// Recover from poisoned lock
|
||||||
|
let mut guard = e.into_inner();
|
||||||
|
*guard = Some(parse_tle_response(&body));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(count)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Spawn a background task that fetches TLEs from CelesTrak on start and
|
||||||
|
/// then refreshes once per day.
|
||||||
|
///
|
||||||
|
/// The task runs until the process exits. Fetch failures are logged but
|
||||||
|
/// do not stop the periodic refresh — hardcoded fallback TLEs remain usable.
|
||||||
|
pub fn spawn_tle_refresh_task() {
|
||||||
|
tokio::spawn(async {
|
||||||
|
// Initial fetch at startup.
|
||||||
|
match refresh_tles_from_celestrak().await {
|
||||||
|
Ok(n) => tracing::info!("TLE refresh: loaded {n} satellite TLEs from CelesTrak"),
|
||||||
|
Err(e) => tracing::warn!("TLE refresh: initial fetch failed ({e}), using hardcoded TLEs"),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Periodic refresh every 24 hours.
|
||||||
|
let mut interval = tokio::time::interval(TLE_REFRESH_INTERVAL);
|
||||||
|
// The first tick fires immediately; skip it since we just fetched.
|
||||||
|
interval.tick().await;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
interval.tick().await;
|
||||||
|
match refresh_tles_from_celestrak().await {
|
||||||
|
Ok(n) => tracing::info!("TLE refresh: updated {n} satellite TLEs from CelesTrak"),
|
||||||
|
Err(e) => tracing::warn!("TLE refresh: fetch failed ({e}), keeping previous TLEs"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// Compute geographic bounds and ground track for a satellite pass.
|
/// Compute geographic bounds and ground track for a satellite pass.
|
||||||
///
|
///
|
||||||
/// Returns `None` if the satellite is unknown or propagation fails.
|
/// Returns `None` if the satellite is unknown or propagation fails.
|
||||||
@@ -88,8 +228,7 @@ pub fn compute_pass_geo(
|
|||||||
Some(satellite.to_string()),
|
Some(satellite.to_string()),
|
||||||
line1.as_bytes(),
|
line1.as_bytes(),
|
||||||
line2.as_bytes(),
|
line2.as_bytes(),
|
||||||
)
|
).ok()?;
|
||||||
.ok()?;
|
|
||||||
|
|
||||||
let constants = Constants::from_elements(&elements).ok()?;
|
let constants = Constants::from_elements(&elements).ok()?;
|
||||||
|
|
||||||
@@ -300,6 +439,40 @@ mod tests {
|
|||||||
assert!(tle_for_satellite("Unknown Sat").is_none());
|
assert!(tle_for_satellite("Unknown Sat").is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_norad_id_mapping() {
|
||||||
|
assert_eq!(norad_id_for_satellite("NOAA-15"), Some(25338));
|
||||||
|
assert_eq!(norad_id_for_satellite("NOAA-18"), Some(28654));
|
||||||
|
assert_eq!(norad_id_for_satellite("NOAA-19"), Some(33591));
|
||||||
|
assert_eq!(norad_id_for_satellite("Meteor-M N2-3"), Some(57166));
|
||||||
|
assert_eq!(norad_id_for_satellite("Meteor-M N2-4"), Some(59051));
|
||||||
|
assert_eq!(norad_id_for_satellite("Unknown"), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_tle_response() {
|
||||||
|
let body = "\
|
||||||
|
NOAA 15
|
||||||
|
1 25338U 98030A 26085.50000000 .00000045 00000-0 36000-4 0 9999
|
||||||
|
2 25338 98.7285 114.5200 0010150 45.0000 315.1500 14.25955000 4002
|
||||||
|
NOAA 19
|
||||||
|
1 33591U 09005A 26085.50000000 .00000028 00000-0 20000-4 0 9997
|
||||||
|
2 33591 99.1700 050.5000 0014000 100.0000 260.0000 14.12300000 8003
|
||||||
|
";
|
||||||
|
let tles = parse_tle_response(body);
|
||||||
|
assert_eq!(tles.len(), 2);
|
||||||
|
assert!(tles.contains_key(&25338));
|
||||||
|
assert!(tles.contains_key(&33591));
|
||||||
|
assert!(tles[&25338].0.starts_with("1 25338"));
|
||||||
|
assert!(tles[&33591].1.starts_with("2 33591"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_tle_response_empty() {
|
||||||
|
assert!(parse_tle_response("").is_empty());
|
||||||
|
assert!(parse_tle_response("not a tle\n").is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_compute_pass_geo_noaa19() {
|
fn test_compute_pass_geo_noaa19() {
|
||||||
// Simulate a ~12 minute pass
|
// Simulate a ~12 minute pass
|
||||||
@@ -335,7 +508,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_elements_epoch_ms() {
|
fn test_elements_epoch_ms() {
|
||||||
// Parse a TLE and verify the epoch converts to a reasonable timestamp
|
// Parse a TLE and verify the epoch converts to a reasonable timestamp
|
||||||
let (line1, line2) = tle_for_satellite("NOAA-19").unwrap();
|
let (line1, line2) = hardcoded_tle(33591).unwrap();
|
||||||
let elements = Elements::from_tle(
|
let elements = Elements::from_tle(
|
||||||
Some("NOAA-19".to_string()),
|
Some("NOAA-19".to_string()),
|
||||||
line1.as_bytes(),
|
line1.as_bytes(),
|
||||||
|
|||||||
@@ -794,6 +794,9 @@ fn spawn_rig_audio_stack(
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// Start periodic TLE refresh from CelesTrak (on start + once/day).
|
||||||
|
trx_core::geo::spawn_tle_refresh_task();
|
||||||
|
|
||||||
// Spawn weather satellite APT decoder task
|
// Spawn weather satellite APT decoder task
|
||||||
let wxsat_pcm_rx = pcm_tx.subscribe();
|
let wxsat_pcm_rx = pcm_tx.subscribe();
|
||||||
let wxsat_state_rx = state_rx.clone();
|
let wxsat_state_rx = state_rx.clone();
|
||||||
|
|||||||
Reference in New Issue
Block a user