├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md ├── docs └── sample.png ├── main ├── sample ├── status.json └── trip.json └── src ├── api.rs ├── frontend.rs └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.22.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "ahash" 22 | version = "0.8.11" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" 25 | dependencies = [ 26 | "cfg-if", 27 | "once_cell", 28 | "version_check", 29 | "zerocopy", 30 | ] 31 | 32 | [[package]] 33 | name = "allocator-api2" 34 | version = "0.2.18" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" 37 | 38 | [[package]] 39 | name = "android-tzdata" 40 | version = "0.1.1" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" 43 | 44 | [[package]] 45 | name = "android_system_properties" 46 | version = "0.1.5" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 49 | dependencies = [ 50 | "libc", 51 | ] 52 | 53 | [[package]] 54 | name = "atomic-waker" 55 | version = "1.1.2" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 58 | 59 | [[package]] 60 | name = "autocfg" 61 | version = "1.3.0" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" 64 | 65 | [[package]] 66 | name = "backtrace" 67 | version = "0.3.73" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" 70 | dependencies = [ 71 | "addr2line", 72 | "cc", 73 | "cfg-if", 74 | "libc", 75 | "miniz_oxide", 76 | "object", 77 | "rustc-demangle", 78 | ] 79 | 80 | [[package]] 81 | name = "bahn-status" 82 | version = "0.1.0" 83 | dependencies = [ 84 | "chrono", 85 | "rand", 86 | "ratatui", 87 | "reqwest", 88 | "serde", 89 | "serde_json", 90 | ] 91 | 92 | [[package]] 93 | name = "base64" 94 | version = "0.22.1" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 97 | 98 | [[package]] 99 | name = "bitflags" 100 | version = "1.3.2" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 103 | 104 | [[package]] 105 | name = "bitflags" 106 | version = "2.6.0" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 109 | 110 | [[package]] 111 | name = "bumpalo" 112 | version = "3.16.0" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 115 | 116 | [[package]] 117 | name = "bytes" 118 | version = "1.6.1" 119 | source = "registry+https://github.com/rust-lang/crates.io-index" 120 | checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" 121 | 122 | [[package]] 123 | name = "cassowary" 124 | version = "0.3.0" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" 127 | 128 | [[package]] 129 | name = "castaway" 130 | version = "0.2.3" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5" 133 | dependencies = [ 134 | "rustversion", 135 | ] 136 | 137 | [[package]] 138 | name = "cc" 139 | version = "1.1.5" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "324c74f2155653c90b04f25b2a47a8a631360cb908f92a772695f430c7e31052" 142 | 143 | [[package]] 144 | name = "cfg-if" 145 | version = "1.0.0" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 148 | 149 | [[package]] 150 | name = "chrono" 151 | version = "0.4.38" 152 | source = "registry+https://github.com/rust-lang/crates.io-index" 153 | checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" 154 | dependencies = [ 155 | "android-tzdata", 156 | "iana-time-zone", 157 | "js-sys", 158 | "num-traits", 159 | "wasm-bindgen", 160 | "windows-targets 0.52.6", 161 | ] 162 | 163 | [[package]] 164 | name = "compact_str" 165 | version = "0.7.1" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f" 168 | dependencies = [ 169 | "castaway", 170 | "cfg-if", 171 | "itoa", 172 | "ryu", 173 | "static_assertions", 174 | ] 175 | 176 | [[package]] 177 | name = "core-foundation" 178 | version = "0.9.4" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 181 | dependencies = [ 182 | "core-foundation-sys", 183 | "libc", 184 | ] 185 | 186 | [[package]] 187 | name = "core-foundation-sys" 188 | version = "0.8.6" 189 | source = "registry+https://github.com/rust-lang/crates.io-index" 190 | checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" 191 | 192 | [[package]] 193 | name = "crossterm" 194 | version = "0.27.0" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" 197 | dependencies = [ 198 | "bitflags 2.6.0", 199 | "crossterm_winapi", 200 | "libc", 201 | "mio", 202 | "parking_lot", 203 | "signal-hook", 204 | "signal-hook-mio", 205 | "winapi", 206 | ] 207 | 208 | [[package]] 209 | name = "crossterm_winapi" 210 | version = "0.9.1" 211 | source = "registry+https://github.com/rust-lang/crates.io-index" 212 | checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" 213 | dependencies = [ 214 | "winapi", 215 | ] 216 | 217 | [[package]] 218 | name = "either" 219 | version = "1.13.0" 220 | source = "registry+https://github.com/rust-lang/crates.io-index" 221 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 222 | 223 | [[package]] 224 | name = "encoding_rs" 225 | version = "0.8.34" 226 | source = "registry+https://github.com/rust-lang/crates.io-index" 227 | checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" 228 | dependencies = [ 229 | "cfg-if", 230 | ] 231 | 232 | [[package]] 233 | name = "equivalent" 234 | version = "1.0.1" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 237 | 238 | [[package]] 239 | name = "errno" 240 | version = "0.3.9" 241 | source = "registry+https://github.com/rust-lang/crates.io-index" 242 | checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" 243 | dependencies = [ 244 | "libc", 245 | "windows-sys 0.52.0", 246 | ] 247 | 248 | [[package]] 249 | name = "fastrand" 250 | version = "2.1.0" 251 | source = "registry+https://github.com/rust-lang/crates.io-index" 252 | checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" 253 | 254 | [[package]] 255 | name = "fnv" 256 | version = "1.0.7" 257 | source = "registry+https://github.com/rust-lang/crates.io-index" 258 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 259 | 260 | [[package]] 261 | name = "foreign-types" 262 | version = "0.3.2" 263 | source = "registry+https://github.com/rust-lang/crates.io-index" 264 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 265 | dependencies = [ 266 | "foreign-types-shared", 267 | ] 268 | 269 | [[package]] 270 | name = "foreign-types-shared" 271 | version = "0.1.1" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 274 | 275 | [[package]] 276 | name = "form_urlencoded" 277 | version = "1.2.1" 278 | source = "registry+https://github.com/rust-lang/crates.io-index" 279 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 280 | dependencies = [ 281 | "percent-encoding", 282 | ] 283 | 284 | [[package]] 285 | name = "futures-channel" 286 | version = "0.3.30" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" 289 | dependencies = [ 290 | "futures-core", 291 | "futures-sink", 292 | ] 293 | 294 | [[package]] 295 | name = "futures-core" 296 | version = "0.3.30" 297 | source = "registry+https://github.com/rust-lang/crates.io-index" 298 | checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" 299 | 300 | [[package]] 301 | name = "futures-io" 302 | version = "0.3.30" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" 305 | 306 | [[package]] 307 | name = "futures-sink" 308 | version = "0.3.30" 309 | source = "registry+https://github.com/rust-lang/crates.io-index" 310 | checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" 311 | 312 | [[package]] 313 | name = "futures-task" 314 | version = "0.3.30" 315 | source = "registry+https://github.com/rust-lang/crates.io-index" 316 | checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" 317 | 318 | [[package]] 319 | name = "futures-util" 320 | version = "0.3.30" 321 | source = "registry+https://github.com/rust-lang/crates.io-index" 322 | checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" 323 | dependencies = [ 324 | "futures-core", 325 | "futures-io", 326 | "futures-sink", 327 | "futures-task", 328 | "memchr", 329 | "pin-project-lite", 330 | "pin-utils", 331 | "slab", 332 | ] 333 | 334 | [[package]] 335 | name = "getrandom" 336 | version = "0.2.15" 337 | source = "registry+https://github.com/rust-lang/crates.io-index" 338 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 339 | dependencies = [ 340 | "cfg-if", 341 | "libc", 342 | "wasi", 343 | ] 344 | 345 | [[package]] 346 | name = "gimli" 347 | version = "0.29.0" 348 | source = "registry+https://github.com/rust-lang/crates.io-index" 349 | checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" 350 | 351 | [[package]] 352 | name = "h2" 353 | version = "0.4.5" 354 | source = "registry+https://github.com/rust-lang/crates.io-index" 355 | checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" 356 | dependencies = [ 357 | "atomic-waker", 358 | "bytes", 359 | "fnv", 360 | "futures-core", 361 | "futures-sink", 362 | "http", 363 | "indexmap", 364 | "slab", 365 | "tokio", 366 | "tokio-util", 367 | "tracing", 368 | ] 369 | 370 | [[package]] 371 | name = "hashbrown" 372 | version = "0.14.5" 373 | source = "registry+https://github.com/rust-lang/crates.io-index" 374 | checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 375 | dependencies = [ 376 | "ahash", 377 | "allocator-api2", 378 | ] 379 | 380 | [[package]] 381 | name = "heck" 382 | version = "0.5.0" 383 | source = "registry+https://github.com/rust-lang/crates.io-index" 384 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 385 | 386 | [[package]] 387 | name = "http" 388 | version = "1.1.0" 389 | source = "registry+https://github.com/rust-lang/crates.io-index" 390 | checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" 391 | dependencies = [ 392 | "bytes", 393 | "fnv", 394 | "itoa", 395 | ] 396 | 397 | [[package]] 398 | name = "http-body" 399 | version = "1.0.1" 400 | source = "registry+https://github.com/rust-lang/crates.io-index" 401 | checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" 402 | dependencies = [ 403 | "bytes", 404 | "http", 405 | ] 406 | 407 | [[package]] 408 | name = "http-body-util" 409 | version = "0.1.2" 410 | source = "registry+https://github.com/rust-lang/crates.io-index" 411 | checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" 412 | dependencies = [ 413 | "bytes", 414 | "futures-util", 415 | "http", 416 | "http-body", 417 | "pin-project-lite", 418 | ] 419 | 420 | [[package]] 421 | name = "httparse" 422 | version = "1.9.4" 423 | source = "registry+https://github.com/rust-lang/crates.io-index" 424 | checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" 425 | 426 | [[package]] 427 | name = "hyper" 428 | version = "1.4.1" 429 | source = "registry+https://github.com/rust-lang/crates.io-index" 430 | checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" 431 | dependencies = [ 432 | "bytes", 433 | "futures-channel", 434 | "futures-util", 435 | "h2", 436 | "http", 437 | "http-body", 438 | "httparse", 439 | "itoa", 440 | "pin-project-lite", 441 | "smallvec", 442 | "tokio", 443 | "want", 444 | ] 445 | 446 | [[package]] 447 | name = "hyper-rustls" 448 | version = "0.27.2" 449 | source = "registry+https://github.com/rust-lang/crates.io-index" 450 | checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" 451 | dependencies = [ 452 | "futures-util", 453 | "http", 454 | "hyper", 455 | "hyper-util", 456 | "rustls", 457 | "rustls-pki-types", 458 | "tokio", 459 | "tokio-rustls", 460 | "tower-service", 461 | ] 462 | 463 | [[package]] 464 | name = "hyper-tls" 465 | version = "0.6.0" 466 | source = "registry+https://github.com/rust-lang/crates.io-index" 467 | checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" 468 | dependencies = [ 469 | "bytes", 470 | "http-body-util", 471 | "hyper", 472 | "hyper-util", 473 | "native-tls", 474 | "tokio", 475 | "tokio-native-tls", 476 | "tower-service", 477 | ] 478 | 479 | [[package]] 480 | name = "hyper-util" 481 | version = "0.1.6" 482 | source = "registry+https://github.com/rust-lang/crates.io-index" 483 | checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" 484 | dependencies = [ 485 | "bytes", 486 | "futures-channel", 487 | "futures-util", 488 | "http", 489 | "http-body", 490 | "hyper", 491 | "pin-project-lite", 492 | "socket2", 493 | "tokio", 494 | "tower", 495 | "tower-service", 496 | "tracing", 497 | ] 498 | 499 | [[package]] 500 | name = "iana-time-zone" 501 | version = "0.1.60" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" 504 | dependencies = [ 505 | "android_system_properties", 506 | "core-foundation-sys", 507 | "iana-time-zone-haiku", 508 | "js-sys", 509 | "wasm-bindgen", 510 | "windows-core", 511 | ] 512 | 513 | [[package]] 514 | name = "iana-time-zone-haiku" 515 | version = "0.1.2" 516 | source = "registry+https://github.com/rust-lang/crates.io-index" 517 | checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 518 | dependencies = [ 519 | "cc", 520 | ] 521 | 522 | [[package]] 523 | name = "idna" 524 | version = "0.5.0" 525 | source = "registry+https://github.com/rust-lang/crates.io-index" 526 | checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" 527 | dependencies = [ 528 | "unicode-bidi", 529 | "unicode-normalization", 530 | ] 531 | 532 | [[package]] 533 | name = "indexmap" 534 | version = "2.2.6" 535 | source = "registry+https://github.com/rust-lang/crates.io-index" 536 | checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" 537 | dependencies = [ 538 | "equivalent", 539 | "hashbrown", 540 | ] 541 | 542 | [[package]] 543 | name = "ipnet" 544 | version = "2.9.0" 545 | source = "registry+https://github.com/rust-lang/crates.io-index" 546 | checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" 547 | 548 | [[package]] 549 | name = "itertools" 550 | version = "0.13.0" 551 | source = "registry+https://github.com/rust-lang/crates.io-index" 552 | checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" 553 | dependencies = [ 554 | "either", 555 | ] 556 | 557 | [[package]] 558 | name = "itoa" 559 | version = "1.0.11" 560 | source = "registry+https://github.com/rust-lang/crates.io-index" 561 | checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" 562 | 563 | [[package]] 564 | name = "js-sys" 565 | version = "0.3.69" 566 | source = "registry+https://github.com/rust-lang/crates.io-index" 567 | checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" 568 | dependencies = [ 569 | "wasm-bindgen", 570 | ] 571 | 572 | [[package]] 573 | name = "libc" 574 | version = "0.2.155" 575 | source = "registry+https://github.com/rust-lang/crates.io-index" 576 | checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" 577 | 578 | [[package]] 579 | name = "linux-raw-sys" 580 | version = "0.4.14" 581 | source = "registry+https://github.com/rust-lang/crates.io-index" 582 | checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" 583 | 584 | [[package]] 585 | name = "lock_api" 586 | version = "0.4.12" 587 | source = "registry+https://github.com/rust-lang/crates.io-index" 588 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 589 | dependencies = [ 590 | "autocfg", 591 | "scopeguard", 592 | ] 593 | 594 | [[package]] 595 | name = "log" 596 | version = "0.4.22" 597 | source = "registry+https://github.com/rust-lang/crates.io-index" 598 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 599 | 600 | [[package]] 601 | name = "lru" 602 | version = "0.12.3" 603 | source = "registry+https://github.com/rust-lang/crates.io-index" 604 | checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" 605 | dependencies = [ 606 | "hashbrown", 607 | ] 608 | 609 | [[package]] 610 | name = "memchr" 611 | version = "2.7.4" 612 | source = "registry+https://github.com/rust-lang/crates.io-index" 613 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 614 | 615 | [[package]] 616 | name = "mime" 617 | version = "0.3.17" 618 | source = "registry+https://github.com/rust-lang/crates.io-index" 619 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 620 | 621 | [[package]] 622 | name = "miniz_oxide" 623 | version = "0.7.4" 624 | source = "registry+https://github.com/rust-lang/crates.io-index" 625 | checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" 626 | dependencies = [ 627 | "adler", 628 | ] 629 | 630 | [[package]] 631 | name = "mio" 632 | version = "0.8.11" 633 | source = "registry+https://github.com/rust-lang/crates.io-index" 634 | checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" 635 | dependencies = [ 636 | "libc", 637 | "log", 638 | "wasi", 639 | "windows-sys 0.48.0", 640 | ] 641 | 642 | [[package]] 643 | name = "native-tls" 644 | version = "0.2.12" 645 | source = "registry+https://github.com/rust-lang/crates.io-index" 646 | checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" 647 | dependencies = [ 648 | "libc", 649 | "log", 650 | "openssl", 651 | "openssl-probe", 652 | "openssl-sys", 653 | "schannel", 654 | "security-framework", 655 | "security-framework-sys", 656 | "tempfile", 657 | ] 658 | 659 | [[package]] 660 | name = "num-traits" 661 | version = "0.2.19" 662 | source = "registry+https://github.com/rust-lang/crates.io-index" 663 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 664 | dependencies = [ 665 | "autocfg", 666 | ] 667 | 668 | [[package]] 669 | name = "object" 670 | version = "0.36.1" 671 | source = "registry+https://github.com/rust-lang/crates.io-index" 672 | checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" 673 | dependencies = [ 674 | "memchr", 675 | ] 676 | 677 | [[package]] 678 | name = "once_cell" 679 | version = "1.19.0" 680 | source = "registry+https://github.com/rust-lang/crates.io-index" 681 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 682 | 683 | [[package]] 684 | name = "openssl" 685 | version = "0.10.64" 686 | source = "registry+https://github.com/rust-lang/crates.io-index" 687 | checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" 688 | dependencies = [ 689 | "bitflags 2.6.0", 690 | "cfg-if", 691 | "foreign-types", 692 | "libc", 693 | "once_cell", 694 | "openssl-macros", 695 | "openssl-sys", 696 | ] 697 | 698 | [[package]] 699 | name = "openssl-macros" 700 | version = "0.1.1" 701 | source = "registry+https://github.com/rust-lang/crates.io-index" 702 | checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" 703 | dependencies = [ 704 | "proc-macro2", 705 | "quote", 706 | "syn", 707 | ] 708 | 709 | [[package]] 710 | name = "openssl-probe" 711 | version = "0.1.5" 712 | source = "registry+https://github.com/rust-lang/crates.io-index" 713 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 714 | 715 | [[package]] 716 | name = "openssl-sys" 717 | version = "0.9.102" 718 | source = "registry+https://github.com/rust-lang/crates.io-index" 719 | checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" 720 | dependencies = [ 721 | "cc", 722 | "libc", 723 | "pkg-config", 724 | "vcpkg", 725 | ] 726 | 727 | [[package]] 728 | name = "parking_lot" 729 | version = "0.12.3" 730 | source = "registry+https://github.com/rust-lang/crates.io-index" 731 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 732 | dependencies = [ 733 | "lock_api", 734 | "parking_lot_core", 735 | ] 736 | 737 | [[package]] 738 | name = "parking_lot_core" 739 | version = "0.9.10" 740 | source = "registry+https://github.com/rust-lang/crates.io-index" 741 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 742 | dependencies = [ 743 | "cfg-if", 744 | "libc", 745 | "redox_syscall", 746 | "smallvec", 747 | "windows-targets 0.52.6", 748 | ] 749 | 750 | [[package]] 751 | name = "paste" 752 | version = "1.0.15" 753 | source = "registry+https://github.com/rust-lang/crates.io-index" 754 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 755 | 756 | [[package]] 757 | name = "percent-encoding" 758 | version = "2.3.1" 759 | source = "registry+https://github.com/rust-lang/crates.io-index" 760 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 761 | 762 | [[package]] 763 | name = "pin-project" 764 | version = "1.1.5" 765 | source = "registry+https://github.com/rust-lang/crates.io-index" 766 | checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" 767 | dependencies = [ 768 | "pin-project-internal", 769 | ] 770 | 771 | [[package]] 772 | name = "pin-project-internal" 773 | version = "1.1.5" 774 | source = "registry+https://github.com/rust-lang/crates.io-index" 775 | checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" 776 | dependencies = [ 777 | "proc-macro2", 778 | "quote", 779 | "syn", 780 | ] 781 | 782 | [[package]] 783 | name = "pin-project-lite" 784 | version = "0.2.14" 785 | source = "registry+https://github.com/rust-lang/crates.io-index" 786 | checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" 787 | 788 | [[package]] 789 | name = "pin-utils" 790 | version = "0.1.0" 791 | source = "registry+https://github.com/rust-lang/crates.io-index" 792 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 793 | 794 | [[package]] 795 | name = "pkg-config" 796 | version = "0.3.30" 797 | source = "registry+https://github.com/rust-lang/crates.io-index" 798 | checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" 799 | 800 | [[package]] 801 | name = "ppv-lite86" 802 | version = "0.2.17" 803 | source = "registry+https://github.com/rust-lang/crates.io-index" 804 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 805 | 806 | [[package]] 807 | name = "proc-macro2" 808 | version = "1.0.86" 809 | source = "registry+https://github.com/rust-lang/crates.io-index" 810 | checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" 811 | dependencies = [ 812 | "unicode-ident", 813 | ] 814 | 815 | [[package]] 816 | name = "quote" 817 | version = "1.0.36" 818 | source = "registry+https://github.com/rust-lang/crates.io-index" 819 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" 820 | dependencies = [ 821 | "proc-macro2", 822 | ] 823 | 824 | [[package]] 825 | name = "rand" 826 | version = "0.8.5" 827 | source = "registry+https://github.com/rust-lang/crates.io-index" 828 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 829 | dependencies = [ 830 | "libc", 831 | "rand_chacha", 832 | "rand_core", 833 | ] 834 | 835 | [[package]] 836 | name = "rand_chacha" 837 | version = "0.3.1" 838 | source = "registry+https://github.com/rust-lang/crates.io-index" 839 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 840 | dependencies = [ 841 | "ppv-lite86", 842 | "rand_core", 843 | ] 844 | 845 | [[package]] 846 | name = "rand_core" 847 | version = "0.6.4" 848 | source = "registry+https://github.com/rust-lang/crates.io-index" 849 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 850 | dependencies = [ 851 | "getrandom", 852 | ] 853 | 854 | [[package]] 855 | name = "ratatui" 856 | version = "0.27.0" 857 | source = "registry+https://github.com/rust-lang/crates.io-index" 858 | checksum = "d16546c5b5962abf8ce6e2881e722b4e0ae3b6f1a08a26ae3573c55853ca68d3" 859 | dependencies = [ 860 | "bitflags 2.6.0", 861 | "cassowary", 862 | "compact_str", 863 | "crossterm", 864 | "itertools", 865 | "lru", 866 | "paste", 867 | "stability", 868 | "strum", 869 | "strum_macros", 870 | "unicode-segmentation", 871 | "unicode-truncate", 872 | "unicode-width", 873 | ] 874 | 875 | [[package]] 876 | name = "redox_syscall" 877 | version = "0.5.3" 878 | source = "registry+https://github.com/rust-lang/crates.io-index" 879 | checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" 880 | dependencies = [ 881 | "bitflags 2.6.0", 882 | ] 883 | 884 | [[package]] 885 | name = "reqwest" 886 | version = "0.12.5" 887 | source = "registry+https://github.com/rust-lang/crates.io-index" 888 | checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" 889 | dependencies = [ 890 | "base64", 891 | "bytes", 892 | "encoding_rs", 893 | "futures-channel", 894 | "futures-core", 895 | "futures-util", 896 | "h2", 897 | "http", 898 | "http-body", 899 | "http-body-util", 900 | "hyper", 901 | "hyper-rustls", 902 | "hyper-tls", 903 | "hyper-util", 904 | "ipnet", 905 | "js-sys", 906 | "log", 907 | "mime", 908 | "native-tls", 909 | "once_cell", 910 | "percent-encoding", 911 | "pin-project-lite", 912 | "rustls-pemfile", 913 | "serde", 914 | "serde_json", 915 | "serde_urlencoded", 916 | "sync_wrapper", 917 | "system-configuration", 918 | "tokio", 919 | "tokio-native-tls", 920 | "tower-service", 921 | "url", 922 | "wasm-bindgen", 923 | "wasm-bindgen-futures", 924 | "web-sys", 925 | "winreg", 926 | ] 927 | 928 | [[package]] 929 | name = "ring" 930 | version = "0.17.8" 931 | source = "registry+https://github.com/rust-lang/crates.io-index" 932 | checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" 933 | dependencies = [ 934 | "cc", 935 | "cfg-if", 936 | "getrandom", 937 | "libc", 938 | "spin", 939 | "untrusted", 940 | "windows-sys 0.52.0", 941 | ] 942 | 943 | [[package]] 944 | name = "rustc-demangle" 945 | version = "0.1.24" 946 | source = "registry+https://github.com/rust-lang/crates.io-index" 947 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 948 | 949 | [[package]] 950 | name = "rustix" 951 | version = "0.38.34" 952 | source = "registry+https://github.com/rust-lang/crates.io-index" 953 | checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" 954 | dependencies = [ 955 | "bitflags 2.6.0", 956 | "errno", 957 | "libc", 958 | "linux-raw-sys", 959 | "windows-sys 0.52.0", 960 | ] 961 | 962 | [[package]] 963 | name = "rustls" 964 | version = "0.23.11" 965 | source = "registry+https://github.com/rust-lang/crates.io-index" 966 | checksum = "4828ea528154ae444e5a642dbb7d5623354030dc9822b83fd9bb79683c7399d0" 967 | dependencies = [ 968 | "once_cell", 969 | "rustls-pki-types", 970 | "rustls-webpki", 971 | "subtle", 972 | "zeroize", 973 | ] 974 | 975 | [[package]] 976 | name = "rustls-pemfile" 977 | version = "2.1.2" 978 | source = "registry+https://github.com/rust-lang/crates.io-index" 979 | checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" 980 | dependencies = [ 981 | "base64", 982 | "rustls-pki-types", 983 | ] 984 | 985 | [[package]] 986 | name = "rustls-pki-types" 987 | version = "1.7.0" 988 | source = "registry+https://github.com/rust-lang/crates.io-index" 989 | checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" 990 | 991 | [[package]] 992 | name = "rustls-webpki" 993 | version = "0.102.5" 994 | source = "registry+https://github.com/rust-lang/crates.io-index" 995 | checksum = "f9a6fccd794a42c2c105b513a2f62bc3fd8f3ba57a4593677ceb0bd035164d78" 996 | dependencies = [ 997 | "ring", 998 | "rustls-pki-types", 999 | "untrusted", 1000 | ] 1001 | 1002 | [[package]] 1003 | name = "rustversion" 1004 | version = "1.0.17" 1005 | source = "registry+https://github.com/rust-lang/crates.io-index" 1006 | checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" 1007 | 1008 | [[package]] 1009 | name = "ryu" 1010 | version = "1.0.18" 1011 | source = "registry+https://github.com/rust-lang/crates.io-index" 1012 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 1013 | 1014 | [[package]] 1015 | name = "schannel" 1016 | version = "0.1.23" 1017 | source = "registry+https://github.com/rust-lang/crates.io-index" 1018 | checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" 1019 | dependencies = [ 1020 | "windows-sys 0.52.0", 1021 | ] 1022 | 1023 | [[package]] 1024 | name = "scopeguard" 1025 | version = "1.2.0" 1026 | source = "registry+https://github.com/rust-lang/crates.io-index" 1027 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1028 | 1029 | [[package]] 1030 | name = "security-framework" 1031 | version = "2.11.1" 1032 | source = "registry+https://github.com/rust-lang/crates.io-index" 1033 | checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" 1034 | dependencies = [ 1035 | "bitflags 2.6.0", 1036 | "core-foundation", 1037 | "core-foundation-sys", 1038 | "libc", 1039 | "security-framework-sys", 1040 | ] 1041 | 1042 | [[package]] 1043 | name = "security-framework-sys" 1044 | version = "2.11.1" 1045 | source = "registry+https://github.com/rust-lang/crates.io-index" 1046 | checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" 1047 | dependencies = [ 1048 | "core-foundation-sys", 1049 | "libc", 1050 | ] 1051 | 1052 | [[package]] 1053 | name = "serde" 1054 | version = "1.0.204" 1055 | source = "registry+https://github.com/rust-lang/crates.io-index" 1056 | checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" 1057 | dependencies = [ 1058 | "serde_derive", 1059 | ] 1060 | 1061 | [[package]] 1062 | name = "serde_derive" 1063 | version = "1.0.204" 1064 | source = "registry+https://github.com/rust-lang/crates.io-index" 1065 | checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" 1066 | dependencies = [ 1067 | "proc-macro2", 1068 | "quote", 1069 | "syn", 1070 | ] 1071 | 1072 | [[package]] 1073 | name = "serde_json" 1074 | version = "1.0.120" 1075 | source = "registry+https://github.com/rust-lang/crates.io-index" 1076 | checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" 1077 | dependencies = [ 1078 | "itoa", 1079 | "ryu", 1080 | "serde", 1081 | ] 1082 | 1083 | [[package]] 1084 | name = "serde_urlencoded" 1085 | version = "0.7.1" 1086 | source = "registry+https://github.com/rust-lang/crates.io-index" 1087 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1088 | dependencies = [ 1089 | "form_urlencoded", 1090 | "itoa", 1091 | "ryu", 1092 | "serde", 1093 | ] 1094 | 1095 | [[package]] 1096 | name = "signal-hook" 1097 | version = "0.3.17" 1098 | source = "registry+https://github.com/rust-lang/crates.io-index" 1099 | checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" 1100 | dependencies = [ 1101 | "libc", 1102 | "signal-hook-registry", 1103 | ] 1104 | 1105 | [[package]] 1106 | name = "signal-hook-mio" 1107 | version = "0.2.3" 1108 | source = "registry+https://github.com/rust-lang/crates.io-index" 1109 | checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" 1110 | dependencies = [ 1111 | "libc", 1112 | "mio", 1113 | "signal-hook", 1114 | ] 1115 | 1116 | [[package]] 1117 | name = "signal-hook-registry" 1118 | version = "1.4.2" 1119 | source = "registry+https://github.com/rust-lang/crates.io-index" 1120 | checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" 1121 | dependencies = [ 1122 | "libc", 1123 | ] 1124 | 1125 | [[package]] 1126 | name = "slab" 1127 | version = "0.4.9" 1128 | source = "registry+https://github.com/rust-lang/crates.io-index" 1129 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 1130 | dependencies = [ 1131 | "autocfg", 1132 | ] 1133 | 1134 | [[package]] 1135 | name = "smallvec" 1136 | version = "1.13.2" 1137 | source = "registry+https://github.com/rust-lang/crates.io-index" 1138 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 1139 | 1140 | [[package]] 1141 | name = "socket2" 1142 | version = "0.5.7" 1143 | source = "registry+https://github.com/rust-lang/crates.io-index" 1144 | checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" 1145 | dependencies = [ 1146 | "libc", 1147 | "windows-sys 0.52.0", 1148 | ] 1149 | 1150 | [[package]] 1151 | name = "spin" 1152 | version = "0.9.8" 1153 | source = "registry+https://github.com/rust-lang/crates.io-index" 1154 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 1155 | 1156 | [[package]] 1157 | name = "stability" 1158 | version = "0.2.1" 1159 | source = "registry+https://github.com/rust-lang/crates.io-index" 1160 | checksum = "d904e7009df136af5297832a3ace3370cd14ff1546a232f4f185036c2736fcac" 1161 | dependencies = [ 1162 | "quote", 1163 | "syn", 1164 | ] 1165 | 1166 | [[package]] 1167 | name = "static_assertions" 1168 | version = "1.1.0" 1169 | source = "registry+https://github.com/rust-lang/crates.io-index" 1170 | checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 1171 | 1172 | [[package]] 1173 | name = "strum" 1174 | version = "0.26.3" 1175 | source = "registry+https://github.com/rust-lang/crates.io-index" 1176 | checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" 1177 | dependencies = [ 1178 | "strum_macros", 1179 | ] 1180 | 1181 | [[package]] 1182 | name = "strum_macros" 1183 | version = "0.26.4" 1184 | source = "registry+https://github.com/rust-lang/crates.io-index" 1185 | checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" 1186 | dependencies = [ 1187 | "heck", 1188 | "proc-macro2", 1189 | "quote", 1190 | "rustversion", 1191 | "syn", 1192 | ] 1193 | 1194 | [[package]] 1195 | name = "subtle" 1196 | version = "2.6.1" 1197 | source = "registry+https://github.com/rust-lang/crates.io-index" 1198 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 1199 | 1200 | [[package]] 1201 | name = "syn" 1202 | version = "2.0.71" 1203 | source = "registry+https://github.com/rust-lang/crates.io-index" 1204 | checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" 1205 | dependencies = [ 1206 | "proc-macro2", 1207 | "quote", 1208 | "unicode-ident", 1209 | ] 1210 | 1211 | [[package]] 1212 | name = "sync_wrapper" 1213 | version = "1.0.1" 1214 | source = "registry+https://github.com/rust-lang/crates.io-index" 1215 | checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" 1216 | 1217 | [[package]] 1218 | name = "system-configuration" 1219 | version = "0.5.1" 1220 | source = "registry+https://github.com/rust-lang/crates.io-index" 1221 | checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" 1222 | dependencies = [ 1223 | "bitflags 1.3.2", 1224 | "core-foundation", 1225 | "system-configuration-sys", 1226 | ] 1227 | 1228 | [[package]] 1229 | name = "system-configuration-sys" 1230 | version = "0.5.0" 1231 | source = "registry+https://github.com/rust-lang/crates.io-index" 1232 | checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" 1233 | dependencies = [ 1234 | "core-foundation-sys", 1235 | "libc", 1236 | ] 1237 | 1238 | [[package]] 1239 | name = "tempfile" 1240 | version = "3.10.1" 1241 | source = "registry+https://github.com/rust-lang/crates.io-index" 1242 | checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" 1243 | dependencies = [ 1244 | "cfg-if", 1245 | "fastrand", 1246 | "rustix", 1247 | "windows-sys 0.52.0", 1248 | ] 1249 | 1250 | [[package]] 1251 | name = "tinyvec" 1252 | version = "1.8.0" 1253 | source = "registry+https://github.com/rust-lang/crates.io-index" 1254 | checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" 1255 | dependencies = [ 1256 | "tinyvec_macros", 1257 | ] 1258 | 1259 | [[package]] 1260 | name = "tinyvec_macros" 1261 | version = "0.1.1" 1262 | source = "registry+https://github.com/rust-lang/crates.io-index" 1263 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 1264 | 1265 | [[package]] 1266 | name = "tokio" 1267 | version = "1.38.1" 1268 | source = "registry+https://github.com/rust-lang/crates.io-index" 1269 | checksum = "eb2caba9f80616f438e09748d5acda951967e1ea58508ef53d9c6402485a46df" 1270 | dependencies = [ 1271 | "backtrace", 1272 | "bytes", 1273 | "libc", 1274 | "mio", 1275 | "pin-project-lite", 1276 | "socket2", 1277 | "windows-sys 0.48.0", 1278 | ] 1279 | 1280 | [[package]] 1281 | name = "tokio-native-tls" 1282 | version = "0.3.1" 1283 | source = "registry+https://github.com/rust-lang/crates.io-index" 1284 | checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" 1285 | dependencies = [ 1286 | "native-tls", 1287 | "tokio", 1288 | ] 1289 | 1290 | [[package]] 1291 | name = "tokio-rustls" 1292 | version = "0.26.0" 1293 | source = "registry+https://github.com/rust-lang/crates.io-index" 1294 | checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" 1295 | dependencies = [ 1296 | "rustls", 1297 | "rustls-pki-types", 1298 | "tokio", 1299 | ] 1300 | 1301 | [[package]] 1302 | name = "tokio-util" 1303 | version = "0.7.11" 1304 | source = "registry+https://github.com/rust-lang/crates.io-index" 1305 | checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" 1306 | dependencies = [ 1307 | "bytes", 1308 | "futures-core", 1309 | "futures-sink", 1310 | "pin-project-lite", 1311 | "tokio", 1312 | ] 1313 | 1314 | [[package]] 1315 | name = "tower" 1316 | version = "0.4.13" 1317 | source = "registry+https://github.com/rust-lang/crates.io-index" 1318 | checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" 1319 | dependencies = [ 1320 | "futures-core", 1321 | "futures-util", 1322 | "pin-project", 1323 | "pin-project-lite", 1324 | "tokio", 1325 | "tower-layer", 1326 | "tower-service", 1327 | ] 1328 | 1329 | [[package]] 1330 | name = "tower-layer" 1331 | version = "0.3.2" 1332 | source = "registry+https://github.com/rust-lang/crates.io-index" 1333 | checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" 1334 | 1335 | [[package]] 1336 | name = "tower-service" 1337 | version = "0.3.2" 1338 | source = "registry+https://github.com/rust-lang/crates.io-index" 1339 | checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" 1340 | 1341 | [[package]] 1342 | name = "tracing" 1343 | version = "0.1.40" 1344 | source = "registry+https://github.com/rust-lang/crates.io-index" 1345 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 1346 | dependencies = [ 1347 | "pin-project-lite", 1348 | "tracing-core", 1349 | ] 1350 | 1351 | [[package]] 1352 | name = "tracing-core" 1353 | version = "0.1.32" 1354 | source = "registry+https://github.com/rust-lang/crates.io-index" 1355 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 1356 | dependencies = [ 1357 | "once_cell", 1358 | ] 1359 | 1360 | [[package]] 1361 | name = "try-lock" 1362 | version = "0.2.5" 1363 | source = "registry+https://github.com/rust-lang/crates.io-index" 1364 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 1365 | 1366 | [[package]] 1367 | name = "unicode-bidi" 1368 | version = "0.3.15" 1369 | source = "registry+https://github.com/rust-lang/crates.io-index" 1370 | checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" 1371 | 1372 | [[package]] 1373 | name = "unicode-ident" 1374 | version = "1.0.12" 1375 | source = "registry+https://github.com/rust-lang/crates.io-index" 1376 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 1377 | 1378 | [[package]] 1379 | name = "unicode-normalization" 1380 | version = "0.1.23" 1381 | source = "registry+https://github.com/rust-lang/crates.io-index" 1382 | checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" 1383 | dependencies = [ 1384 | "tinyvec", 1385 | ] 1386 | 1387 | [[package]] 1388 | name = "unicode-segmentation" 1389 | version = "1.11.0" 1390 | source = "registry+https://github.com/rust-lang/crates.io-index" 1391 | checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" 1392 | 1393 | [[package]] 1394 | name = "unicode-truncate" 1395 | version = "1.1.0" 1396 | source = "registry+https://github.com/rust-lang/crates.io-index" 1397 | checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" 1398 | dependencies = [ 1399 | "itertools", 1400 | "unicode-segmentation", 1401 | "unicode-width", 1402 | ] 1403 | 1404 | [[package]] 1405 | name = "unicode-width" 1406 | version = "0.1.13" 1407 | source = "registry+https://github.com/rust-lang/crates.io-index" 1408 | checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" 1409 | 1410 | [[package]] 1411 | name = "untrusted" 1412 | version = "0.9.0" 1413 | source = "registry+https://github.com/rust-lang/crates.io-index" 1414 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 1415 | 1416 | [[package]] 1417 | name = "url" 1418 | version = "2.5.2" 1419 | source = "registry+https://github.com/rust-lang/crates.io-index" 1420 | checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" 1421 | dependencies = [ 1422 | "form_urlencoded", 1423 | "idna", 1424 | "percent-encoding", 1425 | ] 1426 | 1427 | [[package]] 1428 | name = "vcpkg" 1429 | version = "0.2.15" 1430 | source = "registry+https://github.com/rust-lang/crates.io-index" 1431 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 1432 | 1433 | [[package]] 1434 | name = "version_check" 1435 | version = "0.9.4" 1436 | source = "registry+https://github.com/rust-lang/crates.io-index" 1437 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 1438 | 1439 | [[package]] 1440 | name = "want" 1441 | version = "0.3.1" 1442 | source = "registry+https://github.com/rust-lang/crates.io-index" 1443 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 1444 | dependencies = [ 1445 | "try-lock", 1446 | ] 1447 | 1448 | [[package]] 1449 | name = "wasi" 1450 | version = "0.11.0+wasi-snapshot-preview1" 1451 | source = "registry+https://github.com/rust-lang/crates.io-index" 1452 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1453 | 1454 | [[package]] 1455 | name = "wasm-bindgen" 1456 | version = "0.2.92" 1457 | source = "registry+https://github.com/rust-lang/crates.io-index" 1458 | checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" 1459 | dependencies = [ 1460 | "cfg-if", 1461 | "wasm-bindgen-macro", 1462 | ] 1463 | 1464 | [[package]] 1465 | name = "wasm-bindgen-backend" 1466 | version = "0.2.92" 1467 | source = "registry+https://github.com/rust-lang/crates.io-index" 1468 | checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" 1469 | dependencies = [ 1470 | "bumpalo", 1471 | "log", 1472 | "once_cell", 1473 | "proc-macro2", 1474 | "quote", 1475 | "syn", 1476 | "wasm-bindgen-shared", 1477 | ] 1478 | 1479 | [[package]] 1480 | name = "wasm-bindgen-futures" 1481 | version = "0.4.42" 1482 | source = "registry+https://github.com/rust-lang/crates.io-index" 1483 | checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" 1484 | dependencies = [ 1485 | "cfg-if", 1486 | "js-sys", 1487 | "wasm-bindgen", 1488 | "web-sys", 1489 | ] 1490 | 1491 | [[package]] 1492 | name = "wasm-bindgen-macro" 1493 | version = "0.2.92" 1494 | source = "registry+https://github.com/rust-lang/crates.io-index" 1495 | checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" 1496 | dependencies = [ 1497 | "quote", 1498 | "wasm-bindgen-macro-support", 1499 | ] 1500 | 1501 | [[package]] 1502 | name = "wasm-bindgen-macro-support" 1503 | version = "0.2.92" 1504 | source = "registry+https://github.com/rust-lang/crates.io-index" 1505 | checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" 1506 | dependencies = [ 1507 | "proc-macro2", 1508 | "quote", 1509 | "syn", 1510 | "wasm-bindgen-backend", 1511 | "wasm-bindgen-shared", 1512 | ] 1513 | 1514 | [[package]] 1515 | name = "wasm-bindgen-shared" 1516 | version = "0.2.92" 1517 | source = "registry+https://github.com/rust-lang/crates.io-index" 1518 | checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" 1519 | 1520 | [[package]] 1521 | name = "web-sys" 1522 | version = "0.3.69" 1523 | source = "registry+https://github.com/rust-lang/crates.io-index" 1524 | checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" 1525 | dependencies = [ 1526 | "js-sys", 1527 | "wasm-bindgen", 1528 | ] 1529 | 1530 | [[package]] 1531 | name = "winapi" 1532 | version = "0.3.9" 1533 | source = "registry+https://github.com/rust-lang/crates.io-index" 1534 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1535 | dependencies = [ 1536 | "winapi-i686-pc-windows-gnu", 1537 | "winapi-x86_64-pc-windows-gnu", 1538 | ] 1539 | 1540 | [[package]] 1541 | name = "winapi-i686-pc-windows-gnu" 1542 | version = "0.4.0" 1543 | source = "registry+https://github.com/rust-lang/crates.io-index" 1544 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1545 | 1546 | [[package]] 1547 | name = "winapi-x86_64-pc-windows-gnu" 1548 | version = "0.4.0" 1549 | source = "registry+https://github.com/rust-lang/crates.io-index" 1550 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1551 | 1552 | [[package]] 1553 | name = "windows-core" 1554 | version = "0.52.0" 1555 | source = "registry+https://github.com/rust-lang/crates.io-index" 1556 | checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" 1557 | dependencies = [ 1558 | "windows-targets 0.52.6", 1559 | ] 1560 | 1561 | [[package]] 1562 | name = "windows-sys" 1563 | version = "0.48.0" 1564 | source = "registry+https://github.com/rust-lang/crates.io-index" 1565 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 1566 | dependencies = [ 1567 | "windows-targets 0.48.5", 1568 | ] 1569 | 1570 | [[package]] 1571 | name = "windows-sys" 1572 | version = "0.52.0" 1573 | source = "registry+https://github.com/rust-lang/crates.io-index" 1574 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1575 | dependencies = [ 1576 | "windows-targets 0.52.6", 1577 | ] 1578 | 1579 | [[package]] 1580 | name = "windows-targets" 1581 | version = "0.48.5" 1582 | source = "registry+https://github.com/rust-lang/crates.io-index" 1583 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 1584 | dependencies = [ 1585 | "windows_aarch64_gnullvm 0.48.5", 1586 | "windows_aarch64_msvc 0.48.5", 1587 | "windows_i686_gnu 0.48.5", 1588 | "windows_i686_msvc 0.48.5", 1589 | "windows_x86_64_gnu 0.48.5", 1590 | "windows_x86_64_gnullvm 0.48.5", 1591 | "windows_x86_64_msvc 0.48.5", 1592 | ] 1593 | 1594 | [[package]] 1595 | name = "windows-targets" 1596 | version = "0.52.6" 1597 | source = "registry+https://github.com/rust-lang/crates.io-index" 1598 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1599 | dependencies = [ 1600 | "windows_aarch64_gnullvm 0.52.6", 1601 | "windows_aarch64_msvc 0.52.6", 1602 | "windows_i686_gnu 0.52.6", 1603 | "windows_i686_gnullvm", 1604 | "windows_i686_msvc 0.52.6", 1605 | "windows_x86_64_gnu 0.52.6", 1606 | "windows_x86_64_gnullvm 0.52.6", 1607 | "windows_x86_64_msvc 0.52.6", 1608 | ] 1609 | 1610 | [[package]] 1611 | name = "windows_aarch64_gnullvm" 1612 | version = "0.48.5" 1613 | source = "registry+https://github.com/rust-lang/crates.io-index" 1614 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 1615 | 1616 | [[package]] 1617 | name = "windows_aarch64_gnullvm" 1618 | version = "0.52.6" 1619 | source = "registry+https://github.com/rust-lang/crates.io-index" 1620 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1621 | 1622 | [[package]] 1623 | name = "windows_aarch64_msvc" 1624 | version = "0.48.5" 1625 | source = "registry+https://github.com/rust-lang/crates.io-index" 1626 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 1627 | 1628 | [[package]] 1629 | name = "windows_aarch64_msvc" 1630 | version = "0.52.6" 1631 | source = "registry+https://github.com/rust-lang/crates.io-index" 1632 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1633 | 1634 | [[package]] 1635 | name = "windows_i686_gnu" 1636 | version = "0.48.5" 1637 | source = "registry+https://github.com/rust-lang/crates.io-index" 1638 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 1639 | 1640 | [[package]] 1641 | name = "windows_i686_gnu" 1642 | version = "0.52.6" 1643 | source = "registry+https://github.com/rust-lang/crates.io-index" 1644 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1645 | 1646 | [[package]] 1647 | name = "windows_i686_gnullvm" 1648 | version = "0.52.6" 1649 | source = "registry+https://github.com/rust-lang/crates.io-index" 1650 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1651 | 1652 | [[package]] 1653 | name = "windows_i686_msvc" 1654 | version = "0.48.5" 1655 | source = "registry+https://github.com/rust-lang/crates.io-index" 1656 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 1657 | 1658 | [[package]] 1659 | name = "windows_i686_msvc" 1660 | version = "0.52.6" 1661 | source = "registry+https://github.com/rust-lang/crates.io-index" 1662 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1663 | 1664 | [[package]] 1665 | name = "windows_x86_64_gnu" 1666 | version = "0.48.5" 1667 | source = "registry+https://github.com/rust-lang/crates.io-index" 1668 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 1669 | 1670 | [[package]] 1671 | name = "windows_x86_64_gnu" 1672 | version = "0.52.6" 1673 | source = "registry+https://github.com/rust-lang/crates.io-index" 1674 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1675 | 1676 | [[package]] 1677 | name = "windows_x86_64_gnullvm" 1678 | version = "0.48.5" 1679 | source = "registry+https://github.com/rust-lang/crates.io-index" 1680 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 1681 | 1682 | [[package]] 1683 | name = "windows_x86_64_gnullvm" 1684 | version = "0.52.6" 1685 | source = "registry+https://github.com/rust-lang/crates.io-index" 1686 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1687 | 1688 | [[package]] 1689 | name = "windows_x86_64_msvc" 1690 | version = "0.48.5" 1691 | source = "registry+https://github.com/rust-lang/crates.io-index" 1692 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 1693 | 1694 | [[package]] 1695 | name = "windows_x86_64_msvc" 1696 | version = "0.52.6" 1697 | source = "registry+https://github.com/rust-lang/crates.io-index" 1698 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1699 | 1700 | [[package]] 1701 | name = "winreg" 1702 | version = "0.52.0" 1703 | source = "registry+https://github.com/rust-lang/crates.io-index" 1704 | checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" 1705 | dependencies = [ 1706 | "cfg-if", 1707 | "windows-sys 0.48.0", 1708 | ] 1709 | 1710 | [[package]] 1711 | name = "zerocopy" 1712 | version = "0.7.35" 1713 | source = "registry+https://github.com/rust-lang/crates.io-index" 1714 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 1715 | dependencies = [ 1716 | "zerocopy-derive", 1717 | ] 1718 | 1719 | [[package]] 1720 | name = "zerocopy-derive" 1721 | version = "0.7.35" 1722 | source = "registry+https://github.com/rust-lang/crates.io-index" 1723 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 1724 | dependencies = [ 1725 | "proc-macro2", 1726 | "quote", 1727 | "syn", 1728 | ] 1729 | 1730 | [[package]] 1731 | name = "zeroize" 1732 | version = "1.8.1" 1733 | source = "registry+https://github.com/rust-lang/crates.io-index" 1734 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 1735 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bahn-status" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | chrono = "0.4.38" 8 | rand = "0.8.5" 9 | ratatui = "0.27.0" 10 | reqwest = { version = "0.12.5", features = ["blocking", "json"] } 11 | serde = { version = "1.0.204", features = ["derive"] } 12 | serde_json = "1.0.120" 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bahn-status 2 | 3 | ## About 4 | 5 | Ein alternatives ratatui-basiertes TUI-Frontend fuer die Informationen, die die 6 | Deutsche Bahn freundlicherweise im ICE-Intranet unter 7 | [https://iceportal.de/api1/rs/status](https://iceportal.de/api1/rs/status) 8 | sowie 9 | [https://iceportal.de/api1/rs/tripInfo/trip](https://iceportal.de/api1/rs/tripInfo/trip) 10 | bereitstellt. Tatsaechlich findet sich dort auch manches, was nicht in den 11 | Statusanzeigen steht (z.B. Entfernung zum naechsten Ziel, was sehr nuetzlich 12 | sein kann). 13 | 14 | ![](./docs/sample.png) 15 | 16 | ## Contribution 17 | 18 | ☝ Jedes Mal, wenn der Zug zu spaet kommt, schreibe ich eine Zeile Code. 19 | -------------------------------------------------------------------------------- /docs/sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Baseng0815/bahn-status/1f740c507bc2e54cae955414743b4d573d313cee/docs/sample.png -------------------------------------------------------------------------------- /main: -------------------------------------------------------------------------------- 1 | -- You are riding on ICE9474 (ICE) ------------- 2 | 3 | +- Status information -------------------------- 4 | | Current Speed: 113 5 | | Connectivity: HIGH 6 | | Total trip length: 746km 7 | | Traveled so far: 73km 8 | | Remaining: 339km 9 | | Distance to next: 21km (Friedberg (Hess)) 10 | | Latitude/longitude: (50.57N, 8.66W) 11 | +----------------------------------------------- 12 | 13 | + Trip information ----------------------------- 14 | | x (START) <- Karlsruhe (08:51) 15 | | | actual departure: 08:57 (+6min) 16 | | | 17 | | x (65km) <- Mannheim (09:23) 18 | | | actual departure: 09:31 (+8min) 19 | | | reason: people on track 20 | | | 21 | | | 22 | | x (239km) <- Darmstadt (09:58) 23 | | | 24 | | x (257km) <- Frankfurt (10:07) 25 | | | 26 | | | 27 | | | 28 | | x (331km) <- Friedberg (Hess) (10:32) 29 | +----------------------------------------------- 30 | 31 | -- Last updated: 31 seconds ago ---------------- 32 | -------------------------------------------------------------------------------- /sample/status.json: -------------------------------------------------------------------------------- 1 | { 2 | "connection": true, 3 | "serviceLevel": "AVAILABLE_SERVICE", 4 | "gpsStatus": "VALID", 5 | "internet": "HIGH", 6 | "latitude": 50.085876666666664, 7 | "longitude": 8.669994666666666, 8 | "tileY": 9, 9 | "tileX": -67, 10 | "series": "412", 11 | "serverTime": 1721369676107, 12 | "speed": 3, 13 | "trainType": "ICE", 14 | "tzn": "ICE9474", 15 | "wagonClass": "FIRST", 16 | "connectivity": { 17 | "currentState": "HIGH", 18 | "nextState": "WEAK", 19 | "remainingTimeSeconds": 6000 20 | }, 21 | "bapInstalled": true 22 | } 23 | -------------------------------------------------------------------------------- /sample/trip.json: -------------------------------------------------------------------------------- 1 | { 2 | "trip": { 3 | "tripDate": "2024-07-19", 4 | "trainType": "ICE", 5 | "vzn": "1672", 6 | "actualPosition": 54357, 7 | "distanceFromLastStop": 23, 8 | "totalDistance": 735150, 9 | "stopInfo": { 10 | "scheduledNext": "8000337", 11 | "actualNext": "8000337", 12 | "actualLast": "8000124", 13 | "actualLastStarted": "8000337", 14 | "finalStationName": "Ostseebad Binz", 15 | "finalStationEvaNr": "8011191" 16 | }, 17 | "stops": [ 18 | { 19 | "station": { 20 | "evaNr": "8000105", 21 | "name": "Frankfurt(Main)Hbf", 22 | "code": null, 23 | "geocoordinates": { 24 | "latitude": 50.107145, 25 | "longitude": 8.663789 26 | } 27 | }, 28 | "timetable": { 29 | "scheduledArrivalTime": null, 30 | "actualArrivalTime": null, 31 | "showActualArrivalTime": null, 32 | "arrivalDelay": "", 33 | "scheduledDepartureTime": 1721371860000, 34 | "actualDepartureTime": 1721372479000, 35 | "showActualDepartureTime": true, 36 | "departureDelay": "+10" 37 | }, 38 | "track": { 39 | "scheduled": "13", 40 | "actual": "12" 41 | }, 42 | "info": { 43 | "status": 0, 44 | "passed": true, 45 | "positionStatus": "passed", 46 | "distance": 0, 47 | "distanceFromStart": 0 48 | }, 49 | "delayReasons": null 50 | }, 51 | { 52 | "station": { 53 | "evaNr": "8000111", 54 | "name": "Friedberg(Hess)", 55 | "code": null, 56 | "geocoordinates": { 57 | "latitude": 50.332606, 58 | "longitude": 8.762056 59 | } 60 | }, 61 | "timetable": { 62 | "scheduledArrivalTime": 1721373300000, 63 | "actualArrivalTime": 1721374361000, 64 | "showActualArrivalTime": true, 65 | "arrivalDelay": "+17", 66 | "scheduledDepartureTime": 1721373360000, 67 | "actualDepartureTime": 1721374431000, 68 | "showActualDepartureTime": true, 69 | "departureDelay": "+17" 70 | }, 71 | "track": { 72 | "scheduled": "4", 73 | "actual": "4" 74 | }, 75 | "info": { 76 | "status": 0, 77 | "passed": true, 78 | "positionStatus": "passed", 79 | "distance": 26034, 80 | "distanceFromStart": 26034 81 | }, 82 | "delayReasons": [ 83 | { 84 | "code": "47", 85 | "text": "verspätete Bereitstellung des Zuges" 86 | } 87 | ] 88 | }, 89 | { 90 | "station": { 91 | "evaNr": "8000124", 92 | "name": "Gießen", 93 | "code": null, 94 | "geocoordinates": { 95 | "latitude": 50.579059, 96 | "longitude": 8.661462 97 | } 98 | }, 99 | "timetable": { 100 | "scheduledArrivalTime": 1721374380000, 101 | "actualArrivalTime": 1721375400000, 102 | "showActualArrivalTime": true, 103 | "arrivalDelay": "+17", 104 | "scheduledDepartureTime": 1721374440000, 105 | "actualDepartureTime": 1721375460000, 106 | "showActualDepartureTime": true, 107 | "departureDelay": "+17" 108 | }, 109 | "track": { 110 | "scheduled": "2", 111 | "actual": "2" 112 | }, 113 | "info": { 114 | "status": 0, 115 | "passed": true, 116 | "positionStatus": "departed", 117 | "distance": 28323, 118 | "distanceFromStart": 54357 119 | }, 120 | "delayReasons": [ 121 | { 122 | "code": "47", 123 | "text": "verspätete Bereitstellung des Zuges" 124 | } 125 | ] 126 | }, 127 | { 128 | "station": { 129 | "evaNr": "8000337", 130 | "name": "Marburg(Lahn)", 131 | "code": null, 132 | "geocoordinates": { 133 | "latitude": 50.819272, 134 | "longitude": 8.775014 135 | } 136 | }, 137 | "timetable": { 138 | "scheduledArrivalTime": 1721375400000, 139 | "actualArrivalTime": 1721376300000, 140 | "showActualArrivalTime": true, 141 | "arrivalDelay": "+15", 142 | "scheduledDepartureTime": 1721375460000, 143 | "actualDepartureTime": 1721376420000, 144 | "showActualDepartureTime": true, 145 | "departureDelay": "+16" 146 | }, 147 | "track": { 148 | "scheduled": "5", 149 | "actual": "5" 150 | }, 151 | "info": { 152 | "status": 0, 153 | "passed": false, 154 | "positionStatus": "future", 155 | "distance": 27890, 156 | "distanceFromStart": 82247 157 | }, 158 | "delayReasons": [ 159 | { 160 | "code": "47", 161 | "text": "verspätete Bereitstellung des Zuges" 162 | } 163 | ] 164 | }, 165 | { 166 | "station": { 167 | "evaNr": "8000129", 168 | "name": "Treysa", 169 | "code": null, 170 | "geocoordinates": { 171 | "latitude": 50.910661, 172 | "longitude": 9.185673 173 | } 174 | }, 175 | "timetable": { 176 | "scheduledArrivalTime": 1721376840000, 177 | "actualArrivalTime": 1721377740000, 178 | "showActualArrivalTime": true, 179 | "arrivalDelay": "+15", 180 | "scheduledDepartureTime": 1721376900000, 181 | "actualDepartureTime": 1721377800000, 182 | "showActualDepartureTime": true, 183 | "departureDelay": "+15" 184 | }, 185 | "track": { 186 | "scheduled": "2", 187 | "actual": "2" 188 | }, 189 | "info": { 190 | "status": 0, 191 | "passed": false, 192 | "positionStatus": "future", 193 | "distance": 30568, 194 | "distanceFromStart": 112815 195 | }, 196 | "delayReasons": [ 197 | { 198 | "code": "47", 199 | "text": "verspätete Bereitstellung des Zuges" 200 | } 201 | ] 202 | }, 203 | { 204 | "station": { 205 | "evaNr": "8000368", 206 | "name": "Wabern(Bz Kassel)", 207 | "code": null, 208 | "geocoordinates": { 209 | "latitude": 51.103134, 210 | "longitude": 9.35804 211 | } 212 | }, 213 | "timetable": { 214 | "scheduledArrivalTime": 1721377920000, 215 | "actualArrivalTime": 1721378700000, 216 | "showActualArrivalTime": true, 217 | "arrivalDelay": "+13", 218 | "scheduledDepartureTime": 1721377980000, 219 | "actualDepartureTime": 1721378760000, 220 | "showActualDepartureTime": true, 221 | "departureDelay": "+13" 222 | }, 223 | "track": { 224 | "scheduled": "5", 225 | "actual": "5" 226 | }, 227 | "info": { 228 | "status": 0, 229 | "passed": false, 230 | "positionStatus": "future", 231 | "distance": 24573, 232 | "distanceFromStart": 137388 233 | }, 234 | "delayReasons": [ 235 | { 236 | "code": "47", 237 | "text": "verspätete Bereitstellung des Zuges" 238 | } 239 | ] 240 | }, 241 | { 242 | "station": { 243 | "evaNr": "8003200", 244 | "name": "Kassel-Wilhelmshöhe", 245 | "code": null, 246 | "geocoordinates": { 247 | "latitude": 51.3125585, 248 | "longitude": 9.44711566 249 | } 250 | }, 251 | "timetable": { 252 | "scheduledArrivalTime": 1721379240000, 253 | "actualArrivalTime": 1721379900000, 254 | "showActualArrivalTime": true, 255 | "arrivalDelay": "+11", 256 | "scheduledDepartureTime": 1721379360000, 257 | "actualDepartureTime": 1721380080000, 258 | "showActualDepartureTime": true, 259 | "departureDelay": "+12" 260 | }, 261 | "track": { 262 | "scheduled": "3", 263 | "actual": "3" 264 | }, 265 | "info": { 266 | "status": 0, 267 | "passed": false, 268 | "positionStatus": "future", 269 | "distance": 24106, 270 | "distanceFromStart": 161494 271 | }, 272 | "delayReasons": [ 273 | { 274 | "code": "47", 275 | "text": "verspätete Bereitstellung des Zuges" 276 | } 277 | ] 278 | }, 279 | { 280 | "station": { 281 | "evaNr": "8000128", 282 | "name": "Göttingen", 283 | "code": null, 284 | "geocoordinates": { 285 | "latitude": 51.536815, 286 | "longitude": 9.926072 287 | } 288 | }, 289 | "timetable": { 290 | "scheduledArrivalTime": 1721380560000, 291 | "actualArrivalTime": 1721381160000, 292 | "showActualArrivalTime": true, 293 | "arrivalDelay": "+10", 294 | "scheduledDepartureTime": 1721380620000, 295 | "actualDepartureTime": 1721381280000, 296 | "showActualDepartureTime": true, 297 | "departureDelay": "+11" 298 | }, 299 | "track": { 300 | "scheduled": "9", 301 | "actual": "9" 302 | }, 303 | "info": { 304 | "status": 0, 305 | "passed": false, 306 | "positionStatus": "future", 307 | "distance": 41540, 308 | "distanceFromStart": 203034 309 | }, 310 | "delayReasons": [ 311 | { 312 | "code": "47", 313 | "text": "verspätete Bereitstellung des Zuges" 314 | } 315 | ] 316 | }, 317 | { 318 | "station": { 319 | "evaNr": "8000152", 320 | "name": "Hannover Hbf", 321 | "code": null, 322 | "geocoordinates": { 323 | "latitude": 52.376761, 324 | "longitude": 9.741021 325 | } 326 | }, 327 | "timetable": { 328 | "scheduledArrivalTime": 1721382960000, 329 | "actualArrivalTime": 1721383380000, 330 | "showActualArrivalTime": true, 331 | "arrivalDelay": "+7", 332 | "scheduledDepartureTime": 1721383140000, 333 | "actualDepartureTime": 1721383500000, 334 | "showActualDepartureTime": true, 335 | "departureDelay": "+6" 336 | }, 337 | "track": { 338 | "scheduled": "8", 339 | "actual": "8" 340 | }, 341 | "info": { 342 | "status": 0, 343 | "passed": false, 344 | "positionStatus": "future", 345 | "distance": 94281, 346 | "distanceFromStart": 297315 347 | }, 348 | "delayReasons": [ 349 | { 350 | "code": "47", 351 | "text": "verspätete Bereitstellung des Zuges" 352 | } 353 | ] 354 | }, 355 | { 356 | "station": { 357 | "evaNr": "8000064", 358 | "name": "Celle", 359 | "code": null, 360 | "geocoordinates": { 361 | "latitude": 52.6204548, 362 | "longitude": 10.062468 363 | } 364 | }, 365 | "timetable": { 366 | "scheduledArrivalTime": 1721384220000, 367 | "actualArrivalTime": 1721384580000, 368 | "showActualArrivalTime": true, 369 | "arrivalDelay": "+6", 370 | "scheduledDepartureTime": 1721384280000, 371 | "actualDepartureTime": 1721384640000, 372 | "showActualDepartureTime": true, 373 | "departureDelay": "+6" 374 | }, 375 | "track": { 376 | "scheduled": "5", 377 | "actual": "5" 378 | }, 379 | "info": { 380 | "status": 0, 381 | "passed": false, 382 | "positionStatus": "future", 383 | "distance": 34763, 384 | "distanceFromStart": 332078 385 | }, 386 | "delayReasons": [ 387 | { 388 | "code": "47", 389 | "text": "verspätete Bereitstellung des Zuges" 390 | } 391 | ] 392 | }, 393 | { 394 | "station": { 395 | "evaNr": "8000168", 396 | "name": "Uelzen", 397 | "code": null, 398 | "geocoordinates": { 399 | "latitude": 52.969781, 400 | "longitude": 10.553053 401 | } 402 | }, 403 | "timetable": { 404 | "scheduledArrivalTime": 1721385600000, 405 | "actualArrivalTime": 1721385900000, 406 | "showActualArrivalTime": true, 407 | "arrivalDelay": "+5", 408 | "scheduledDepartureTime": 1721385720000, 409 | "actualDepartureTime": 1721386020000, 410 | "showActualDepartureTime": true, 411 | "departureDelay": "+5" 412 | }, 413 | "track": { 414 | "scheduled": "102", 415 | "actual": "102" 416 | }, 417 | "info": { 418 | "status": 0, 419 | "passed": false, 420 | "positionStatus": "future", 421 | "distance": 50973, 422 | "distanceFromStart": 383051 423 | }, 424 | "delayReasons": [ 425 | { 426 | "code": "47", 427 | "text": "verspätete Bereitstellung des Zuges" 428 | } 429 | ] 430 | }, 431 | { 432 | "station": { 433 | "evaNr": "8000238", 434 | "name": "Lüneburg", 435 | "code": null, 436 | "geocoordinates": { 437 | "latitude": 53.249656, 438 | "longitude": 10.41989 439 | } 440 | }, 441 | "timetable": { 442 | "scheduledArrivalTime": 1721386620000, 443 | "actualArrivalTime": 1721386800000, 444 | "showActualArrivalTime": true, 445 | "arrivalDelay": "+3", 446 | "scheduledDepartureTime": 1721386740000, 447 | "actualDepartureTime": 1721386920000, 448 | "showActualDepartureTime": true, 449 | "departureDelay": "+3" 450 | }, 451 | "track": { 452 | "scheduled": "2", 453 | "actual": "2" 454 | }, 455 | "info": { 456 | "status": 0, 457 | "passed": false, 458 | "positionStatus": "future", 459 | "distance": 32374, 460 | "distanceFromStart": 415425 461 | }, 462 | "delayReasons": [ 463 | { 464 | "code": "47", 465 | "text": "verspätete Bereitstellung des Zuges" 466 | } 467 | ] 468 | }, 469 | { 470 | "station": { 471 | "evaNr": "8000147", 472 | "name": "Hamburg-Harburg", 473 | "code": null, 474 | "geocoordinates": { 475 | "latitude": 53.455908, 476 | "longitude": 9.991701 477 | } 478 | }, 479 | "timetable": { 480 | "scheduledArrivalTime": 1721387760000, 481 | "actualArrivalTime": 1721387940000, 482 | "showActualArrivalTime": true, 483 | "arrivalDelay": "+3", 484 | "scheduledDepartureTime": 1721387880000, 485 | "actualDepartureTime": 1721388060000, 486 | "showActualDepartureTime": true, 487 | "departureDelay": "+3" 488 | }, 489 | "track": { 490 | "scheduled": "1", 491 | "actual": "1" 492 | }, 493 | "info": { 494 | "status": 0, 495 | "passed": false, 496 | "positionStatus": "future", 497 | "distance": 36529, 498 | "distanceFromStart": 451954 499 | }, 500 | "delayReasons": [ 501 | { 502 | "code": "47", 503 | "text": "verspätete Bereitstellung des Zuges" 504 | } 505 | ] 506 | }, 507 | { 508 | "station": { 509 | "evaNr": "8002549", 510 | "name": "Hamburg Hbf", 511 | "code": null, 512 | "geocoordinates": { 513 | "latitude": 53.552736, 514 | "longitude": 10.006909 515 | } 516 | }, 517 | "timetable": { 518 | "scheduledArrivalTime": 1721388600000, 519 | "actualArrivalTime": 1721388780000, 520 | "showActualArrivalTime": true, 521 | "arrivalDelay": "+3", 522 | "scheduledDepartureTime": 1721389380000, 523 | "actualDepartureTime": 1721389560000, 524 | "showActualDepartureTime": true, 525 | "departureDelay": "+3" 526 | }, 527 | "track": { 528 | "scheduled": "11A-C", 529 | "actual": "11A-C" 530 | }, 531 | "info": { 532 | "status": 0, 533 | "passed": false, 534 | "positionStatus": "future", 535 | "distance": 10817, 536 | "distanceFromStart": 462771 537 | }, 538 | "delayReasons": [ 539 | { 540 | "code": "47", 541 | "text": "verspätete Bereitstellung des Zuges" 542 | } 543 | ] 544 | }, 545 | { 546 | "station": { 547 | "evaNr": "8010324", 548 | "name": "Schwerin Hbf", 549 | "code": null, 550 | "geocoordinates": { 551 | "latitude": 53.634739, 552 | "longitude": 11.407455 553 | } 554 | }, 555 | "timetable": { 556 | "scheduledArrivalTime": 1721392560000, 557 | "actualArrivalTime": 1721392560000, 558 | "showActualArrivalTime": true, 559 | "arrivalDelay": "", 560 | "scheduledDepartureTime": 1721392620000, 561 | "actualDepartureTime": 1721392740000, 562 | "showActualDepartureTime": true, 563 | "departureDelay": "+2" 564 | }, 565 | "track": { 566 | "scheduled": "2", 567 | "actual": "2" 568 | }, 569 | "info": { 570 | "status": 0, 571 | "passed": false, 572 | "positionStatus": "future", 573 | "distance": 92902, 574 | "distanceFromStart": 555673 575 | }, 576 | "delayReasons": [ 577 | { 578 | "code": "47", 579 | "text": "verspätete Bereitstellung des Zuges" 580 | } 581 | ] 582 | }, 583 | { 584 | "station": { 585 | "evaNr": "8010066", 586 | "name": "Bützow", 587 | "code": null, 588 | "geocoordinates": { 589 | "latitude": 53.8371137, 590 | "longitude": 11.9981942 591 | } 592 | }, 593 | "timetable": { 594 | "scheduledArrivalTime": 1721394480000, 595 | "actualArrivalTime": 1721394480000, 596 | "showActualArrivalTime": true, 597 | "arrivalDelay": "", 598 | "scheduledDepartureTime": 1721394600000, 599 | "actualDepartureTime": 1721394600000, 600 | "showActualDepartureTime": true, 601 | "departureDelay": "" 602 | }, 603 | "track": { 604 | "scheduled": "2", 605 | "actual": "2" 606 | }, 607 | "info": { 608 | "status": 0, 609 | "passed": false, 610 | "positionStatus": "future", 611 | "distance": 44913, 612 | "distanceFromStart": 600586 613 | }, 614 | "delayReasons": [ 615 | { 616 | "code": "47", 617 | "text": "verspätete Bereitstellung des Zuges" 618 | } 619 | ] 620 | }, 621 | { 622 | "station": { 623 | "evaNr": "8010304", 624 | "name": "Rostock Hbf", 625 | "code": null, 626 | "geocoordinates": { 627 | "latitude": 54.078246, 628 | "longitude": 12.131079 629 | } 630 | }, 631 | "timetable": { 632 | "scheduledArrivalTime": 1721395920000, 633 | "actualArrivalTime": 1721395920000, 634 | "showActualArrivalTime": true, 635 | "arrivalDelay": "", 636 | "scheduledDepartureTime": 1721396280000, 637 | "actualDepartureTime": 1721396280000, 638 | "showActualDepartureTime": true, 639 | "departureDelay": "" 640 | }, 641 | "track": { 642 | "scheduled": "7", 643 | "actual": "7" 644 | }, 645 | "info": { 646 | "status": 0, 647 | "passed": false, 648 | "positionStatus": "future", 649 | "distance": 28195, 650 | "distanceFromStart": 628781 651 | }, 652 | "delayReasons": [ 653 | { 654 | "code": "47", 655 | "text": "verspätete Bereitstellung des Zuges" 656 | } 657 | ] 658 | }, 659 | { 660 | "station": { 661 | "evaNr": "8012763", 662 | "name": "Ribnitz-Damgarten West", 663 | "code": null, 664 | "geocoordinates": { 665 | "latitude": 54.239176, 666 | "longitude": 12.436965 667 | } 668 | }, 669 | "timetable": { 670 | "scheduledArrivalTime": 1721397540000, 671 | "actualArrivalTime": 1721397540000, 672 | "showActualArrivalTime": true, 673 | "arrivalDelay": "", 674 | "scheduledDepartureTime": 1721397660000, 675 | "actualDepartureTime": 1721397660000, 676 | "showActualDepartureTime": true, 677 | "departureDelay": "" 678 | }, 679 | "track": { 680 | "scheduled": "1", 681 | "actual": "1" 682 | }, 683 | "info": { 684 | "status": 0, 685 | "passed": false, 686 | "positionStatus": "future", 687 | "distance": 26782, 688 | "distanceFromStart": 655563 689 | }, 690 | "delayReasons": [ 691 | { 692 | "code": "47", 693 | "text": "verspätete Bereitstellung des Zuges" 694 | } 695 | ] 696 | }, 697 | { 698 | "station": { 699 | "evaNr": "8010355", 700 | "name": "Velgast", 701 | "code": null, 702 | "geocoordinates": { 703 | "latitude": 54.277316, 704 | "longitude": 12.803137 705 | } 706 | }, 707 | "timetable": { 708 | "scheduledArrivalTime": 1721398500000, 709 | "actualArrivalTime": 1721398500000, 710 | "showActualArrivalTime": true, 711 | "arrivalDelay": "", 712 | "scheduledDepartureTime": 1721398560000, 713 | "actualDepartureTime": 1721398560000, 714 | "showActualDepartureTime": true, 715 | "departureDelay": "" 716 | }, 717 | "track": { 718 | "scheduled": "2", 719 | "actual": "2" 720 | }, 721 | "info": { 722 | "status": 0, 723 | "passed": false, 724 | "positionStatus": "future", 725 | "distance": 24166, 726 | "distanceFromStart": 679729 727 | }, 728 | "delayReasons": [ 729 | { 730 | "code": "47", 731 | "text": "verspätete Bereitstellung des Zuges" 732 | } 733 | ] 734 | }, 735 | { 736 | "station": { 737 | "evaNr": "8010338", 738 | "name": "Stralsund Hbf", 739 | "code": null, 740 | "geocoordinates": { 741 | "latitude": 54.308626, 742 | "longitude": 13.077321 743 | } 744 | }, 745 | "timetable": { 746 | "scheduledArrivalTime": 1721399400000, 747 | "actualArrivalTime": 1721399400000, 748 | "showActualArrivalTime": true, 749 | "arrivalDelay": "", 750 | "scheduledDepartureTime": 1721399520000, 751 | "actualDepartureTime": 1721399520000, 752 | "showActualDepartureTime": true, 753 | "departureDelay": "" 754 | }, 755 | "track": { 756 | "scheduled": "6", 757 | "actual": "6" 758 | }, 759 | "info": { 760 | "status": 0, 761 | "passed": false, 762 | "positionStatus": "future", 763 | "distance": 18136, 764 | "distanceFromStart": 697865 765 | }, 766 | "delayReasons": [ 767 | { 768 | "code": "47", 769 | "text": "verspätete Bereitstellung des Zuges" 770 | } 771 | ] 772 | }, 773 | { 774 | "station": { 775 | "evaNr": "8010033", 776 | "name": "Bergen auf Rügen", 777 | "code": null, 778 | "geocoordinates": { 779 | "latitude": 54.4205, 780 | "longitude": 13.417821 781 | } 782 | }, 783 | "timetable": { 784 | "scheduledArrivalTime": 1721400840000, 785 | "actualArrivalTime": 1721400840000, 786 | "showActualArrivalTime": true, 787 | "arrivalDelay": "", 788 | "scheduledDepartureTime": 1721400960000, 789 | "actualDepartureTime": 1721400960000, 790 | "showActualDepartureTime": true, 791 | "departureDelay": "" 792 | }, 793 | "track": { 794 | "scheduled": "2", 795 | "actual": "2" 796 | }, 797 | "info": { 798 | "status": 0, 799 | "passed": false, 800 | "positionStatus": "future", 801 | "distance": 25332, 802 | "distanceFromStart": 723197 803 | }, 804 | "delayReasons": [ 805 | { 806 | "code": "47", 807 | "text": "verspätete Bereitstellung des Zuges" 808 | } 809 | ] 810 | }, 811 | { 812 | "station": { 813 | "evaNr": "8011191", 814 | "name": "Ostseebad Binz", 815 | "code": null, 816 | "geocoordinates": { 817 | "latitude": 54.404819, 818 | "longitude": 13.600507 819 | } 820 | }, 821 | "timetable": { 822 | "scheduledArrivalTime": 1721402400000, 823 | "actualArrivalTime": 1721402400000, 824 | "showActualArrivalTime": true, 825 | "arrivalDelay": "", 826 | "scheduledDepartureTime": null, 827 | "actualDepartureTime": null, 828 | "showActualDepartureTime": null, 829 | "departureDelay": "" 830 | }, 831 | "track": { 832 | "scheduled": "2", 833 | "actual": "2" 834 | }, 835 | "info": { 836 | "status": 0, 837 | "passed": false, 838 | "positionStatus": "future", 839 | "distance": 11953, 840 | "distanceFromStart": 735150 841 | }, 842 | "delayReasons": [ 843 | { 844 | "code": "47", 845 | "text": "verspätete Bereitstellung des Zuges" 846 | } 847 | ] 848 | } 849 | ] 850 | }, 851 | "connection": { 852 | "trainType": null, 853 | "vzn": null, 854 | "trainNumber": null, 855 | "station": null, 856 | "timetable": null, 857 | "track": null, 858 | "info": null, 859 | "stops": null, 860 | "conflict": "NO_CONFLICT" 861 | }, 862 | "active": null 863 | } 864 | -------------------------------------------------------------------------------- /src/api.rs: -------------------------------------------------------------------------------- 1 | // API access and data structures 2 | 3 | // Status 4 | 5 | use std::{ 6 | error::Error, 7 | fs::{self, File}, 8 | io::Read, 9 | path::{Path, PathBuf}, 10 | }; 11 | 12 | use rand::Rng; 13 | use serde::Deserialize; 14 | 15 | #[derive(Default, Deserialize, Debug)] 16 | pub struct ApiEndpoints { 17 | pub status: String, 18 | pub trip: String, 19 | } 20 | 21 | #[derive(Default, Deserialize, Debug)] 22 | pub struct ApiPaths { 23 | pub status: PathBuf, 24 | pub trip: PathBuf, 25 | } 26 | 27 | #[derive(Default, Deserialize, Debug)] 28 | pub struct Connectivity { 29 | currentState: String, 30 | nextState: Option, 31 | remainingTimeSeconds: Option, 32 | } 33 | 34 | #[derive(Default, Deserialize, Debug)] 35 | pub struct StatusInfo { 36 | pub connection: bool, // no idea what is is 37 | pub serviceLevel: String, 38 | pub gpsStatus: String, 39 | pub internet: String, 40 | pub latitude: f64, 41 | pub longitude: f64, 42 | pub tileY: i64, 43 | pub tileX: i64, 44 | pub series: String, // TODO parse in a better way (I'm not a train nerd so w/e) 45 | pub serverTime: u64, 46 | pub speed: f64, 47 | pub trainType: String, 48 | pub tzn: String, // train number 49 | pub wagonClass: String, 50 | connectivity: Connectivity, 51 | pub bapInstalled: bool, // bap = bahn-api ? 52 | } 53 | 54 | // Trip 55 | 56 | #[derive(Default, Deserialize, Debug)] 57 | pub struct TripStopInfo { 58 | pub scheduledNext: String, 59 | pub actualNext: String, 60 | pub actualLast: String, 61 | pub actualLastStarted: String, 62 | pub finalStationName: String, 63 | pub finalStationEvaNr: String, 64 | } 65 | 66 | #[derive(Default, Deserialize, Debug)] 67 | pub struct GeoCoordinates { 68 | pub latitude: f64, 69 | pub longitude: f64, 70 | } 71 | 72 | #[derive(Default, Deserialize, Debug)] 73 | pub struct Station { 74 | pub evaNr: String, 75 | pub name: String, 76 | pub code: Option, 77 | pub geocoordinates: GeoCoordinates, 78 | } 79 | 80 | #[derive(Default, Deserialize, Debug)] 81 | pub struct Timetable { 82 | pub scheduledArrivalTime: Option, // option since no arrival at first station 83 | pub actualArrivalTime: Option, 84 | pub showActualArrivalTime: Option, 85 | pub arrivalDelay: Option, 86 | pub scheduledDepartureTime: Option, // option since no departure from last station 87 | pub actualDepartureTime: Option, 88 | pub showActualDepartureTime: Option, 89 | pub departureDelay: Option, 90 | } 91 | 92 | #[derive(Default, Deserialize, Debug)] 93 | pub struct Track { 94 | pub scheduled: String, 95 | pub actual: String, 96 | } 97 | 98 | #[derive(Default, Deserialize, Debug)] 99 | pub struct StopInfo { 100 | pub status: u64, 101 | pub passed: bool, 102 | pub positionStatus: String, 103 | pub distance: u64, 104 | pub distanceFromStart: u64, 105 | } 106 | 107 | #[derive(Default, Deserialize, Debug)] 108 | pub struct DelayReason { 109 | // TODO can't fill this out yet (the train is actually on time) 110 | } 111 | 112 | #[derive(Default, Deserialize, Debug)] 113 | pub struct Stop { 114 | pub station: Station, 115 | pub timetable: Timetable, 116 | pub track: Track, 117 | pub info: StopInfo, 118 | pub delay_reasons: Option>, 119 | } 120 | 121 | #[derive(Default, Deserialize, Debug)] 122 | pub struct Connection { 123 | pub trainType: Option, 124 | pub vzn: Option, 125 | pub trainNumber: Option, 126 | pub station: Option, 127 | pub timetable: Option, 128 | pub track: Option, 129 | pub info: Option, 130 | pub stops: Option>, 131 | pub conflict: String, 132 | } 133 | 134 | #[derive(Default, Deserialize, Debug)] 135 | pub struct Trip { 136 | pub tripDate: String, 137 | pub trainType: String, 138 | pub vzn: String, // train identifier 139 | pub actualPosition: u64, 140 | pub distanceFromLastStop: u64, 141 | pub totalDistance: u64, 142 | pub stopInfo: TripStopInfo, 143 | pub stops: Vec, 144 | } 145 | 146 | #[derive(Default, Deserialize, Debug)] 147 | pub struct TripInfo { 148 | pub trip: Trip, 149 | pub connection: Connection, 150 | pub active: Option, 151 | } 152 | 153 | #[derive(Default, Deserialize, Debug)] 154 | pub struct Info { 155 | pub status: StatusInfo, 156 | pub trip: TripInfo, 157 | } 158 | 159 | impl StatusInfo { 160 | pub fn query(endpoint: &str) -> Result { 161 | let client = reqwest::blocking::Client::new(); 162 | 163 | let response = client 164 | .get(endpoint) 165 | .header( 166 | "User-Agent", 167 | "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0", 168 | ) 169 | .send()?; 170 | let deserialized = response.json()?; 171 | Ok(deserialized) 172 | } 173 | 174 | pub fn from_file(path: &Path) -> Result> { 175 | let content = fs::read_to_string(path)?; 176 | let mut status: StatusInfo = serde_json::from_str(&content)?; 177 | status.speed = rand::thread_rng().gen_range(0.0..300.0); 178 | Ok(status) 179 | } 180 | } 181 | 182 | impl TripInfo { 183 | pub fn query(endpoint: &str) -> Result { 184 | let client = reqwest::blocking::Client::new(); 185 | 186 | let response = client 187 | .get(endpoint) 188 | .header( 189 | "User-Agent", 190 | "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0", 191 | ) 192 | .send()?; 193 | let deserialized = response.json()?; 194 | Ok(deserialized) 195 | } 196 | 197 | pub fn from_file(path: &Path) -> Result> { 198 | let content = fs::read_to_string(path)?; 199 | let trip: TripInfo = serde_json::from_str(&content)?; 200 | Ok(trip) 201 | } 202 | } 203 | 204 | impl Info { 205 | pub fn query(endpoints: &ApiEndpoints) -> Result { 206 | let status = StatusInfo::query(&endpoints.status)?; 207 | let trip = TripInfo::query(&endpoints.trip)?; 208 | 209 | Ok(Info { status, trip }) 210 | } 211 | 212 | pub fn from_file(paths: &ApiPaths) -> Result> { 213 | let status = StatusInfo::from_file(&paths.status)?; 214 | let trip = TripInfo::from_file(&paths.trip)?; 215 | 216 | Ok(Info { status, trip }) 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /src/frontend.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | collections::VecDeque, 3 | error::Error, 4 | io::{self, stdout, Stdout}, 5 | path::PathBuf, 6 | time::{Duration, Instant}, 7 | }; 8 | 9 | use chrono::{DateTime, Local, NaiveDateTime}; 10 | use ratatui::{ 11 | backend::CrosstermBackend, 12 | crossterm::{ 13 | event::{self, Event, KeyCode}, 14 | terminal::{enable_raw_mode, EnterAlternateScreen}, 15 | ExecutableCommand, 16 | }, 17 | layout::{Constraint, Direction, Layout, Rect}, 18 | style::Color, 19 | text::{Line, Span, Text}, 20 | widgets::{ 21 | self, 22 | canvas::{Canvas, Circle, Map, MapResolution, Shape}, 23 | Block, Paragraph, 24 | }, 25 | Frame, Terminal, 26 | }; 27 | 28 | use crate::api::{ApiEndpoints, ApiPaths, Info, Station, StatusInfo}; 29 | 30 | // +- Status information -------------------------- 31 | // | Current Speed: 113 32 | // | Connectivity: HIGH 33 | // | Total trip length: 746km 34 | // | Traveled so far: 73km 35 | // | Remaining: 339km 36 | // | Distance to next: 21km (Friedberg (Hess)) 37 | // | Latitude/longitude: (50.57N, 8.66W) 38 | // +----------------------------------------------- 39 | 40 | #[derive(Debug, PartialEq)] 41 | enum PanelSelection { 42 | BasicInformation, 43 | StatusInformation, 44 | SpeedInformation, 45 | TripInformation, 46 | } 47 | 48 | impl PanelSelection { 49 | pub fn next(&mut self) { 50 | *self = match *self { 51 | PanelSelection::BasicInformation => PanelSelection::StatusInformation, 52 | PanelSelection::StatusInformation => PanelSelection::SpeedInformation, 53 | PanelSelection::SpeedInformation => PanelSelection::TripInformation, 54 | PanelSelection::TripInformation => PanelSelection::BasicInformation, 55 | } 56 | } 57 | 58 | pub fn prev(&mut self) { 59 | *self = match *self { 60 | PanelSelection::BasicInformation => PanelSelection::TripInformation, 61 | PanelSelection::StatusInformation => PanelSelection::BasicInformation, 62 | PanelSelection::SpeedInformation => PanelSelection::StatusInformation, 63 | PanelSelection::TripInformation => PanelSelection::SpeedInformation, 64 | } 65 | } 66 | } 67 | 68 | // variables preserved across draw calls 69 | #[derive(Debug)] 70 | pub struct Frontend { 71 | selection: PanelSelection, 72 | data: VecDeque, // server timestamp contained in status 73 | 74 | // data for trip information 75 | selected_station_detailed: bool, 76 | selected_station: usize, 77 | } 78 | 79 | impl Frontend { 80 | pub fn new(bufsize: usize) -> Result> { 81 | Ok(Frontend { 82 | selection: PanelSelection::BasicInformation, 83 | data: VecDeque::with_capacity(bufsize), 84 | selected_station_detailed: false, 85 | selected_station: 0, 86 | }) 87 | } 88 | 89 | fn draw_basic_info(&self, frame: &mut Frame, area: Rect) { 90 | let info = self.data.back().expect("Nothing to draw"); 91 | 92 | let content = format!( 93 | "\ 94 | Schienenfahrzeugtyp: {} 95 | Schienenfahrzeugbezeichnung: {} 96 | Sozioökonomisches Milieu: {} 97 | Streckenführung: von {} nach {} 98 | ", 99 | info.status.trainType, 100 | info.status.tzn, 101 | info.status.wagonClass, 102 | info.trip 103 | .trip 104 | .stops 105 | .first() 106 | .expect("Everything has to start somewhere") 107 | .station 108 | .name, 109 | info.trip 110 | .trip 111 | .stops 112 | .last() 113 | .expect("Everything has to end somewhere") 114 | .station 115 | .name 116 | ); 117 | 118 | let block = if self.selection == PanelSelection::BasicInformation { 119 | Block::bordered() 120 | .title("Grundlegende Informationen") 121 | .border_style(Color::Magenta) 122 | } else { 123 | Block::bordered().title("Grundlegende Informationen") 124 | }; 125 | 126 | frame.render_widget(Paragraph::new(content).block(block), area); 127 | } 128 | 129 | fn draw_status(&self, frame: &mut Frame, area: Rect) { 130 | let info = self.data.back().expect("Nothing to draw"); 131 | 132 | let ap = info.trip.trip.actualPosition; 133 | let td = info.trip.trip.totalDistance; 134 | 135 | let average_speed = 136 | self.data.iter().fold(0.0, |acc, e| acc + e.status.speed) / self.data.len() as f64; 137 | 138 | let next_stop_eva = &info.trip.trip.stopInfo.scheduledNext; 139 | let next_stop = &info 140 | .trip 141 | .trip 142 | .stops 143 | .iter() 144 | .find(|stop| &stop.station.evaNr == next_stop_eva) 145 | .expect("A stop with this evaNr must exist"); 146 | 147 | let next_stop_dist = next_stop.info.distanceFromStart - ap; 148 | let next_stop_name = &next_stop.station.name; 149 | 150 | let content = format!( 151 | "\ 152 | Aktuelle Geschwindigkeit: {:.0}km/h 153 | Gleitender Mittelwert: {:.0}km/h 154 | Internetzwerkverbindungsgüte: {} 155 | Gesamte Streckenlänge: {}km 156 | Davon bereits zurückgelegt: {}km ({:.2}%) 157 | Verbleibend (nach Adam Riese): {}km ({:.2}%) 158 | Entfernung zum nächsten Halt: {}km ({}) 159 | Aktuelle geographische Lage: ({:.03}N, {:.03}W)", 160 | info.status.speed, 161 | average_speed, 162 | info.status.internet, 163 | td / 1000, 164 | ap / 1000, 165 | ap as f64 / td as f64 * 100.0, 166 | (td - ap) / 1000, 167 | (td - ap) as f64 / td as f64 * 100.0, 168 | next_stop_dist / 1000, 169 | next_stop_name, 170 | info.status.latitude, 171 | info.status.longitude 172 | ); 173 | 174 | let block = if self.selection == PanelSelection::StatusInformation { 175 | Block::bordered() 176 | .title("Statusinformation") 177 | .border_style(Color::Magenta) 178 | } else { 179 | Block::bordered().title("Statusinformation") 180 | }; 181 | 182 | frame.render_widget(Paragraph::new(content).block(block), area); 183 | } 184 | 185 | fn draw_speed_graph(&self, frame: &mut Frame, area: Rect) { 186 | let block = if self.selection == PanelSelection::SpeedInformation { 187 | Block::bordered() 188 | .title("Geschwindigkeitsverlauf") 189 | .border_style(Color::Magenta) 190 | } else { 191 | Block::bordered().title("Geschwindigkeitsverlauf") 192 | }; 193 | 194 | let canvas = Canvas::default() 195 | .block(block) 196 | .x_bounds([0.0, self.data.capacity() as f64]) 197 | .y_bounds([0.0, 300.0]) 198 | .paint(|ctx| { 199 | for (xc, (curr, next)) in self.data.iter().zip(self.data.iter().skip(1)).enumerate() 200 | { 201 | ctx.draw(&widgets::canvas::Line { 202 | x1: xc as f64, 203 | y1: curr.status.speed, 204 | x2: xc as f64 + 1.0, 205 | y2: next.status.speed, 206 | color: if curr.status.speed > next.status.speed { 207 | Color::Red 208 | } else { 209 | Color::Green 210 | }, 211 | }); 212 | } 213 | }); 214 | 215 | frame.render_widget(canvas, area); 216 | } 217 | 218 | fn draw_trip(&self, frame: &mut Frame, area: Rect) { 219 | let info = self.data.back().expect("Nothing to draw"); 220 | 221 | let lphk = 5; // lines per kilometers (TODO calculate appropriate value) 222 | 223 | let height = (area.height - 2) as usize; // subtract 2 for border 224 | 225 | let data_when: DateTime = 226 | DateTime::from_timestamp(info.status.serverTime as i64 / 1000, 0) 227 | .unwrap() 228 | .into(); 229 | let now = Local::now().time(); 230 | let diff = now - data_when.time(); 231 | 232 | let block = if self.selection == PanelSelection::TripInformation { 233 | Block::bordered() 234 | .title("Streckenverlauf") 235 | .border_style(Color::Magenta) 236 | .title_bottom(format!( 237 | "[Zuletzt aktualisiert: {} (vor {} Sekunden)]", 238 | data_when.format("%H:%M:%S"), 239 | diff.num_seconds() 240 | )) 241 | } else { 242 | Block::bordered() 243 | .title("Streckenverlauf") 244 | .title_bottom(format!( 245 | "[Zuletzt aktualisiert: {} (vor {} Sekunden)]", 246 | data_when.format("%H:%M:%S"), 247 | diff.num_seconds() 248 | )) 249 | }; 250 | 251 | let area_inside = Rect { 252 | x: area.x + 1, 253 | y: area.y + 1, 254 | width: area.width - 2, 255 | height: area.height - 2, 256 | }; 257 | 258 | let layout_constraints = info.trip.trip.stops.iter().map(|stop| { 259 | Constraint::Ratio( 260 | stop.info.distanceFromStart as u32, 261 | info.trip.trip.totalDistance as u32, 262 | ) 263 | }); 264 | let layouts = Layout::new(Direction::Vertical, layout_constraints).split(area_inside); 265 | 266 | // draw line (will get overwritten later on) (TODO) 267 | // for i in 0..area.height { 268 | // frame.render_widget(Paragraph::new(" |"), R); 269 | // } 270 | 271 | // draw stations 272 | for (i, stop) in info.trip.trip.stops.iter().enumerate() { 273 | let layout = layouts[i]; 274 | 275 | let text = if let Some(sat) = stop.timetable.scheduledArrivalTime { 276 | let time: DateTime = DateTime::from_timestamp(sat as i64 / 1000, 0) 277 | .unwrap() 278 | .into(); 279 | let now = Local::now().time(); 280 | let aat = stop 281 | .timetable 282 | .actualArrivalTime 283 | .expect("If there is a scheduled time there should also be an actual time"); 284 | let delay = (aat as i64 - sat as i64) / 1000 / 60; 285 | 286 | if delay == 0 { 287 | format!("{} ({})", stop.station.name.clone(), time.format("%H:%M")) 288 | } else { 289 | format!( 290 | "{} ({}; {}{})", 291 | stop.station.name.clone(), 292 | time.format("%H:%M"), 293 | if delay < 0 { "-" } else { "+" }, 294 | delay 295 | ) 296 | } 297 | } else { 298 | format!("{} (-)", stop.station.name.clone()) 299 | }; 300 | 301 | if self.selected_station_detailed && i == self.selected_station { 302 | // detailed information (delay reasons, track, coordinates, distance...) 303 | let track = format!( 304 | "Gleis {}{}", 305 | stop.track.actual, 306 | if stop.track.actual == stop.track.scheduled { 307 | String::from("") 308 | } else { 309 | format!("(urspr. {})", stop.track.scheduled) 310 | } 311 | ); 312 | 313 | let additional = format!("{}\n{}\n", text, track); 314 | frame.render_widget(Paragraph::new(additional), layout); 315 | } else { 316 | frame.render_widget(Paragraph::new(text), layout); 317 | } 318 | } 319 | 320 | let next_eva = &info.trip.trip.stopInfo.scheduledNext; 321 | let next_stop = info 322 | .trip 323 | .trip 324 | .stops 325 | .iter() 326 | .filter(|&stop| stop.station.evaNr == *next_eva) 327 | .collect::>(); 328 | assert_eq!(next_stop.len(), 1); 329 | 330 | frame.render_widget(Paragraph::new("").block(block), area); 331 | } 332 | 333 | fn ui(&self, frame: &mut Frame) { 334 | let layout = Layout::new( 335 | Direction::Vertical, 336 | [ 337 | Constraint::Length(6), 338 | Constraint::Length(10), 339 | Constraint::default(), 340 | ], 341 | ) 342 | .split(frame.size()); 343 | 344 | let layout_1 = Layout::new( 345 | Direction::Horizontal, 346 | [Constraint::Min(50), Constraint::default()], 347 | ) 348 | .split(layout[1]); 349 | 350 | self.draw_basic_info(frame, layout[0]); 351 | self.draw_status(frame, layout_1[0]); 352 | self.draw_speed_graph(frame, layout_1[1]); 353 | self.draw_trip(frame, layout[2]); 354 | } 355 | 356 | // update state (query API, move graphs, ...) 357 | fn tick(&mut self) { 358 | // let files = ApiPaths { 359 | // status: PathBuf::from("sample/status.json"), 360 | // trip: PathBuf::from("sample/trip.json"), 361 | // }; 362 | 363 | // let info = Info::from_file(&files).unwrap(); 364 | 365 | let endpoints = ApiEndpoints { 366 | status: String::from("https://iceportal.de/api1/rs/status"), 367 | trip: String::from("https://iceportal.de/api1/rs/tripInfo/trip"), 368 | }; 369 | 370 | let info = Info::query(&endpoints).unwrap(); 371 | 372 | if self.data.len() == self.data.capacity() { 373 | self.data.pop_front(); 374 | } 375 | 376 | self.data.push_back(info); 377 | } 378 | 379 | pub fn enter_loop(&mut self, tick_rate: Duration) -> io::Result { 380 | let mut last_tick = Instant::now(); 381 | let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?; 382 | self.tick(); // tick once to initialize 383 | 384 | loop { 385 | terminal.draw(|frame| self.ui(frame))?; 386 | 387 | let timeout = tick_rate.saturating_sub(last_tick.elapsed()); 388 | 389 | if event::poll(Duration::from_secs(1))? { 390 | if let Event::Key(key) = event::read()? { 391 | if key.kind == event::KeyEventKind::Press { 392 | match key.code { 393 | KeyCode::Char('q') => { 394 | return Ok(true); 395 | } 396 | KeyCode::Tab => { 397 | self.selection.next(); 398 | } 399 | KeyCode::BackTab => { 400 | self.selection.prev(); 401 | } 402 | KeyCode::Enter => { 403 | if self.selection == PanelSelection::TripInformation { 404 | self.selected_station_detailed = 405 | !self.selected_station_detailed; 406 | } 407 | } 408 | KeyCode::Char('k') => { 409 | if let Some(info) = self.data.back() { 410 | if self.selected_station_detailed { 411 | self.selected_station = (self.selected_station + 1) 412 | .min(info.trip.trip.stops.len() - 1); 413 | } 414 | } 415 | } 416 | KeyCode::Char('j') => { 417 | if let Some(info) = self.data.back() { 418 | if self.selected_station_detailed { 419 | self.selected_station = self 420 | .selected_station 421 | .checked_sub(1) 422 | .unwrap_or(self.selected_station); 423 | } 424 | } 425 | } 426 | _ => (), 427 | } 428 | } 429 | } 430 | } 431 | 432 | if last_tick.elapsed() >= tick_rate { 433 | last_tick = Instant::now(); 434 | self.tick(); 435 | } 436 | } 437 | } 438 | } 439 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::{error::Error, io::stdout, time::Duration}; 2 | 3 | use frontend::Frontend; 4 | use ratatui::crossterm::{ 5 | terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, 6 | ExecutableCommand, 7 | }; 8 | 9 | mod api; 10 | mod frontend; 11 | 12 | fn main() -> Result<(), Box> { 13 | // let endpoints = ApiEndpoints { 14 | // status: String::from("https://iceportal.de/api1/rs/status"), 15 | // trip: String::from("https://iceportal.de/api1/rs/tripInfo/trip"), 16 | // }; 17 | 18 | // let info = Info::query(&endpoints)?; 19 | 20 | let tick_rate = Duration::from_millis(5000); // update every 5 seconds 21 | 22 | enable_raw_mode()?; 23 | 24 | stdout().execute(EnterAlternateScreen)?; 25 | 26 | let mut frontend = Frontend::new(50)?; 27 | frontend.enter_loop(tick_rate)?; 28 | 29 | disable_raw_mode()?; 30 | stdout().execute(LeaveAlternateScreen)?; 31 | 32 | Ok(()) 33 | } 34 | --------------------------------------------------------------------------------