├── .github └── workflows │ └── ci.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md └── src ├── client.rs ├── config.rs ├── lib.rs ├── main.rs ├── network.rs ├── terminal.rs └── tui.rs /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: ["main"] 6 | pull_request: 7 | branches: ["main"] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v3 18 | 19 | # Cache dependencies to speed up subsequent builds 20 | - name: Cache Cargo dependencies 21 | uses: actions/cache@v4 22 | with: 23 | path: ~/.cargo 24 | key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} 25 | restore-keys: | 26 | ${{ runner.os }}-cargo- 27 | 28 | # Build the library 29 | - name: Build 30 | run: cargo build --verbose 31 | 32 | # Run tests 33 | - name: Run tests 34 | run: cargo test --verbose 35 | 36 | # Run static analysis with clippy 37 | - name: Run clippy 38 | run: cargo clippy --all -- -D warnings 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 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 = "anstream" 40 | version = "0.6.14" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" 43 | dependencies = [ 44 | "anstyle", 45 | "anstyle-parse", 46 | "anstyle-query", 47 | "anstyle-wincon", 48 | "colorchoice", 49 | "is_terminal_polyfill", 50 | "utf8parse", 51 | ] 52 | 53 | [[package]] 54 | name = "anstyle" 55 | version = "1.0.7" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" 58 | 59 | [[package]] 60 | name = "anstyle-parse" 61 | version = "0.2.4" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" 64 | dependencies = [ 65 | "utf8parse", 66 | ] 67 | 68 | [[package]] 69 | name = "anstyle-query" 70 | version = "1.1.0" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" 73 | dependencies = [ 74 | "windows-sys 0.52.0", 75 | ] 76 | 77 | [[package]] 78 | name = "anstyle-wincon" 79 | version = "3.0.3" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" 82 | dependencies = [ 83 | "anstyle", 84 | "windows-sys 0.52.0", 85 | ] 86 | 87 | [[package]] 88 | name = "atomic-waker" 89 | version = "1.1.2" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 92 | 93 | [[package]] 94 | name = "autocfg" 95 | version = "1.3.0" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" 98 | 99 | [[package]] 100 | name = "backtrace" 101 | version = "0.3.73" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" 104 | dependencies = [ 105 | "addr2line", 106 | "cc", 107 | "cfg-if", 108 | "libc", 109 | "miniz_oxide", 110 | "object", 111 | "rustc-demangle", 112 | ] 113 | 114 | [[package]] 115 | name = "base64" 116 | version = "0.21.7" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" 119 | 120 | [[package]] 121 | name = "base64" 122 | version = "0.22.1" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 125 | 126 | [[package]] 127 | name = "bitflags" 128 | version = "1.3.2" 129 | source = "registry+https://github.com/rust-lang/crates.io-index" 130 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 131 | 132 | [[package]] 133 | name = "bitflags" 134 | version = "2.6.0" 135 | source = "registry+https://github.com/rust-lang/crates.io-index" 136 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 137 | 138 | [[package]] 139 | name = "bumpalo" 140 | version = "3.16.0" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 143 | 144 | [[package]] 145 | name = "bytes" 146 | version = "1.6.0" 147 | source = "registry+https://github.com/rust-lang/crates.io-index" 148 | checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" 149 | 150 | [[package]] 151 | name = "cassowary" 152 | version = "0.3.0" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" 155 | 156 | [[package]] 157 | name = "castaway" 158 | version = "0.2.3" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5" 161 | dependencies = [ 162 | "rustversion", 163 | ] 164 | 165 | [[package]] 166 | name = "cc" 167 | version = "1.2.16" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" 170 | dependencies = [ 171 | "shlex", 172 | ] 173 | 174 | [[package]] 175 | name = "cfg-if" 176 | version = "1.0.0" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 179 | 180 | [[package]] 181 | name = "clap" 182 | version = "4.5.9" 183 | source = "registry+https://github.com/rust-lang/crates.io-index" 184 | checksum = "64acc1846d54c1fe936a78dc189c34e28d3f5afc348403f28ecf53660b9b8462" 185 | dependencies = [ 186 | "clap_builder", 187 | "clap_derive", 188 | ] 189 | 190 | [[package]] 191 | name = "clap_builder" 192 | version = "4.5.9" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942" 195 | dependencies = [ 196 | "anstream", 197 | "anstyle", 198 | "clap_lex", 199 | "strsim", 200 | ] 201 | 202 | [[package]] 203 | name = "clap_derive" 204 | version = "4.5.8" 205 | source = "registry+https://github.com/rust-lang/crates.io-index" 206 | checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" 207 | dependencies = [ 208 | "heck", 209 | "proc-macro2", 210 | "quote", 211 | "syn", 212 | ] 213 | 214 | [[package]] 215 | name = "clap_lex" 216 | version = "0.7.1" 217 | source = "registry+https://github.com/rust-lang/crates.io-index" 218 | checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" 219 | 220 | [[package]] 221 | name = "colorchoice" 222 | version = "1.0.1" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" 225 | 226 | [[package]] 227 | name = "compact_str" 228 | version = "0.7.1" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f" 231 | dependencies = [ 232 | "castaway", 233 | "cfg-if", 234 | "itoa", 235 | "ryu", 236 | "static_assertions", 237 | ] 238 | 239 | [[package]] 240 | name = "core-foundation" 241 | version = "0.9.4" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 244 | dependencies = [ 245 | "core-foundation-sys", 246 | "libc", 247 | ] 248 | 249 | [[package]] 250 | name = "core-foundation-sys" 251 | version = "0.8.6" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" 254 | 255 | [[package]] 256 | name = "crossterm" 257 | version = "0.27.0" 258 | source = "registry+https://github.com/rust-lang/crates.io-index" 259 | checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" 260 | dependencies = [ 261 | "bitflags 2.6.0", 262 | "crossterm_winapi", 263 | "libc", 264 | "mio", 265 | "parking_lot", 266 | "signal-hook", 267 | "signal-hook-mio", 268 | "winapi", 269 | ] 270 | 271 | [[package]] 272 | name = "crossterm_winapi" 273 | version = "0.9.1" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" 276 | dependencies = [ 277 | "winapi", 278 | ] 279 | 280 | [[package]] 281 | name = "either" 282 | version = "1.13.0" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 285 | 286 | [[package]] 287 | name = "encoding_rs" 288 | version = "0.8.34" 289 | source = "registry+https://github.com/rust-lang/crates.io-index" 290 | checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" 291 | dependencies = [ 292 | "cfg-if", 293 | ] 294 | 295 | [[package]] 296 | name = "equivalent" 297 | version = "1.0.1" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 300 | 301 | [[package]] 302 | name = "errno" 303 | version = "0.3.9" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" 306 | dependencies = [ 307 | "libc", 308 | "windows-sys 0.52.0", 309 | ] 310 | 311 | [[package]] 312 | name = "eventsource-client" 313 | version = "0.12.2" 314 | source = "registry+https://github.com/rust-lang/crates.io-index" 315 | checksum = "4c80c6714d1a380314fcb11a22eeff022e1e1c9642f0bb54e15dc9cb29f37b29" 316 | dependencies = [ 317 | "futures", 318 | "hyper 0.14.30", 319 | "hyper-rustls 0.24.2", 320 | "hyper-timeout", 321 | "log", 322 | "pin-project", 323 | "rand", 324 | "tokio", 325 | ] 326 | 327 | [[package]] 328 | name = "fastrand" 329 | version = "2.1.0" 330 | source = "registry+https://github.com/rust-lang/crates.io-index" 331 | checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" 332 | 333 | [[package]] 334 | name = "fnv" 335 | version = "1.0.7" 336 | source = "registry+https://github.com/rust-lang/crates.io-index" 337 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 338 | 339 | [[package]] 340 | name = "foreign-types" 341 | version = "0.3.2" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 344 | dependencies = [ 345 | "foreign-types-shared", 346 | ] 347 | 348 | [[package]] 349 | name = "foreign-types-shared" 350 | version = "0.1.1" 351 | source = "registry+https://github.com/rust-lang/crates.io-index" 352 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 353 | 354 | [[package]] 355 | name = "form_urlencoded" 356 | version = "1.2.1" 357 | source = "registry+https://github.com/rust-lang/crates.io-index" 358 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 359 | dependencies = [ 360 | "percent-encoding", 361 | ] 362 | 363 | [[package]] 364 | name = "futures" 365 | version = "0.3.30" 366 | source = "registry+https://github.com/rust-lang/crates.io-index" 367 | checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" 368 | dependencies = [ 369 | "futures-channel", 370 | "futures-core", 371 | "futures-executor", 372 | "futures-io", 373 | "futures-sink", 374 | "futures-task", 375 | "futures-util", 376 | ] 377 | 378 | [[package]] 379 | name = "futures-channel" 380 | version = "0.3.30" 381 | source = "registry+https://github.com/rust-lang/crates.io-index" 382 | checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" 383 | dependencies = [ 384 | "futures-core", 385 | "futures-sink", 386 | ] 387 | 388 | [[package]] 389 | name = "futures-core" 390 | version = "0.3.30" 391 | source = "registry+https://github.com/rust-lang/crates.io-index" 392 | checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" 393 | 394 | [[package]] 395 | name = "futures-executor" 396 | version = "0.3.30" 397 | source = "registry+https://github.com/rust-lang/crates.io-index" 398 | checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" 399 | dependencies = [ 400 | "futures-core", 401 | "futures-task", 402 | "futures-util", 403 | ] 404 | 405 | [[package]] 406 | name = "futures-io" 407 | version = "0.3.30" 408 | source = "registry+https://github.com/rust-lang/crates.io-index" 409 | checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" 410 | 411 | [[package]] 412 | name = "futures-macro" 413 | version = "0.3.30" 414 | source = "registry+https://github.com/rust-lang/crates.io-index" 415 | checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" 416 | dependencies = [ 417 | "proc-macro2", 418 | "quote", 419 | "syn", 420 | ] 421 | 422 | [[package]] 423 | name = "futures-sink" 424 | version = "0.3.30" 425 | source = "registry+https://github.com/rust-lang/crates.io-index" 426 | checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" 427 | 428 | [[package]] 429 | name = "futures-task" 430 | version = "0.3.30" 431 | source = "registry+https://github.com/rust-lang/crates.io-index" 432 | checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" 433 | 434 | [[package]] 435 | name = "futures-util" 436 | version = "0.3.30" 437 | source = "registry+https://github.com/rust-lang/crates.io-index" 438 | checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" 439 | dependencies = [ 440 | "futures-channel", 441 | "futures-core", 442 | "futures-io", 443 | "futures-macro", 444 | "futures-sink", 445 | "futures-task", 446 | "memchr", 447 | "pin-project-lite", 448 | "pin-utils", 449 | "slab", 450 | ] 451 | 452 | [[package]] 453 | name = "getrandom" 454 | version = "0.2.15" 455 | source = "registry+https://github.com/rust-lang/crates.io-index" 456 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 457 | dependencies = [ 458 | "cfg-if", 459 | "libc", 460 | "wasi", 461 | ] 462 | 463 | [[package]] 464 | name = "gimli" 465 | version = "0.29.0" 466 | source = "registry+https://github.com/rust-lang/crates.io-index" 467 | checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" 468 | 469 | [[package]] 470 | name = "h2" 471 | version = "0.3.26" 472 | source = "registry+https://github.com/rust-lang/crates.io-index" 473 | checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" 474 | dependencies = [ 475 | "bytes", 476 | "fnv", 477 | "futures-core", 478 | "futures-sink", 479 | "futures-util", 480 | "http 0.2.12", 481 | "indexmap", 482 | "slab", 483 | "tokio", 484 | "tokio-util", 485 | "tracing", 486 | ] 487 | 488 | [[package]] 489 | name = "h2" 490 | version = "0.4.5" 491 | source = "registry+https://github.com/rust-lang/crates.io-index" 492 | checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" 493 | dependencies = [ 494 | "atomic-waker", 495 | "bytes", 496 | "fnv", 497 | "futures-core", 498 | "futures-sink", 499 | "http 1.1.0", 500 | "indexmap", 501 | "slab", 502 | "tokio", 503 | "tokio-util", 504 | "tracing", 505 | ] 506 | 507 | [[package]] 508 | name = "hashbrown" 509 | version = "0.14.5" 510 | source = "registry+https://github.com/rust-lang/crates.io-index" 511 | checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 512 | dependencies = [ 513 | "ahash", 514 | "allocator-api2", 515 | ] 516 | 517 | [[package]] 518 | name = "heck" 519 | version = "0.5.0" 520 | source = "registry+https://github.com/rust-lang/crates.io-index" 521 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 522 | 523 | [[package]] 524 | name = "http" 525 | version = "0.2.12" 526 | source = "registry+https://github.com/rust-lang/crates.io-index" 527 | checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" 528 | dependencies = [ 529 | "bytes", 530 | "fnv", 531 | "itoa", 532 | ] 533 | 534 | [[package]] 535 | name = "http" 536 | version = "1.1.0" 537 | source = "registry+https://github.com/rust-lang/crates.io-index" 538 | checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" 539 | dependencies = [ 540 | "bytes", 541 | "fnv", 542 | "itoa", 543 | ] 544 | 545 | [[package]] 546 | name = "http-body" 547 | version = "0.4.6" 548 | source = "registry+https://github.com/rust-lang/crates.io-index" 549 | checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" 550 | dependencies = [ 551 | "bytes", 552 | "http 0.2.12", 553 | "pin-project-lite", 554 | ] 555 | 556 | [[package]] 557 | name = "http-body" 558 | version = "1.0.0" 559 | source = "registry+https://github.com/rust-lang/crates.io-index" 560 | checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" 561 | dependencies = [ 562 | "bytes", 563 | "http 1.1.0", 564 | ] 565 | 566 | [[package]] 567 | name = "http-body-util" 568 | version = "0.1.2" 569 | source = "registry+https://github.com/rust-lang/crates.io-index" 570 | checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" 571 | dependencies = [ 572 | "bytes", 573 | "futures-util", 574 | "http 1.1.0", 575 | "http-body 1.0.0", 576 | "pin-project-lite", 577 | ] 578 | 579 | [[package]] 580 | name = "httparse" 581 | version = "1.9.4" 582 | source = "registry+https://github.com/rust-lang/crates.io-index" 583 | checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" 584 | 585 | [[package]] 586 | name = "httpdate" 587 | version = "1.0.3" 588 | source = "registry+https://github.com/rust-lang/crates.io-index" 589 | checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" 590 | 591 | [[package]] 592 | name = "hyper" 593 | version = "0.14.30" 594 | source = "registry+https://github.com/rust-lang/crates.io-index" 595 | checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" 596 | dependencies = [ 597 | "bytes", 598 | "futures-channel", 599 | "futures-core", 600 | "futures-util", 601 | "h2 0.3.26", 602 | "http 0.2.12", 603 | "http-body 0.4.6", 604 | "httparse", 605 | "httpdate", 606 | "itoa", 607 | "pin-project-lite", 608 | "socket2", 609 | "tokio", 610 | "tower-service", 611 | "tracing", 612 | "want", 613 | ] 614 | 615 | [[package]] 616 | name = "hyper" 617 | version = "1.4.1" 618 | source = "registry+https://github.com/rust-lang/crates.io-index" 619 | checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" 620 | dependencies = [ 621 | "bytes", 622 | "futures-channel", 623 | "futures-util", 624 | "h2 0.4.5", 625 | "http 1.1.0", 626 | "http-body 1.0.0", 627 | "httparse", 628 | "itoa", 629 | "pin-project-lite", 630 | "smallvec", 631 | "tokio", 632 | "want", 633 | ] 634 | 635 | [[package]] 636 | name = "hyper-rustls" 637 | version = "0.24.2" 638 | source = "registry+https://github.com/rust-lang/crates.io-index" 639 | checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" 640 | dependencies = [ 641 | "futures-util", 642 | "http 0.2.12", 643 | "hyper 0.14.30", 644 | "log", 645 | "rustls 0.21.12", 646 | "rustls-native-certs", 647 | "tokio", 648 | "tokio-rustls 0.24.1", 649 | ] 650 | 651 | [[package]] 652 | name = "hyper-rustls" 653 | version = "0.27.2" 654 | source = "registry+https://github.com/rust-lang/crates.io-index" 655 | checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" 656 | dependencies = [ 657 | "futures-util", 658 | "http 1.1.0", 659 | "hyper 1.4.1", 660 | "hyper-util", 661 | "rustls 0.23.11", 662 | "rustls-pki-types", 663 | "tokio", 664 | "tokio-rustls 0.26.0", 665 | "tower-service", 666 | ] 667 | 668 | [[package]] 669 | name = "hyper-timeout" 670 | version = "0.4.1" 671 | source = "registry+https://github.com/rust-lang/crates.io-index" 672 | checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" 673 | dependencies = [ 674 | "hyper 0.14.30", 675 | "pin-project-lite", 676 | "tokio", 677 | "tokio-io-timeout", 678 | ] 679 | 680 | [[package]] 681 | name = "hyper-tls" 682 | version = "0.6.0" 683 | source = "registry+https://github.com/rust-lang/crates.io-index" 684 | checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" 685 | dependencies = [ 686 | "bytes", 687 | "http-body-util", 688 | "hyper 1.4.1", 689 | "hyper-util", 690 | "native-tls", 691 | "tokio", 692 | "tokio-native-tls", 693 | "tower-service", 694 | ] 695 | 696 | [[package]] 697 | name = "hyper-util" 698 | version = "0.1.6" 699 | source = "registry+https://github.com/rust-lang/crates.io-index" 700 | checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" 701 | dependencies = [ 702 | "bytes", 703 | "futures-channel", 704 | "futures-util", 705 | "http 1.1.0", 706 | "http-body 1.0.0", 707 | "hyper 1.4.1", 708 | "pin-project-lite", 709 | "socket2", 710 | "tokio", 711 | "tower", 712 | "tower-service", 713 | "tracing", 714 | ] 715 | 716 | [[package]] 717 | name = "idna" 718 | version = "0.5.0" 719 | source = "registry+https://github.com/rust-lang/crates.io-index" 720 | checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" 721 | dependencies = [ 722 | "unicode-bidi", 723 | "unicode-normalization", 724 | ] 725 | 726 | [[package]] 727 | name = "indexmap" 728 | version = "2.2.6" 729 | source = "registry+https://github.com/rust-lang/crates.io-index" 730 | checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" 731 | dependencies = [ 732 | "equivalent", 733 | "hashbrown", 734 | ] 735 | 736 | [[package]] 737 | name = "ipnet" 738 | version = "2.9.0" 739 | source = "registry+https://github.com/rust-lang/crates.io-index" 740 | checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" 741 | 742 | [[package]] 743 | name = "is_terminal_polyfill" 744 | version = "1.70.0" 745 | source = "registry+https://github.com/rust-lang/crates.io-index" 746 | checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" 747 | 748 | [[package]] 749 | name = "itertools" 750 | version = "0.12.1" 751 | source = "registry+https://github.com/rust-lang/crates.io-index" 752 | checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" 753 | dependencies = [ 754 | "either", 755 | ] 756 | 757 | [[package]] 758 | name = "itertools" 759 | version = "0.13.0" 760 | source = "registry+https://github.com/rust-lang/crates.io-index" 761 | checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" 762 | dependencies = [ 763 | "either", 764 | ] 765 | 766 | [[package]] 767 | name = "itoa" 768 | version = "1.0.11" 769 | source = "registry+https://github.com/rust-lang/crates.io-index" 770 | checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" 771 | 772 | [[package]] 773 | name = "js-sys" 774 | version = "0.3.69" 775 | source = "registry+https://github.com/rust-lang/crates.io-index" 776 | checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" 777 | dependencies = [ 778 | "wasm-bindgen", 779 | ] 780 | 781 | [[package]] 782 | name = "libc" 783 | version = "0.2.155" 784 | source = "registry+https://github.com/rust-lang/crates.io-index" 785 | checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" 786 | 787 | [[package]] 788 | name = "linux-raw-sys" 789 | version = "0.4.14" 790 | source = "registry+https://github.com/rust-lang/crates.io-index" 791 | checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" 792 | 793 | [[package]] 794 | name = "lock_api" 795 | version = "0.4.12" 796 | source = "registry+https://github.com/rust-lang/crates.io-index" 797 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 798 | dependencies = [ 799 | "autocfg", 800 | "scopeguard", 801 | ] 802 | 803 | [[package]] 804 | name = "log" 805 | version = "0.4.22" 806 | source = "registry+https://github.com/rust-lang/crates.io-index" 807 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 808 | 809 | [[package]] 810 | name = "lru" 811 | version = "0.12.3" 812 | source = "registry+https://github.com/rust-lang/crates.io-index" 813 | checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" 814 | dependencies = [ 815 | "hashbrown", 816 | ] 817 | 818 | [[package]] 819 | name = "memchr" 820 | version = "2.7.4" 821 | source = "registry+https://github.com/rust-lang/crates.io-index" 822 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 823 | 824 | [[package]] 825 | name = "mime" 826 | version = "0.3.17" 827 | source = "registry+https://github.com/rust-lang/crates.io-index" 828 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 829 | 830 | [[package]] 831 | name = "miniz_oxide" 832 | version = "0.7.4" 833 | source = "registry+https://github.com/rust-lang/crates.io-index" 834 | checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" 835 | dependencies = [ 836 | "adler", 837 | ] 838 | 839 | [[package]] 840 | name = "mio" 841 | version = "0.8.11" 842 | source = "registry+https://github.com/rust-lang/crates.io-index" 843 | checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" 844 | dependencies = [ 845 | "libc", 846 | "log", 847 | "wasi", 848 | "windows-sys 0.48.0", 849 | ] 850 | 851 | [[package]] 852 | name = "native-tls" 853 | version = "0.2.12" 854 | source = "registry+https://github.com/rust-lang/crates.io-index" 855 | checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" 856 | dependencies = [ 857 | "libc", 858 | "log", 859 | "openssl", 860 | "openssl-probe", 861 | "openssl-sys", 862 | "schannel", 863 | "security-framework", 864 | "security-framework-sys", 865 | "tempfile", 866 | ] 867 | 868 | [[package]] 869 | name = "object" 870 | version = "0.36.1" 871 | source = "registry+https://github.com/rust-lang/crates.io-index" 872 | checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" 873 | dependencies = [ 874 | "memchr", 875 | ] 876 | 877 | [[package]] 878 | name = "once_cell" 879 | version = "1.19.0" 880 | source = "registry+https://github.com/rust-lang/crates.io-index" 881 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 882 | 883 | [[package]] 884 | name = "openssl" 885 | version = "0.10.72" 886 | source = "registry+https://github.com/rust-lang/crates.io-index" 887 | checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" 888 | dependencies = [ 889 | "bitflags 2.6.0", 890 | "cfg-if", 891 | "foreign-types", 892 | "libc", 893 | "once_cell", 894 | "openssl-macros", 895 | "openssl-sys", 896 | ] 897 | 898 | [[package]] 899 | name = "openssl-macros" 900 | version = "0.1.1" 901 | source = "registry+https://github.com/rust-lang/crates.io-index" 902 | checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" 903 | dependencies = [ 904 | "proc-macro2", 905 | "quote", 906 | "syn", 907 | ] 908 | 909 | [[package]] 910 | name = "openssl-probe" 911 | version = "0.1.5" 912 | source = "registry+https://github.com/rust-lang/crates.io-index" 913 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 914 | 915 | [[package]] 916 | name = "openssl-sys" 917 | version = "0.9.107" 918 | source = "registry+https://github.com/rust-lang/crates.io-index" 919 | checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07" 920 | dependencies = [ 921 | "cc", 922 | "libc", 923 | "pkg-config", 924 | "vcpkg", 925 | ] 926 | 927 | [[package]] 928 | name = "parking_lot" 929 | version = "0.12.3" 930 | source = "registry+https://github.com/rust-lang/crates.io-index" 931 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 932 | dependencies = [ 933 | "lock_api", 934 | "parking_lot_core", 935 | ] 936 | 937 | [[package]] 938 | name = "parking_lot_core" 939 | version = "0.9.10" 940 | source = "registry+https://github.com/rust-lang/crates.io-index" 941 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 942 | dependencies = [ 943 | "cfg-if", 944 | "libc", 945 | "redox_syscall", 946 | "smallvec", 947 | "windows-targets 0.52.6", 948 | ] 949 | 950 | [[package]] 951 | name = "paste" 952 | version = "1.0.15" 953 | source = "registry+https://github.com/rust-lang/crates.io-index" 954 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 955 | 956 | [[package]] 957 | name = "percent-encoding" 958 | version = "2.3.1" 959 | source = "registry+https://github.com/rust-lang/crates.io-index" 960 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 961 | 962 | [[package]] 963 | name = "pin-project" 964 | version = "1.1.5" 965 | source = "registry+https://github.com/rust-lang/crates.io-index" 966 | checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" 967 | dependencies = [ 968 | "pin-project-internal", 969 | ] 970 | 971 | [[package]] 972 | name = "pin-project-internal" 973 | version = "1.1.5" 974 | source = "registry+https://github.com/rust-lang/crates.io-index" 975 | checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" 976 | dependencies = [ 977 | "proc-macro2", 978 | "quote", 979 | "syn", 980 | ] 981 | 982 | [[package]] 983 | name = "pin-project-lite" 984 | version = "0.2.14" 985 | source = "registry+https://github.com/rust-lang/crates.io-index" 986 | checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" 987 | 988 | [[package]] 989 | name = "pin-utils" 990 | version = "0.1.0" 991 | source = "registry+https://github.com/rust-lang/crates.io-index" 992 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 993 | 994 | [[package]] 995 | name = "pkg-config" 996 | version = "0.3.30" 997 | source = "registry+https://github.com/rust-lang/crates.io-index" 998 | checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" 999 | 1000 | [[package]] 1001 | name = "ppv-lite86" 1002 | version = "0.2.17" 1003 | source = "registry+https://github.com/rust-lang/crates.io-index" 1004 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 1005 | 1006 | [[package]] 1007 | name = "proc-macro2" 1008 | version = "1.0.86" 1009 | source = "registry+https://github.com/rust-lang/crates.io-index" 1010 | checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" 1011 | dependencies = [ 1012 | "unicode-ident", 1013 | ] 1014 | 1015 | [[package]] 1016 | name = "quote" 1017 | version = "1.0.36" 1018 | source = "registry+https://github.com/rust-lang/crates.io-index" 1019 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" 1020 | dependencies = [ 1021 | "proc-macro2", 1022 | ] 1023 | 1024 | [[package]] 1025 | name = "rand" 1026 | version = "0.8.5" 1027 | source = "registry+https://github.com/rust-lang/crates.io-index" 1028 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1029 | dependencies = [ 1030 | "libc", 1031 | "rand_chacha", 1032 | "rand_core", 1033 | ] 1034 | 1035 | [[package]] 1036 | name = "rand_chacha" 1037 | version = "0.3.1" 1038 | source = "registry+https://github.com/rust-lang/crates.io-index" 1039 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1040 | dependencies = [ 1041 | "ppv-lite86", 1042 | "rand_core", 1043 | ] 1044 | 1045 | [[package]] 1046 | name = "rand_core" 1047 | version = "0.6.4" 1048 | source = "registry+https://github.com/rust-lang/crates.io-index" 1049 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1050 | dependencies = [ 1051 | "getrandom", 1052 | ] 1053 | 1054 | [[package]] 1055 | name = "ratatui" 1056 | version = "0.26.3" 1057 | source = "registry+https://github.com/rust-lang/crates.io-index" 1058 | checksum = "f44c9e68fd46eda15c646fbb85e1040b657a58cdc8c98db1d97a55930d991eef" 1059 | dependencies = [ 1060 | "bitflags 2.6.0", 1061 | "cassowary", 1062 | "compact_str", 1063 | "crossterm", 1064 | "itertools 0.12.1", 1065 | "lru", 1066 | "paste", 1067 | "stability", 1068 | "strum", 1069 | "unicode-segmentation", 1070 | "unicode-truncate", 1071 | "unicode-width", 1072 | ] 1073 | 1074 | [[package]] 1075 | name = "redox_syscall" 1076 | version = "0.5.2" 1077 | source = "registry+https://github.com/rust-lang/crates.io-index" 1078 | checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" 1079 | dependencies = [ 1080 | "bitflags 2.6.0", 1081 | ] 1082 | 1083 | [[package]] 1084 | name = "reqwest" 1085 | version = "0.12.5" 1086 | source = "registry+https://github.com/rust-lang/crates.io-index" 1087 | checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" 1088 | dependencies = [ 1089 | "base64 0.22.1", 1090 | "bytes", 1091 | "encoding_rs", 1092 | "futures-core", 1093 | "futures-util", 1094 | "h2 0.4.5", 1095 | "http 1.1.0", 1096 | "http-body 1.0.0", 1097 | "http-body-util", 1098 | "hyper 1.4.1", 1099 | "hyper-rustls 0.27.2", 1100 | "hyper-tls", 1101 | "hyper-util", 1102 | "ipnet", 1103 | "js-sys", 1104 | "log", 1105 | "mime", 1106 | "native-tls", 1107 | "once_cell", 1108 | "percent-encoding", 1109 | "pin-project-lite", 1110 | "rustls-pemfile 2.1.2", 1111 | "serde", 1112 | "serde_json", 1113 | "serde_urlencoded", 1114 | "sync_wrapper", 1115 | "system-configuration", 1116 | "tokio", 1117 | "tokio-native-tls", 1118 | "tower-service", 1119 | "url", 1120 | "wasm-bindgen", 1121 | "wasm-bindgen-futures", 1122 | "web-sys", 1123 | "winreg", 1124 | ] 1125 | 1126 | [[package]] 1127 | name = "ring" 1128 | version = "0.17.13" 1129 | source = "registry+https://github.com/rust-lang/crates.io-index" 1130 | checksum = "70ac5d832aa16abd7d1def883a8545280c20a60f523a370aa3a9617c2b8550ee" 1131 | dependencies = [ 1132 | "cc", 1133 | "cfg-if", 1134 | "getrandom", 1135 | "libc", 1136 | "untrusted", 1137 | "windows-sys 0.52.0", 1138 | ] 1139 | 1140 | [[package]] 1141 | name = "roller" 1142 | version = "0.1.1" 1143 | dependencies = [ 1144 | "clap", 1145 | "crossterm", 1146 | "eventsource-client", 1147 | "futures", 1148 | "ratatui", 1149 | "reqwest", 1150 | "serde", 1151 | "serde_json", 1152 | "tokio", 1153 | ] 1154 | 1155 | [[package]] 1156 | name = "rustc-demangle" 1157 | version = "0.1.24" 1158 | source = "registry+https://github.com/rust-lang/crates.io-index" 1159 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 1160 | 1161 | [[package]] 1162 | name = "rustix" 1163 | version = "0.38.34" 1164 | source = "registry+https://github.com/rust-lang/crates.io-index" 1165 | checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" 1166 | dependencies = [ 1167 | "bitflags 2.6.0", 1168 | "errno", 1169 | "libc", 1170 | "linux-raw-sys", 1171 | "windows-sys 0.52.0", 1172 | ] 1173 | 1174 | [[package]] 1175 | name = "rustls" 1176 | version = "0.21.12" 1177 | source = "registry+https://github.com/rust-lang/crates.io-index" 1178 | checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" 1179 | dependencies = [ 1180 | "log", 1181 | "ring", 1182 | "rustls-webpki 0.101.7", 1183 | "sct", 1184 | ] 1185 | 1186 | [[package]] 1187 | name = "rustls" 1188 | version = "0.23.11" 1189 | source = "registry+https://github.com/rust-lang/crates.io-index" 1190 | checksum = "4828ea528154ae444e5a642dbb7d5623354030dc9822b83fd9bb79683c7399d0" 1191 | dependencies = [ 1192 | "once_cell", 1193 | "rustls-pki-types", 1194 | "rustls-webpki 0.102.5", 1195 | "subtle", 1196 | "zeroize", 1197 | ] 1198 | 1199 | [[package]] 1200 | name = "rustls-native-certs" 1201 | version = "0.6.3" 1202 | source = "registry+https://github.com/rust-lang/crates.io-index" 1203 | checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" 1204 | dependencies = [ 1205 | "openssl-probe", 1206 | "rustls-pemfile 1.0.4", 1207 | "schannel", 1208 | "security-framework", 1209 | ] 1210 | 1211 | [[package]] 1212 | name = "rustls-pemfile" 1213 | version = "1.0.4" 1214 | source = "registry+https://github.com/rust-lang/crates.io-index" 1215 | checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" 1216 | dependencies = [ 1217 | "base64 0.21.7", 1218 | ] 1219 | 1220 | [[package]] 1221 | name = "rustls-pemfile" 1222 | version = "2.1.2" 1223 | source = "registry+https://github.com/rust-lang/crates.io-index" 1224 | checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" 1225 | dependencies = [ 1226 | "base64 0.22.1", 1227 | "rustls-pki-types", 1228 | ] 1229 | 1230 | [[package]] 1231 | name = "rustls-pki-types" 1232 | version = "1.7.0" 1233 | source = "registry+https://github.com/rust-lang/crates.io-index" 1234 | checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" 1235 | 1236 | [[package]] 1237 | name = "rustls-webpki" 1238 | version = "0.101.7" 1239 | source = "registry+https://github.com/rust-lang/crates.io-index" 1240 | checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" 1241 | dependencies = [ 1242 | "ring", 1243 | "untrusted", 1244 | ] 1245 | 1246 | [[package]] 1247 | name = "rustls-webpki" 1248 | version = "0.102.5" 1249 | source = "registry+https://github.com/rust-lang/crates.io-index" 1250 | checksum = "f9a6fccd794a42c2c105b513a2f62bc3fd8f3ba57a4593677ceb0bd035164d78" 1251 | dependencies = [ 1252 | "ring", 1253 | "rustls-pki-types", 1254 | "untrusted", 1255 | ] 1256 | 1257 | [[package]] 1258 | name = "rustversion" 1259 | version = "1.0.17" 1260 | source = "registry+https://github.com/rust-lang/crates.io-index" 1261 | checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" 1262 | 1263 | [[package]] 1264 | name = "ryu" 1265 | version = "1.0.18" 1266 | source = "registry+https://github.com/rust-lang/crates.io-index" 1267 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 1268 | 1269 | [[package]] 1270 | name = "schannel" 1271 | version = "0.1.23" 1272 | source = "registry+https://github.com/rust-lang/crates.io-index" 1273 | checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" 1274 | dependencies = [ 1275 | "windows-sys 0.52.0", 1276 | ] 1277 | 1278 | [[package]] 1279 | name = "scopeguard" 1280 | version = "1.2.0" 1281 | source = "registry+https://github.com/rust-lang/crates.io-index" 1282 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1283 | 1284 | [[package]] 1285 | name = "sct" 1286 | version = "0.7.1" 1287 | source = "registry+https://github.com/rust-lang/crates.io-index" 1288 | checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" 1289 | dependencies = [ 1290 | "ring", 1291 | "untrusted", 1292 | ] 1293 | 1294 | [[package]] 1295 | name = "security-framework" 1296 | version = "2.11.0" 1297 | source = "registry+https://github.com/rust-lang/crates.io-index" 1298 | checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" 1299 | dependencies = [ 1300 | "bitflags 2.6.0", 1301 | "core-foundation", 1302 | "core-foundation-sys", 1303 | "libc", 1304 | "security-framework-sys", 1305 | ] 1306 | 1307 | [[package]] 1308 | name = "security-framework-sys" 1309 | version = "2.11.0" 1310 | source = "registry+https://github.com/rust-lang/crates.io-index" 1311 | checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" 1312 | dependencies = [ 1313 | "core-foundation-sys", 1314 | "libc", 1315 | ] 1316 | 1317 | [[package]] 1318 | name = "serde" 1319 | version = "1.0.204" 1320 | source = "registry+https://github.com/rust-lang/crates.io-index" 1321 | checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" 1322 | dependencies = [ 1323 | "serde_derive", 1324 | ] 1325 | 1326 | [[package]] 1327 | name = "serde_derive" 1328 | version = "1.0.204" 1329 | source = "registry+https://github.com/rust-lang/crates.io-index" 1330 | checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" 1331 | dependencies = [ 1332 | "proc-macro2", 1333 | "quote", 1334 | "syn", 1335 | ] 1336 | 1337 | [[package]] 1338 | name = "serde_json" 1339 | version = "1.0.120" 1340 | source = "registry+https://github.com/rust-lang/crates.io-index" 1341 | checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" 1342 | dependencies = [ 1343 | "itoa", 1344 | "ryu", 1345 | "serde", 1346 | ] 1347 | 1348 | [[package]] 1349 | name = "serde_urlencoded" 1350 | version = "0.7.1" 1351 | source = "registry+https://github.com/rust-lang/crates.io-index" 1352 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1353 | dependencies = [ 1354 | "form_urlencoded", 1355 | "itoa", 1356 | "ryu", 1357 | "serde", 1358 | ] 1359 | 1360 | [[package]] 1361 | name = "shlex" 1362 | version = "1.3.0" 1363 | source = "registry+https://github.com/rust-lang/crates.io-index" 1364 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1365 | 1366 | [[package]] 1367 | name = "signal-hook" 1368 | version = "0.3.17" 1369 | source = "registry+https://github.com/rust-lang/crates.io-index" 1370 | checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" 1371 | dependencies = [ 1372 | "libc", 1373 | "signal-hook-registry", 1374 | ] 1375 | 1376 | [[package]] 1377 | name = "signal-hook-mio" 1378 | version = "0.2.3" 1379 | source = "registry+https://github.com/rust-lang/crates.io-index" 1380 | checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" 1381 | dependencies = [ 1382 | "libc", 1383 | "mio", 1384 | "signal-hook", 1385 | ] 1386 | 1387 | [[package]] 1388 | name = "signal-hook-registry" 1389 | version = "1.4.2" 1390 | source = "registry+https://github.com/rust-lang/crates.io-index" 1391 | checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" 1392 | dependencies = [ 1393 | "libc", 1394 | ] 1395 | 1396 | [[package]] 1397 | name = "slab" 1398 | version = "0.4.9" 1399 | source = "registry+https://github.com/rust-lang/crates.io-index" 1400 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 1401 | dependencies = [ 1402 | "autocfg", 1403 | ] 1404 | 1405 | [[package]] 1406 | name = "smallvec" 1407 | version = "1.13.2" 1408 | source = "registry+https://github.com/rust-lang/crates.io-index" 1409 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 1410 | 1411 | [[package]] 1412 | name = "socket2" 1413 | version = "0.5.7" 1414 | source = "registry+https://github.com/rust-lang/crates.io-index" 1415 | checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" 1416 | dependencies = [ 1417 | "libc", 1418 | "windows-sys 0.52.0", 1419 | ] 1420 | 1421 | [[package]] 1422 | name = "stability" 1423 | version = "0.2.1" 1424 | source = "registry+https://github.com/rust-lang/crates.io-index" 1425 | checksum = "d904e7009df136af5297832a3ace3370cd14ff1546a232f4f185036c2736fcac" 1426 | dependencies = [ 1427 | "quote", 1428 | "syn", 1429 | ] 1430 | 1431 | [[package]] 1432 | name = "static_assertions" 1433 | version = "1.1.0" 1434 | source = "registry+https://github.com/rust-lang/crates.io-index" 1435 | checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 1436 | 1437 | [[package]] 1438 | name = "strsim" 1439 | version = "0.11.1" 1440 | source = "registry+https://github.com/rust-lang/crates.io-index" 1441 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 1442 | 1443 | [[package]] 1444 | name = "strum" 1445 | version = "0.26.3" 1446 | source = "registry+https://github.com/rust-lang/crates.io-index" 1447 | checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" 1448 | dependencies = [ 1449 | "strum_macros", 1450 | ] 1451 | 1452 | [[package]] 1453 | name = "strum_macros" 1454 | version = "0.26.4" 1455 | source = "registry+https://github.com/rust-lang/crates.io-index" 1456 | checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" 1457 | dependencies = [ 1458 | "heck", 1459 | "proc-macro2", 1460 | "quote", 1461 | "rustversion", 1462 | "syn", 1463 | ] 1464 | 1465 | [[package]] 1466 | name = "subtle" 1467 | version = "2.6.1" 1468 | source = "registry+https://github.com/rust-lang/crates.io-index" 1469 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 1470 | 1471 | [[package]] 1472 | name = "syn" 1473 | version = "2.0.70" 1474 | source = "registry+https://github.com/rust-lang/crates.io-index" 1475 | checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16" 1476 | dependencies = [ 1477 | "proc-macro2", 1478 | "quote", 1479 | "unicode-ident", 1480 | ] 1481 | 1482 | [[package]] 1483 | name = "sync_wrapper" 1484 | version = "1.0.1" 1485 | source = "registry+https://github.com/rust-lang/crates.io-index" 1486 | checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" 1487 | 1488 | [[package]] 1489 | name = "system-configuration" 1490 | version = "0.5.1" 1491 | source = "registry+https://github.com/rust-lang/crates.io-index" 1492 | checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" 1493 | dependencies = [ 1494 | "bitflags 1.3.2", 1495 | "core-foundation", 1496 | "system-configuration-sys", 1497 | ] 1498 | 1499 | [[package]] 1500 | name = "system-configuration-sys" 1501 | version = "0.5.0" 1502 | source = "registry+https://github.com/rust-lang/crates.io-index" 1503 | checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" 1504 | dependencies = [ 1505 | "core-foundation-sys", 1506 | "libc", 1507 | ] 1508 | 1509 | [[package]] 1510 | name = "tempfile" 1511 | version = "3.10.1" 1512 | source = "registry+https://github.com/rust-lang/crates.io-index" 1513 | checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" 1514 | dependencies = [ 1515 | "cfg-if", 1516 | "fastrand", 1517 | "rustix", 1518 | "windows-sys 0.52.0", 1519 | ] 1520 | 1521 | [[package]] 1522 | name = "tinyvec" 1523 | version = "1.8.0" 1524 | source = "registry+https://github.com/rust-lang/crates.io-index" 1525 | checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" 1526 | dependencies = [ 1527 | "tinyvec_macros", 1528 | ] 1529 | 1530 | [[package]] 1531 | name = "tinyvec_macros" 1532 | version = "0.1.1" 1533 | source = "registry+https://github.com/rust-lang/crates.io-index" 1534 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 1535 | 1536 | [[package]] 1537 | name = "tokio" 1538 | version = "1.38.2" 1539 | source = "registry+https://github.com/rust-lang/crates.io-index" 1540 | checksum = "68722da18b0fc4a05fdc1120b302b82051265792a1e1b399086e9b204b10ad3d" 1541 | dependencies = [ 1542 | "backtrace", 1543 | "bytes", 1544 | "libc", 1545 | "mio", 1546 | "pin-project-lite", 1547 | "socket2", 1548 | "tokio-macros", 1549 | "windows-sys 0.48.0", 1550 | ] 1551 | 1552 | [[package]] 1553 | name = "tokio-io-timeout" 1554 | version = "1.2.0" 1555 | source = "registry+https://github.com/rust-lang/crates.io-index" 1556 | checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" 1557 | dependencies = [ 1558 | "pin-project-lite", 1559 | "tokio", 1560 | ] 1561 | 1562 | [[package]] 1563 | name = "tokio-macros" 1564 | version = "2.3.0" 1565 | source = "registry+https://github.com/rust-lang/crates.io-index" 1566 | checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" 1567 | dependencies = [ 1568 | "proc-macro2", 1569 | "quote", 1570 | "syn", 1571 | ] 1572 | 1573 | [[package]] 1574 | name = "tokio-native-tls" 1575 | version = "0.3.1" 1576 | source = "registry+https://github.com/rust-lang/crates.io-index" 1577 | checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" 1578 | dependencies = [ 1579 | "native-tls", 1580 | "tokio", 1581 | ] 1582 | 1583 | [[package]] 1584 | name = "tokio-rustls" 1585 | version = "0.24.1" 1586 | source = "registry+https://github.com/rust-lang/crates.io-index" 1587 | checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" 1588 | dependencies = [ 1589 | "rustls 0.21.12", 1590 | "tokio", 1591 | ] 1592 | 1593 | [[package]] 1594 | name = "tokio-rustls" 1595 | version = "0.26.0" 1596 | source = "registry+https://github.com/rust-lang/crates.io-index" 1597 | checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" 1598 | dependencies = [ 1599 | "rustls 0.23.11", 1600 | "rustls-pki-types", 1601 | "tokio", 1602 | ] 1603 | 1604 | [[package]] 1605 | name = "tokio-util" 1606 | version = "0.7.11" 1607 | source = "registry+https://github.com/rust-lang/crates.io-index" 1608 | checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" 1609 | dependencies = [ 1610 | "bytes", 1611 | "futures-core", 1612 | "futures-sink", 1613 | "pin-project-lite", 1614 | "tokio", 1615 | ] 1616 | 1617 | [[package]] 1618 | name = "tower" 1619 | version = "0.4.13" 1620 | source = "registry+https://github.com/rust-lang/crates.io-index" 1621 | checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" 1622 | dependencies = [ 1623 | "futures-core", 1624 | "futures-util", 1625 | "pin-project", 1626 | "pin-project-lite", 1627 | "tokio", 1628 | "tower-layer", 1629 | "tower-service", 1630 | ] 1631 | 1632 | [[package]] 1633 | name = "tower-layer" 1634 | version = "0.3.2" 1635 | source = "registry+https://github.com/rust-lang/crates.io-index" 1636 | checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" 1637 | 1638 | [[package]] 1639 | name = "tower-service" 1640 | version = "0.3.2" 1641 | source = "registry+https://github.com/rust-lang/crates.io-index" 1642 | checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" 1643 | 1644 | [[package]] 1645 | name = "tracing" 1646 | version = "0.1.40" 1647 | source = "registry+https://github.com/rust-lang/crates.io-index" 1648 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 1649 | dependencies = [ 1650 | "pin-project-lite", 1651 | "tracing-core", 1652 | ] 1653 | 1654 | [[package]] 1655 | name = "tracing-core" 1656 | version = "0.1.32" 1657 | source = "registry+https://github.com/rust-lang/crates.io-index" 1658 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 1659 | dependencies = [ 1660 | "once_cell", 1661 | ] 1662 | 1663 | [[package]] 1664 | name = "try-lock" 1665 | version = "0.2.5" 1666 | source = "registry+https://github.com/rust-lang/crates.io-index" 1667 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 1668 | 1669 | [[package]] 1670 | name = "unicode-bidi" 1671 | version = "0.3.15" 1672 | source = "registry+https://github.com/rust-lang/crates.io-index" 1673 | checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" 1674 | 1675 | [[package]] 1676 | name = "unicode-ident" 1677 | version = "1.0.12" 1678 | source = "registry+https://github.com/rust-lang/crates.io-index" 1679 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 1680 | 1681 | [[package]] 1682 | name = "unicode-normalization" 1683 | version = "0.1.23" 1684 | source = "registry+https://github.com/rust-lang/crates.io-index" 1685 | checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" 1686 | dependencies = [ 1687 | "tinyvec", 1688 | ] 1689 | 1690 | [[package]] 1691 | name = "unicode-segmentation" 1692 | version = "1.11.0" 1693 | source = "registry+https://github.com/rust-lang/crates.io-index" 1694 | checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" 1695 | 1696 | [[package]] 1697 | name = "unicode-truncate" 1698 | version = "1.1.0" 1699 | source = "registry+https://github.com/rust-lang/crates.io-index" 1700 | checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" 1701 | dependencies = [ 1702 | "itertools 0.13.0", 1703 | "unicode-segmentation", 1704 | "unicode-width", 1705 | ] 1706 | 1707 | [[package]] 1708 | name = "unicode-width" 1709 | version = "0.1.13" 1710 | source = "registry+https://github.com/rust-lang/crates.io-index" 1711 | checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" 1712 | 1713 | [[package]] 1714 | name = "untrusted" 1715 | version = "0.9.0" 1716 | source = "registry+https://github.com/rust-lang/crates.io-index" 1717 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 1718 | 1719 | [[package]] 1720 | name = "url" 1721 | version = "2.5.2" 1722 | source = "registry+https://github.com/rust-lang/crates.io-index" 1723 | checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" 1724 | dependencies = [ 1725 | "form_urlencoded", 1726 | "idna", 1727 | "percent-encoding", 1728 | ] 1729 | 1730 | [[package]] 1731 | name = "utf8parse" 1732 | version = "0.2.2" 1733 | source = "registry+https://github.com/rust-lang/crates.io-index" 1734 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 1735 | 1736 | [[package]] 1737 | name = "vcpkg" 1738 | version = "0.2.15" 1739 | source = "registry+https://github.com/rust-lang/crates.io-index" 1740 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 1741 | 1742 | [[package]] 1743 | name = "version_check" 1744 | version = "0.9.4" 1745 | source = "registry+https://github.com/rust-lang/crates.io-index" 1746 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 1747 | 1748 | [[package]] 1749 | name = "want" 1750 | version = "0.3.1" 1751 | source = "registry+https://github.com/rust-lang/crates.io-index" 1752 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 1753 | dependencies = [ 1754 | "try-lock", 1755 | ] 1756 | 1757 | [[package]] 1758 | name = "wasi" 1759 | version = "0.11.0+wasi-snapshot-preview1" 1760 | source = "registry+https://github.com/rust-lang/crates.io-index" 1761 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1762 | 1763 | [[package]] 1764 | name = "wasm-bindgen" 1765 | version = "0.2.92" 1766 | source = "registry+https://github.com/rust-lang/crates.io-index" 1767 | checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" 1768 | dependencies = [ 1769 | "cfg-if", 1770 | "wasm-bindgen-macro", 1771 | ] 1772 | 1773 | [[package]] 1774 | name = "wasm-bindgen-backend" 1775 | version = "0.2.92" 1776 | source = "registry+https://github.com/rust-lang/crates.io-index" 1777 | checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" 1778 | dependencies = [ 1779 | "bumpalo", 1780 | "log", 1781 | "once_cell", 1782 | "proc-macro2", 1783 | "quote", 1784 | "syn", 1785 | "wasm-bindgen-shared", 1786 | ] 1787 | 1788 | [[package]] 1789 | name = "wasm-bindgen-futures" 1790 | version = "0.4.42" 1791 | source = "registry+https://github.com/rust-lang/crates.io-index" 1792 | checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" 1793 | dependencies = [ 1794 | "cfg-if", 1795 | "js-sys", 1796 | "wasm-bindgen", 1797 | "web-sys", 1798 | ] 1799 | 1800 | [[package]] 1801 | name = "wasm-bindgen-macro" 1802 | version = "0.2.92" 1803 | source = "registry+https://github.com/rust-lang/crates.io-index" 1804 | checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" 1805 | dependencies = [ 1806 | "quote", 1807 | "wasm-bindgen-macro-support", 1808 | ] 1809 | 1810 | [[package]] 1811 | name = "wasm-bindgen-macro-support" 1812 | version = "0.2.92" 1813 | source = "registry+https://github.com/rust-lang/crates.io-index" 1814 | checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" 1815 | dependencies = [ 1816 | "proc-macro2", 1817 | "quote", 1818 | "syn", 1819 | "wasm-bindgen-backend", 1820 | "wasm-bindgen-shared", 1821 | ] 1822 | 1823 | [[package]] 1824 | name = "wasm-bindgen-shared" 1825 | version = "0.2.92" 1826 | source = "registry+https://github.com/rust-lang/crates.io-index" 1827 | checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" 1828 | 1829 | [[package]] 1830 | name = "web-sys" 1831 | version = "0.3.69" 1832 | source = "registry+https://github.com/rust-lang/crates.io-index" 1833 | checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" 1834 | dependencies = [ 1835 | "js-sys", 1836 | "wasm-bindgen", 1837 | ] 1838 | 1839 | [[package]] 1840 | name = "winapi" 1841 | version = "0.3.9" 1842 | source = "registry+https://github.com/rust-lang/crates.io-index" 1843 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1844 | dependencies = [ 1845 | "winapi-i686-pc-windows-gnu", 1846 | "winapi-x86_64-pc-windows-gnu", 1847 | ] 1848 | 1849 | [[package]] 1850 | name = "winapi-i686-pc-windows-gnu" 1851 | version = "0.4.0" 1852 | source = "registry+https://github.com/rust-lang/crates.io-index" 1853 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1854 | 1855 | [[package]] 1856 | name = "winapi-x86_64-pc-windows-gnu" 1857 | version = "0.4.0" 1858 | source = "registry+https://github.com/rust-lang/crates.io-index" 1859 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1860 | 1861 | [[package]] 1862 | name = "windows-sys" 1863 | version = "0.48.0" 1864 | source = "registry+https://github.com/rust-lang/crates.io-index" 1865 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 1866 | dependencies = [ 1867 | "windows-targets 0.48.5", 1868 | ] 1869 | 1870 | [[package]] 1871 | name = "windows-sys" 1872 | version = "0.52.0" 1873 | source = "registry+https://github.com/rust-lang/crates.io-index" 1874 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1875 | dependencies = [ 1876 | "windows-targets 0.52.6", 1877 | ] 1878 | 1879 | [[package]] 1880 | name = "windows-targets" 1881 | version = "0.48.5" 1882 | source = "registry+https://github.com/rust-lang/crates.io-index" 1883 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 1884 | dependencies = [ 1885 | "windows_aarch64_gnullvm 0.48.5", 1886 | "windows_aarch64_msvc 0.48.5", 1887 | "windows_i686_gnu 0.48.5", 1888 | "windows_i686_msvc 0.48.5", 1889 | "windows_x86_64_gnu 0.48.5", 1890 | "windows_x86_64_gnullvm 0.48.5", 1891 | "windows_x86_64_msvc 0.48.5", 1892 | ] 1893 | 1894 | [[package]] 1895 | name = "windows-targets" 1896 | version = "0.52.6" 1897 | source = "registry+https://github.com/rust-lang/crates.io-index" 1898 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1899 | dependencies = [ 1900 | "windows_aarch64_gnullvm 0.52.6", 1901 | "windows_aarch64_msvc 0.52.6", 1902 | "windows_i686_gnu 0.52.6", 1903 | "windows_i686_gnullvm", 1904 | "windows_i686_msvc 0.52.6", 1905 | "windows_x86_64_gnu 0.52.6", 1906 | "windows_x86_64_gnullvm 0.52.6", 1907 | "windows_x86_64_msvc 0.52.6", 1908 | ] 1909 | 1910 | [[package]] 1911 | name = "windows_aarch64_gnullvm" 1912 | version = "0.48.5" 1913 | source = "registry+https://github.com/rust-lang/crates.io-index" 1914 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 1915 | 1916 | [[package]] 1917 | name = "windows_aarch64_gnullvm" 1918 | version = "0.52.6" 1919 | source = "registry+https://github.com/rust-lang/crates.io-index" 1920 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1921 | 1922 | [[package]] 1923 | name = "windows_aarch64_msvc" 1924 | version = "0.48.5" 1925 | source = "registry+https://github.com/rust-lang/crates.io-index" 1926 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 1927 | 1928 | [[package]] 1929 | name = "windows_aarch64_msvc" 1930 | version = "0.52.6" 1931 | source = "registry+https://github.com/rust-lang/crates.io-index" 1932 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1933 | 1934 | [[package]] 1935 | name = "windows_i686_gnu" 1936 | version = "0.48.5" 1937 | source = "registry+https://github.com/rust-lang/crates.io-index" 1938 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 1939 | 1940 | [[package]] 1941 | name = "windows_i686_gnu" 1942 | version = "0.52.6" 1943 | source = "registry+https://github.com/rust-lang/crates.io-index" 1944 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1945 | 1946 | [[package]] 1947 | name = "windows_i686_gnullvm" 1948 | version = "0.52.6" 1949 | source = "registry+https://github.com/rust-lang/crates.io-index" 1950 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1951 | 1952 | [[package]] 1953 | name = "windows_i686_msvc" 1954 | version = "0.48.5" 1955 | source = "registry+https://github.com/rust-lang/crates.io-index" 1956 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 1957 | 1958 | [[package]] 1959 | name = "windows_i686_msvc" 1960 | version = "0.52.6" 1961 | source = "registry+https://github.com/rust-lang/crates.io-index" 1962 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1963 | 1964 | [[package]] 1965 | name = "windows_x86_64_gnu" 1966 | version = "0.48.5" 1967 | source = "registry+https://github.com/rust-lang/crates.io-index" 1968 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 1969 | 1970 | [[package]] 1971 | name = "windows_x86_64_gnu" 1972 | version = "0.52.6" 1973 | source = "registry+https://github.com/rust-lang/crates.io-index" 1974 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1975 | 1976 | [[package]] 1977 | name = "windows_x86_64_gnullvm" 1978 | version = "0.48.5" 1979 | source = "registry+https://github.com/rust-lang/crates.io-index" 1980 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 1981 | 1982 | [[package]] 1983 | name = "windows_x86_64_gnullvm" 1984 | version = "0.52.6" 1985 | source = "registry+https://github.com/rust-lang/crates.io-index" 1986 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1987 | 1988 | [[package]] 1989 | name = "windows_x86_64_msvc" 1990 | version = "0.48.5" 1991 | source = "registry+https://github.com/rust-lang/crates.io-index" 1992 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 1993 | 1994 | [[package]] 1995 | name = "windows_x86_64_msvc" 1996 | version = "0.52.6" 1997 | source = "registry+https://github.com/rust-lang/crates.io-index" 1998 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1999 | 2000 | [[package]] 2001 | name = "winreg" 2002 | version = "0.52.0" 2003 | source = "registry+https://github.com/rust-lang/crates.io-index" 2004 | checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" 2005 | dependencies = [ 2006 | "cfg-if", 2007 | "windows-sys 0.48.0", 2008 | ] 2009 | 2010 | [[package]] 2011 | name = "zerocopy" 2012 | version = "0.7.35" 2013 | source = "registry+https://github.com/rust-lang/crates.io-index" 2014 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 2015 | dependencies = [ 2016 | "zerocopy-derive", 2017 | ] 2018 | 2019 | [[package]] 2020 | name = "zerocopy-derive" 2021 | version = "0.7.35" 2022 | source = "registry+https://github.com/rust-lang/crates.io-index" 2023 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 2024 | dependencies = [ 2025 | "proc-macro2", 2026 | "quote", 2027 | "syn", 2028 | ] 2029 | 2030 | [[package]] 2031 | name = "zeroize" 2032 | version = "1.8.1" 2033 | source = "registry+https://github.com/rust-lang/crates.io-index" 2034 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 2035 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "roller" 3 | version = "0.1.1" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | # async & streams 8 | tokio = { version = "1.38.2", features = ["macros"] } 9 | futures = "0.3.30" 10 | # http 11 | reqwest = "0.12.4" 12 | # server-side events 13 | eventsource-client = "0.12.2" 14 | # de/ser 15 | serde = { version = "1.0.203", features = ["derive"] } 16 | serde_json = "1.0.117" 17 | # terminal interface 18 | ratatui = "0.26.3" 19 | crossterm = "0.27.0" 20 | # config & input 21 | clap = { version = "4.5.7", features = ["derive"] } 22 | 23 | 24 | [profile.release] 25 | opt-level = 3 26 | lto = "fat" 27 | codegen-units = 1 28 | debug = false 29 | rpath = false 30 | panic = 'abort' 31 | incremental = false 32 | overflow-checks = false 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2024 wavefnx 2 | 3 | Mozilla Public License Version 2.0 4 | ================================== 5 | 6 | 1. Definitions 7 | -------------- 8 | 9 | 1.1. "Contributor" 10 | means each individual or legal entity that creates, contributes to 11 | the creation of, or owns Covered Software. 12 | 13 | 1.2. "Contributor Version" 14 | means the combination of the Contributions of others (if any) used 15 | by a Contributor and that particular Contributor's Contribution. 16 | 17 | 1.3. "Contribution" 18 | means Covered Software of a particular Contributor. 19 | 20 | 1.4. "Covered Software" 21 | means Source Code Form to which the initial Contributor has attached 22 | the notice in Exhibit A, the Executable Form of such Source Code 23 | Form, and Modifications of such Source Code Form, in each case 24 | including portions thereof. 25 | 26 | 1.5. "Incompatible With Secondary Licenses" 27 | means 28 | 29 | (a) that the initial Contributor has attached the notice described 30 | in Exhibit B to the Covered Software; or 31 | 32 | (b) that the Covered Software was made available under the terms of 33 | version 1.1 or earlier of the License, but not also under the 34 | terms of a Secondary License. 35 | 36 | 1.6. "Executable Form" 37 | means any form of the work other than Source Code Form. 38 | 39 | 1.7. "Larger Work" 40 | means a work that combines Covered Software with other material, in 41 | a separate file or files, that is not Covered Software. 42 | 43 | 1.8. "License" 44 | means this document. 45 | 46 | 1.9. "Licensable" 47 | means having the right to grant, to the maximum extent possible, 48 | whether at the time of the initial grant or subsequently, any and 49 | all of the rights conveyed by this License. 50 | 51 | 1.10. "Modifications" 52 | means any of the following: 53 | 54 | (a) any file in Source Code Form that results from an addition to, 55 | deletion from, or modification of the contents of Covered 56 | Software; or 57 | 58 | (b) any new file in Source Code Form that contains any Covered 59 | Software. 60 | 61 | 1.11. "Patent Claims" of a Contributor 62 | means any patent claim(s), including without limitation, method, 63 | process, and apparatus claims, in any patent Licensable by such 64 | Contributor that would be infringed, but for the grant of the 65 | License, by the making, using, selling, offering for sale, having 66 | made, import, or transfer of either its Contributions or its 67 | Contributor Version. 68 | 69 | 1.12. "Secondary License" 70 | means either the GNU General Public License, Version 2.0, the GNU 71 | Lesser General Public License, Version 2.1, the GNU Affero General 72 | Public License, Version 3.0, or any later versions of those 73 | licenses. 74 | 75 | 1.13. "Source Code Form" 76 | means the form of the work preferred for making modifications. 77 | 78 | 1.14. "You" (or "Your") 79 | means an individual or a legal entity exercising rights under this 80 | License. For legal entities, "You" includes any entity that 81 | controls, is controlled by, or is under common control with You. For 82 | purposes of this definition, "control" means (a) the power, direct 83 | or indirect, to cause the direction or management of such entity, 84 | whether by contract or otherwise, or (b) ownership of more than 85 | fifty percent (50%) of the outstanding shares or beneficial 86 | ownership of such entity. 87 | 88 | 2. License Grants and Conditions 89 | -------------------------------- 90 | 91 | 2.1. Grants 92 | 93 | Each Contributor hereby grants You a world-wide, royalty-free, 94 | non-exclusive license: 95 | 96 | (a) under intellectual property rights (other than patent or trademark) 97 | Licensable by such Contributor to use, reproduce, make available, 98 | modify, display, perform, distribute, and otherwise exploit its 99 | Contributions, either on an unmodified basis, with Modifications, or 100 | as part of a Larger Work; and 101 | 102 | (b) under Patent Claims of such Contributor to make, use, sell, offer 103 | for sale, have made, import, and otherwise transfer either its 104 | Contributions or its Contributor Version. 105 | 106 | 2.2. Effective Date 107 | 108 | The licenses granted in Section 2.1 with respect to any Contribution 109 | become effective for each Contribution on the date the Contributor first 110 | distributes such Contribution. 111 | 112 | 2.3. Limitations on Grant Scope 113 | 114 | The licenses granted in this Section 2 are the only rights granted under 115 | this License. No additional rights or licenses will be implied from the 116 | distribution or licensing of Covered Software under this License. 117 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 118 | Contributor: 119 | 120 | (a) for any code that a Contributor has removed from Covered Software; 121 | or 122 | 123 | (b) for infringements caused by: (i) Your and any other third party's 124 | modifications of Covered Software, or (ii) the combination of its 125 | Contributions with other software (except as part of its Contributor 126 | Version); or 127 | 128 | (c) under Patent Claims infringed by Covered Software in the absence of 129 | its Contributions. 130 | 131 | This License does not grant any rights in the trademarks, service marks, 132 | or logos of any Contributor (except as may be necessary to comply with 133 | the notice requirements in Section 3.4). 134 | 135 | 2.4. Subsequent Licenses 136 | 137 | No Contributor makes additional grants as a result of Your choice to 138 | distribute the Covered Software under a subsequent version of this 139 | License (see Section 10.2) or under the terms of a Secondary License (if 140 | permitted under the terms of Section 3.3). 141 | 142 | 2.5. Representation 143 | 144 | Each Contributor represents that the Contributor believes its 145 | Contributions are its original creation(s) or it has sufficient rights 146 | to grant the rights to its Contributions conveyed by this License. 147 | 148 | 2.6. Fair Use 149 | 150 | This License is not intended to limit any rights You have under 151 | applicable copyright doctrines of fair use, fair dealing, or other 152 | equivalents. 153 | 154 | 2.7. Conditions 155 | 156 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 157 | in Section 2.1. 158 | 159 | 3. Responsibilities 160 | ------------------- 161 | 162 | 3.1. Distribution of Source Form 163 | 164 | All distribution of Covered Software in Source Code Form, including any 165 | Modifications that You create or to which You contribute, must be under 166 | the terms of this License. You must inform recipients that the Source 167 | Code Form of the Covered Software is governed by the terms of this 168 | License, and how they can obtain a copy of this License. You may not 169 | attempt to alter or restrict the recipients' rights in the Source Code 170 | Form. 171 | 172 | 3.2. Distribution of Executable Form 173 | 174 | If You distribute Covered Software in Executable Form then: 175 | 176 | (a) such Covered Software must also be made available in Source Code 177 | Form, as described in Section 3.1, and You must inform recipients of 178 | the Executable Form how they can obtain a copy of such Source Code 179 | Form by reasonable means in a timely manner, at a charge no more 180 | than the cost of distribution to the recipient; and 181 | 182 | (b) You may distribute such Executable Form under the terms of this 183 | License, or sublicense it under different terms, provided that the 184 | license for the Executable Form does not attempt to limit or alter 185 | the recipients' rights in the Source Code Form under this License. 186 | 187 | 3.3. Distribution of a Larger Work 188 | 189 | You may create and distribute a Larger Work under terms of Your choice, 190 | provided that You also comply with the requirements of this License for 191 | the Covered Software. If the Larger Work is a combination of Covered 192 | Software with a work governed by one or more Secondary Licenses, and the 193 | Covered Software is not Incompatible With Secondary Licenses, this 194 | License permits You to additionally distribute such Covered Software 195 | under the terms of such Secondary License(s), so that the recipient of 196 | the Larger Work may, at their option, further distribute the Covered 197 | Software under the terms of either this License or such Secondary 198 | License(s). 199 | 200 | 3.4. Notices 201 | 202 | You may not remove or alter the substance of any license notices 203 | (including copyright notices, patent notices, disclaimers of warranty, 204 | or limitations of liability) contained within the Source Code Form of 205 | the Covered Software, except that You may alter any license notices to 206 | the extent required to remedy known factual inaccuracies. 207 | 208 | 3.5. Application of Additional Terms 209 | 210 | You may choose to offer, and to charge a fee for, warranty, support, 211 | indemnity or liability obligations to one or more recipients of Covered 212 | Software. However, You may do so only on Your own behalf, and not on 213 | behalf of any Contributor. You must make it absolutely clear that any 214 | such warranty, support, indemnity, or liability obligation is offered by 215 | You alone, and You hereby agree to indemnify every Contributor for any 216 | liability incurred by such Contributor as a result of warranty, support, 217 | indemnity or liability terms You offer. You may include additional 218 | disclaimers of warranty and limitations of liability specific to any 219 | jurisdiction. 220 | 221 | 4. Inability to Comply Due to Statute or Regulation 222 | --------------------------------------------------- 223 | 224 | If it is impossible for You to comply with any of the terms of this 225 | License with respect to some or all of the Covered Software due to 226 | statute, judicial order, or regulation then You must: (a) comply with 227 | the terms of this License to the maximum extent possible; and (b) 228 | describe the limitations and the code they affect. Such description must 229 | be placed in a text file included with all distributions of the Covered 230 | Software under this License. Except to the extent prohibited by statute 231 | or regulation, such description must be sufficiently detailed for a 232 | recipient of ordinary skill to be able to understand it. 233 | 234 | 5. Termination 235 | -------------- 236 | 237 | 5.1. The rights granted under this License will terminate automatically 238 | if You fail to comply with any of its terms. However, if You become 239 | compliant, then the rights granted under this License from a particular 240 | Contributor are reinstated (a) provisionally, unless and until such 241 | Contributor explicitly and finally terminates Your grants, and (b) on an 242 | ongoing basis, if such Contributor fails to notify You of the 243 | non-compliance by some reasonable means prior to 60 days after You have 244 | come back into compliance. Moreover, Your grants from a particular 245 | Contributor are reinstated on an ongoing basis if such Contributor 246 | notifies You of the non-compliance by some reasonable means, this is the 247 | first time You have received notice of non-compliance with this License 248 | from such Contributor, and You become compliant prior to 30 days after 249 | Your receipt of the notice. 250 | 251 | 5.2. If You initiate litigation against any entity by asserting a patent 252 | infringement claim (excluding declaratory judgment actions, 253 | counter-claims, and cross-claims) alleging that a Contributor Version 254 | directly or indirectly infringes any patent, then the rights granted to 255 | You by any and all Contributors for the Covered Software under Section 256 | 2.1 of this License shall terminate. 257 | 258 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 259 | end user license agreements (excluding distributors and resellers) which 260 | have been validly granted by You or Your distributors under this License 261 | prior to termination shall survive termination. 262 | 263 | ************************************************************************ 264 | * * 265 | * 6. Disclaimer of Warranty * 266 | * ------------------------- * 267 | * * 268 | * Covered Software is provided under this License on an "as is" * 269 | * basis, without warranty of any kind, either expressed, implied, or * 270 | * statutory, including, without limitation, warranties that the * 271 | * Covered Software is free of defects, merchantable, fit for a * 272 | * particular purpose or non-infringing. The entire risk as to the * 273 | * quality and performance of the Covered Software is with You. * 274 | * Should any Covered Software prove defective in any respect, You * 275 | * (not any Contributor) assume the cost of any necessary servicing, * 276 | * repair, or correction. This disclaimer of warranty constitutes an * 277 | * essential part of this License. No use of any Covered Software is * 278 | * authorized under this License except under this disclaimer. * 279 | * * 280 | ************************************************************************ 281 | 282 | ************************************************************************ 283 | * * 284 | * 7. Limitation of Liability * 285 | * -------------------------- * 286 | * * 287 | * Under no circumstances and under no legal theory, whether tort * 288 | * (including negligence), contract, or otherwise, shall any * 289 | * Contributor, or anyone who distributes Covered Software as * 290 | * permitted above, be liable to You for any direct, indirect, * 291 | * special, incidental, or consequential damages of any character * 292 | * including, without limitation, damages for lost profits, loss of * 293 | * goodwill, work stoppage, computer failure or malfunction, or any * 294 | * and all other commercial damages or losses, even if such party * 295 | * shall have been informed of the possibility of such damages. This * 296 | * limitation of liability shall not apply to liability for death or * 297 | * personal injury resulting from such party's negligence to the * 298 | * extent applicable law prohibits such limitation. Some * 299 | * jurisdictions do not allow the exclusion or limitation of * 300 | * incidental or consequential damages, so this exclusion and * 301 | * limitation may not apply to You. * 302 | * * 303 | ************************************************************************ 304 | 305 | 8. Litigation 306 | ------------- 307 | 308 | Any litigation relating to this License may be brought only in the 309 | courts of a jurisdiction where the defendant maintains its principal 310 | place of business and such litigation shall be governed by laws of that 311 | jurisdiction, without reference to its conflict-of-law provisions. 312 | Nothing in this Section shall prevent a party's ability to bring 313 | cross-claims or counter-claims. 314 | 315 | 9. Miscellaneous 316 | ---------------- 317 | 318 | This License represents the complete agreement concerning the subject 319 | matter hereof. If any provision of this License is held to be 320 | unenforceable, such provision shall be reformed only to the extent 321 | necessary to make it enforceable. Any law or regulation which provides 322 | that the language of a contract shall be construed against the drafter 323 | shall not be used to construe this License against a Contributor. 324 | 325 | 10. Versions of the License 326 | --------------------------- 327 | 328 | 10.1. New Versions 329 | 330 | Mozilla Foundation is the license steward. Except as provided in Section 331 | 10.3, no one other than the license steward has the right to modify or 332 | publish new versions of this License. Each version will be given a 333 | distinguishing version number. 334 | 335 | 10.2. Effect of New Versions 336 | 337 | You may distribute the Covered Software under the terms of the version 338 | of the License under which You originally received the Covered Software, 339 | or under the terms of any subsequent version published by the license 340 | steward. 341 | 342 | 10.3. Modified Versions 343 | 344 | If you create software not governed by this License, and you want to 345 | create a new license for such software, you may create and use a 346 | modified version of this License if you rename the license and remove 347 | any references to the name of the license steward (except to note that 348 | such modified license differs from this License). 349 | 350 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 351 | Licenses 352 | 353 | If You choose to distribute Source Code Form that is Incompatible With 354 | Secondary Licenses under the terms of this version of the License, the 355 | notice described in Exhibit B of this License must be attached. 356 | 357 | Exhibit A - Source Code Form License Notice 358 | ------------------------------------------- 359 | 360 | This Source Code Form is subject to the terms of the Mozilla Public 361 | License, v. 2.0. If a copy of the MPL was not distributed with this 362 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 363 | 364 | If it is not possible or desirable to put the notice in a particular 365 | file, then You may include the notice in a location (such as a LICENSE 366 | file in a relevant directory) where a recipient would be likely to look 367 | for such a notice. 368 | 369 | You may add additional accurate notices of copyright ownership. 370 | 371 | Exhibit B - "Incompatible With Secondary Licenses" Notice 372 | --------------------------------------------------------- 373 | 374 | This Source Code Form is "Incompatible With Secondary Licenses", as 375 | defined by the Mozilla Public License, v. 2.0. 376 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | ![roller-banner](https://github.com/wavefnx/roller/assets/157986149/4b235f87-ede1-4512-80eb-76c7a61814d5) 6 |
7 | 8 |
9 | 10 | [Overview](#Overview) | [Disclaimer](#Disclaimer) | [Installation](#Installation) | [Usage](#Usage) | [Examples](#Examples) | [Aknowledgements](#Aknowledgements) | [License](#License) 11 |
12 | 13 | 14 |
15 | 16 | [![CI](https://img.shields.io/github/actions/workflow/status/wavefnx/roller/ci.yml?style=flat-square&label=CI&labelColor=%23343940&color=%2340C057)](https://github.com/wavefnx/roller/actions/workflows/ci.yml) 17 | [![MPL-2.0](https://img.shields.io/github/license/wavefnx/roller?style=flat-square&color=blue&label=)](LICENSE) 18 |
19 | 20 | ## Overview 21 | Terminal interface tracking gas, transactions and data processed by Decentralized Networks. 22 | 23 | 24 | ## Disclaimer 25 | This library is in early development stages and subject to potential breaking changes. 26 | Backward compatibility or further maintenance is not guaranteed. The package is intentionally not published on crates.io until and if there's an `alpha` release in the future. 27 | 28 | Contributions are welcome. Users are encouraged to submit pull requests, fork, or alter the code in accordance with the terms outlined in the [LICENSE](LICENSE). 29 | 30 | 31 | ## Installation 32 | You can currently build from source by running the following command in the root of the repository: 33 | ```rust 34 | cargo build --release 35 | ``` 36 | 37 | ## Usage 38 | ``` 39 | Terminal interface tracking gas, transactions and data processed by Decentralized Networks 40 | 41 | Usage: roller [OPTIONS] 42 | 43 | Options: 44 | -i, --interval-ms Interval in ms to wait between events. [default: 100] 45 | Increase for lower resource consumption, decrease for more frequent updates 46 | --api-endpoint Change the default API Endpoint by specifying a different URL 47 | -h, --help Print help 48 | -V, --version Print version 49 | ``` 50 | 51 | ## Examples 52 | 53 | ```sh 54 | // The default update interval (100ms) should offer a good balance between low resource consumption and updated data. 55 | roller 56 | 57 | // To run it as a long, background widget, you can increase the interval to 500ms, 1s or more. 58 | roller -i 1000 59 | 60 | // Additionally, to get SSE data live with no bounds, as they are being produced by the SSE API: 61 | roller -i 0 62 | ``` 63 | 64 | ## Aknowledgements 65 | The interface is using the same API as [rollup.wtf](https://rollup.wtf), which is provided by [conduit.xyz](https://conduit.xyz). 66 | 67 | ## License 68 | This library is released under the terms of the [Mozilla Public License](https://www.mozilla.org/en-US/MPL/) version 2.0. See [LICENSE](LICENSE). 69 | -------------------------------------------------------------------------------- /src/client.rs: -------------------------------------------------------------------------------- 1 | use crate::Network; 2 | use eventsource_client::{self as es, Client as EventSourceClient, SSE}; 3 | use futures::Stream; 4 | use std::{collections::HashMap, pin::Pin}; 5 | 6 | /// The client provides methods for retrieving network metadata and establishing 7 | /// a connection to a Server-Sent Events (SSE) stream for receiving real-time updates. 8 | pub struct Client { 9 | url: String, 10 | } 11 | 12 | /// The response we're expecting from the EventSourceClient after connection. 13 | /// This is a stream of Server-Sent Events (SSE) or an error. 14 | type StreamResponse = Pin> + Send + Sync + 'static)>>; 15 | 16 | impl Client { 17 | /// Creates a new instance of the client with the specified URL. 18 | /// 19 | /// ### Arguments 20 | /// * `url` - The base URL of the conduit.xyz API. 21 | /// 22 | /// ### Returns 23 | /// A new instance of the `Client`. 24 | pub fn new>(url: T) -> Self { 25 | Self { url: url.into() } 26 | } 27 | 28 | /// Retrieves the network metadata from the API, without the Data field, which will be populated 29 | /// through SSE (server-side event) data after initialization. 30 | /// 31 | /// This method sends a GET request to the `/networkMetadata` endpoint 32 | /// of the API. The response is expected to be a JSON object with network IDs as keys. 33 | /// 34 | /// ### Returns 35 | /// A vector of `Network` structs representing the retrieved network metadata, 36 | /// or an error if the request fails or the response cannot be parsed. 37 | pub async fn get_networks(&self) -> Result, Box> { 38 | // Construct the endpoint URL by appending `/networkMetadata` to the base URL. 39 | let endpoint = format!("{}/networkMetadata", self.url); 40 | let response = reqwest::get(&endpoint).await?; 41 | // Collect the body bytes into a vector 42 | let body = response.bytes().await?.to_vec(); 43 | // We're expecting the response to be a JSON object with network IDs as keys 44 | let networks: HashMap = serde_json::from_slice(&body)?; 45 | // The keys/IDs are the same as the `name` field of the Network, 46 | // therefor we can discard them. 47 | Ok(networks.values().cloned().collect()) 48 | } 49 | 50 | /// Establishes a connection to the Server-Sent Events (SSE) stream of the rollup API. 51 | /// 52 | /// This will create an `EventSourceClient` using the `/sse` endpoint of the API 53 | /// and return a `Stream` of `SSE` events. 54 | /// 55 | /// ### Returns 56 | /// A `StreamResponse` representing the SSE stream, or an error if the connection fails. 57 | pub async fn get_stream(&self) -> Result { 58 | Ok(es::ClientBuilder::for_url(&format!("{}/sse", self.url))? 59 | .build() 60 | .stream()) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | use clap::Parser; 2 | use serde::Serialize; 3 | 4 | #[derive(Parser, Debug, Serialize)] 5 | #[clap(version = crate::VERSION, author = "wavefnx @wavefnx")] 6 | /// Terminal interface tracking gas, transactions and data processed by Decentralized Networks. 7 | pub struct Config { 8 | /// Interval in ms to wait between events. 9 | /// Increase for lower resource consumption, decrease for more frequent updates. 10 | #[clap(long, short = 'i', default_value = "100")] 11 | pub interval_ms: u64, 12 | 13 | /// Change the default API Endpoint by specifying a different URL. 14 | #[clap(long, default_value = crate::DEFAULT_API_ENDPOINT)] 15 | pub api_endpoint: String, 16 | } 17 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | const VERSION: &str = env!("CARGO_PKG_VERSION"); 2 | pub const DEFAULT_API_ENDPOINT: &str = "https://tracker-api-gdesfolyga-uw.a.run.app"; 3 | 4 | mod client; 5 | pub use client::Client; 6 | 7 | mod network; 8 | pub use network::Network; 9 | 10 | mod tui; 11 | pub use tui::Tui; 12 | 13 | mod config; 14 | pub use config::Config; 15 | 16 | mod terminal; 17 | pub use terminal::Terminal; 18 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use clap::Parser; 2 | use crossterm::event::{self, Event as CEvent, KeyCode}; 3 | use eventsource_client::SSE; 4 | use futures::TryStreamExt; 5 | use roller::{Client, Config, Tui}; 6 | use std::{error::Error, time::Duration}; 7 | 8 | // Currently we keep it single-threaded, since there's not much we get from multi. 9 | // In the future, data processing could be offloaded to a separate thread. 10 | #[tokio::main(flavor = "current_thread")] 11 | async fn main() -> Result<(), Box> { 12 | // Parse the command-line configuration 13 | let config = Config::parse(); 14 | // Create a new client instance with the specified API endpoint, or default 15 | let client = Client::new(config.api_endpoint); 16 | 17 | // Retrieve the list of networks from the API, this will give us the metadata. 18 | // At this point, the Data field of the Network struct will be `None` and will be populated later on through SSE. 19 | let networks = client.get_networks().await?; 20 | // Create a new Tui instance with the retrieved network metadata. 21 | let mut tui = Tui::new(networks); 22 | 23 | // Get the SSE Event Stream from the API. 24 | let mut stream = client.get_stream().await?; 25 | 26 | // Enter the terminal mode 27 | let mut terminal = roller::Terminal::enter()?; 28 | 29 | // Start the main event loop 30 | while let Ok(event) = stream.try_next().await { 31 | // Check if an event is received 32 | 33 | if let Some(SSE::Event(event)) = event { 34 | // Update the networks data in the Tui 35 | tui.update_networks(event); 36 | // Redraw the Tui on the terminal 37 | terminal.draw(|f| tui.render(f))?; 38 | } 39 | 40 | // This serves two purposes: 41 | // 1. Checking for user input 42 | // 2. Blocking the thread, lowering the interval in which we process events. 43 | // 44 | // In a multi-thread scenario, we can collect and process multiple events while waiting 45 | if crossterm::event::poll(Duration::from_millis(config.interval_ms))? { 46 | // Read the user input event 47 | if let CEvent::Key(key) = event::read()? { 48 | match key.code { 49 | // Break the loop and exit if 'q' is received 50 | KeyCode::Char('q') => break, 51 | // For any other key, pass it to the Tui for handling 52 | _ => tui.handle_input(key.code), 53 | } 54 | } 55 | } 56 | } 57 | 58 | // Exit the terminal mode and restore the previous terminal state 59 | terminal.exit()?; 60 | 61 | Ok(()) 62 | } 63 | -------------------------------------------------------------------------------- /src/network.rs: -------------------------------------------------------------------------------- 1 | use ratatui::{text::Text, widgets::Row}; 2 | use serde::{Deserialize, Deserializer}; 3 | 4 | /// Represents the data associated with a network. 5 | #[derive(Debug, serde::Deserialize, Default, Clone)] 6 | #[serde(rename_all = "camelCase")] 7 | pub struct Data { 8 | // The current block number of the network. 9 | pub block_number: u64, 10 | // The transactions per second of the network. 11 | #[serde(deserialize_with = "deserialize_string_to_f32")] 12 | pub tps: f32, 13 | // The gas per second of the network. 14 | #[serde(deserialize_with = "deserialize_string_to_f32")] 15 | pub gps: f32, 16 | // The data per second of the network, is processing. 17 | #[serde(deserialize_with = "deserialize_string_to_f32")] 18 | pub dps: f32, 19 | // 20 | // The fields below are disabled until required. 21 | // 22 | // pub data_count: u64, 23 | // pub gas_count: u64, 24 | // pub timestamp: u64, 25 | // pub tx_count: u64, 26 | } 27 | 28 | #[derive(Debug, serde::Deserialize, Default, Clone)] 29 | #[serde(rename_all = "camelCase")] 30 | pub struct Network { 31 | // The name of the network. This is also the networks ID. 32 | pub name: String, 33 | // The label/human-readable name of the network. 34 | pub label: String, 35 | #[serde(deserialize_with = "deserialize_chain_id_to_name")] 36 | // The parent chain, which is also used as a Settlment Layer 37 | // in the case of an Layer 2 network. 38 | pub parent_chain: String, 39 | // The data availability layer of the network. 40 | pub da: String, 41 | // The stack used by the network. 42 | pub stack: String, 43 | // The data associated with the network. 44 | // Populated through SSE (server-side event) data after initialization. 45 | pub data: Option, 46 | // 47 | // The fields below are disabled until required. 48 | // 49 | // pub provider: String, 50 | // pub website: String, 51 | // pub explorer: String, 52 | } 53 | 54 | /// Deserializes a chain ID into a chain name. 55 | /// 56 | /// ### Arguments 57 | /// * `deserializer` - The deserializer used to deserialize the chain ID,serde in this case. 58 | /// 59 | /// ### Returns 60 | /// The chain name corresponding to the deserialized chain ID. 61 | pub fn deserialize_chain_id_to_name<'de, D>(deserializer: D) -> Result 62 | where 63 | D: Deserializer<'de>, 64 | { 65 | let chain_id: String = Deserialize::deserialize(deserializer)?; 66 | let chain_id: u64 = chain_id.parse().unwrap_or_default(); 67 | Ok(Network::name_from_chain_id(chain_id)) 68 | } 69 | 70 | /// Deserializes a string into a f32. The fields utilizing this deserialization function 71 | /// will be Strings, since they received from an SSE event in a JSON form. 72 | /// We're parsing it into a f32 to be able to work with the values before displaying them. 73 | /// 74 | /// ### Arguments 75 | /// * `deserializer` - The deserializer used to deserialize the value, serde in this case. 76 | /// 77 | /// ### Returns 78 | /// The f32 value of the deserialized string. 79 | pub fn deserialize_string_to_f32<'de, D>(deserializer: D) -> Result 80 | where 81 | D: Deserializer<'de>, 82 | { 83 | let value: String = Deserialize::deserialize(deserializer)?; 84 | Ok(value.parse().unwrap_or_default()) 85 | } 86 | 87 | impl Network { 88 | /// A new instance of `Network` with the provided parameters. 89 | pub fn new( 90 | name: String, 91 | label: String, 92 | parent_chain: String, 93 | da: String, 94 | stack: String, 95 | data: Option, 96 | ) -> Self { 97 | Self { 98 | name, 99 | label, 100 | parent_chain, 101 | da, 102 | stack, 103 | data, 104 | } 105 | } 106 | 107 | /// Updates the data associated with the network. 108 | /// 109 | /// ### Arguments 110 | /// * `data` - The new data of the network. 111 | pub fn update_data(&mut self, data: Option) { 112 | self.data = data; 113 | } 114 | 115 | /// {Unstable} Converts the network into a ratatui `Row` widget. 116 | /// It will get ownership of the data field before returning. 117 | /// 118 | /// ### Returns 119 | /// A `Row` widget containing the network's data in a formatted manner. 120 | pub fn to_row(&self) -> Row { 121 | let data = self.data.to_owned().unwrap_or_default(); 122 | Row::new(vec![ 123 | Text::raw(&self.label), 124 | Text::raw(data.block_number.to_string()), 125 | Text::raw(data.tps.to_string()), 126 | Text::raw(data.gps.to_string()), 127 | Text::raw(data.dps.to_string()), 128 | Text::raw(&self.stack), 129 | Text::raw(&self.da), 130 | Text::raw(&self.parent_chain), 131 | ]) 132 | } 133 | 134 | /// Returns the chain name based on the chain ID. 135 | /// 136 | /// ### Arguments 137 | /// * `id` - The chain ID. 138 | /// 139 | /// ### Returns 140 | /// The chain name corresponding to the chain ID, or "unknown" if the ID is not recognized or listed. 141 | fn name_from_chain_id(id: u64) -> String { 142 | match id { 143 | 1 => String::from("ethereum"), 144 | 8453 => String::from("base"), 145 | 42161 => String::from("arbitrum"), 146 | _ => String::from("unknown"), 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/terminal.rs: -------------------------------------------------------------------------------- 1 | use crossterm::{ 2 | event::DisableMouseCapture, 3 | execute, 4 | terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, 5 | }; 6 | use ratatui::backend::CrosstermBackend; 7 | use std::{ 8 | error::Error, 9 | io::Stdout, 10 | ops::{Deref, DerefMut}, 11 | }; 12 | 13 | /// The `Terminal` struct represents a terminal instance. 14 | /// 15 | /// It wraps the `ratatui::Terminal` with a `CrosstermBackend` and provides 16 | /// methods for entering and exiting the terminal mode. 17 | pub struct Terminal { 18 | /// The inner `ratatui::Terminal` instance with a `CrosstermBackend`. 19 | /// It implements the `Deref` and `DerefMut` which allow direct access to it. 20 | pub inner: ratatui::Terminal>, 21 | } 22 | 23 | impl Terminal { 24 | /// Enters the terminal mode and returns a new `Terminal` instance. 25 | /// 26 | /// By enabling the terminals behavior changes, 27 | /// you can find out more by following this [link](https://docs.rs/crossterm/latest/crossterm/terminal/index.html#raw-mode) 28 | /// 29 | /// We then instantiate a new `CrosstermBackend` with Stdout as a writer, `EnterAlternateScreen`, clean the screen and then return the Terminal instance. 30 | /// 31 | /// ### Returns 32 | /// A new instance of the `Terminal` struct, or an error if any part of the process fails. 33 | pub fn enter() -> Result> { 34 | // [link](https://docs.rs/crossterm/latest/crossterm/terminal/index.html#raw-mode) 35 | enable_raw_mode()?; 36 | let backend = CrosstermBackend::new(std::io::stdout()); 37 | let mut terminal = ratatui::Terminal::new(backend)?; 38 | execute!( 39 | terminal.backend_mut(), 40 | EnterAlternateScreen, 41 | DisableMouseCapture 42 | )?; 43 | 44 | terminal.clear()?; 45 | 46 | Ok(Self { inner: terminal }) 47 | } 48 | 49 | /// Exits the terminal mode and restores the previous terminal state. 50 | /// 51 | /// Reverts the changes made by `Self::enter`, clears the terminal and shows/resets the cursor to the top left corner. 52 | /// 53 | /// ### Returns 54 | /// An `Ok` result if the terminal was successfully exited or an error if any part of the process fails. 55 | pub fn exit(&mut self) -> Result<(), Box> { 56 | disable_raw_mode()?; 57 | execute!(self.backend_mut(), LeaveAlternateScreen,)?; 58 | self.clear()?; 59 | self.set_cursor(0, 0)?; 60 | self.show_cursor()?; 61 | 62 | Ok(()) 63 | } 64 | } 65 | 66 | /// Implements the `Deref` trait for `Terminal`. 67 | /// 68 | /// This allows dereferencing a `Terminal` instance to access the underlying 69 | /// `ratatui::Terminal>` methods and properties directly. 70 | impl Deref for Terminal { 71 | type Target = ratatui::Terminal>; 72 | 73 | fn deref(&self) -> &Self::Target { 74 | &self.inner 75 | } 76 | } 77 | 78 | /// Implements the `DerefMut` trait for `Terminal`. 79 | /// 80 | /// Mutably dereferencing a `Terminal` instance to access and modify the 81 | /// underlying `ratatui::Terminal>` methods and properties directly. 82 | impl DerefMut for Terminal { 83 | fn deref_mut(&mut self) -> &mut Self::Target { 84 | &mut self.inner 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/tui.rs: -------------------------------------------------------------------------------- 1 | use crate::{network::Data, Network}; 2 | use crossterm::event::KeyCode; 3 | use eventsource_client::Event; 4 | use ratatui::style::palette::tailwind::SLATE; 5 | use ratatui::{prelude::*, widgets::*}; 6 | 7 | /// Represents the sorting strategies for the network table, currently only `DESC`. 8 | #[derive(Debug, Default)] 9 | pub enum SortingStrategy { 10 | /// Sort by Gas Per Second (GPS). 11 | #[default] 12 | Gps, 13 | /// Sort by Transactions Per Second (TPS). 14 | Tps, 15 | /// Sort by Data Per Second (DPS). 16 | Dps, 17 | } 18 | 19 | // Currently since we're working with one screen, we can keep things more compact. 20 | // Later on we can split this struct into multiple ones. 21 | // 22 | /// Represents the Text-based User Interface (TUI) for displaying network information. 23 | pub struct Tui { 24 | /// The list of networks to display in the table. 25 | pub networks: Vec, 26 | /// {unstable} The current selection state of the table. 27 | pub selected: TableState, 28 | /// The current sorting strategy for the network table. GPS is default. 29 | pub sorting_strategy: SortingStrategy, 30 | /// Flag to check if the info bar has been rendered to avoid re-rendering. 31 | pub info_rendered: bool, 32 | } 33 | 34 | impl Tui { 35 | // Offload constant values to the struct, so they aren't computed on runtime. 36 | const TABLE_STYLE: Style = Style::new().fg(SLATE.c400); 37 | 38 | const TABLE_HIGHLIGHT_STYLE: Style = Style::new().bg(SLATE.c500).fg(SLATE.c900); 39 | 40 | const TABLE_WIDTHS: [Constraint; 8] = [ 41 | Constraint::Percentage(15), 42 | Constraint::Percentage(10), 43 | Constraint::Percentage(10), 44 | Constraint::Percentage(10), 45 | Constraint::Percentage(10), 46 | Constraint::Percentage(15), 47 | Constraint::Percentage(10), 48 | Constraint::Percentage(10), 49 | ]; 50 | 51 | /// Creates a new instance of the Tui. 52 | /// 53 | /// The Tui is initialized with the provided list of networks, an empty table selection state set to the first row, 54 | /// and the default sorting strategy (GPS). 55 | /// 56 | /// ### Arguments 57 | /// * `networks` - The list of networks to display in the table. 58 | /// 59 | /// ### Returns 60 | /// A new instance of the Tui. 61 | pub fn new(networks: Vec) -> Self { 62 | Self { 63 | networks, 64 | selected: TableState::new().with_selected(0), 65 | sorting_strategy: SortingStrategy::default(), 66 | info_rendered: false, 67 | } 68 | } 69 | 70 | /// Updates the networks data based on the incoming event. 71 | /// 72 | /// This method searches for the network in the `networks` list that matches the `event_type` 73 | /// of the incoming event.If a matching network is found, its data is updated with the data 74 | /// from the event. After updating the network data, the `sort_networks` method is called to 75 | /// re-sort the networks based on the current sorting strategy. 76 | /// 77 | /// A`HashMap` could be used for faster lookups, although in this case we'd have to `collect()` 78 | /// each time before rendering or sorting the networks. 79 | /// 80 | /// ### Arguments 81 | /// * `event` - The incoming SSE event containing the network data to update. 82 | pub fn update_networks(&mut self, event: Event) { 83 | if let Some(network) = self 84 | .networks 85 | .iter_mut() 86 | .find(|n| n.name == event.event_type) 87 | { 88 | // parse the string data into the Data struct 89 | let data = serde_json::from_str(&event.data).unwrap_or_default(); 90 | // and update the network 91 | network.update_data(data); 92 | } 93 | 94 | self.sort_networks(); 95 | } 96 | 97 | /// Sorts the networks based on the current sorting strategy. 98 | /// 99 | /// This method uses the `sort_by` function to sort the `networks` list based on the selected 100 | /// sorting strategy. The sorting is performed in descending order. 101 | fn sort_networks(&mut self) { 102 | self.networks.sort_by(|a, b| { 103 | let default = Data::default(); 104 | let a_data = a.data.as_ref().unwrap_or(&default); 105 | let b_data = b.data.as_ref().unwrap_or(&default); 106 | 107 | let (a, b) = match self.sorting_strategy { 108 | SortingStrategy::Gps => (a_data.gps, b_data.gps), 109 | SortingStrategy::Tps => (a_data.tps, b_data.tps), 110 | SortingStrategy::Dps => (a_data.dps, b_data.dps), 111 | }; 112 | 113 | b.partial_cmp(&a).unwrap_or(std::cmp::Ordering::Equal) 114 | }); 115 | } 116 | 117 | /// Handles user input related to the TUI functionality. 118 | /// The `char` 'q' is handled in the main loop for exiting.` 119 | /// 120 | /// This method responds to user input events to navigate the network table and change the 121 | /// sorting strategy. The supported navigation keys are: 122 | /// - Up arrow: Move the selection to the previous row. 123 | /// - Down arrow: Move the selection to the next row. 124 | /// 125 | /// The supported sorting strategy keys are: 126 | /// - 'g': Sort by Gas Per Second (GPS). 127 | /// - 't': Sort by Transactions Per Second (TPS). 128 | /// - 'k': Sort by Data Per Second (DPS). 129 | /// 130 | /// ### Arguments 131 | /// * `key` - The key code of the user input event. 132 | pub fn handle_input(&mut self, key: KeyCode) { 133 | if let Some(current) = self.selected.selected() { 134 | let network_size = self.networks.len().saturating_sub(1); 135 | match key { 136 | KeyCode::Up => { 137 | self.selected 138 | .select(Some(current.saturating_sub(1).min(network_size))); 139 | } 140 | KeyCode::Down => { 141 | self.selected 142 | .select(Some(current.saturating_add(1).min(network_size))); 143 | } 144 | KeyCode::Char('g') => { 145 | self.sorting_strategy = SortingStrategy::Gps; 146 | self.sort_networks(); 147 | } 148 | KeyCode::Char('t') => { 149 | self.sorting_strategy = SortingStrategy::Tps; 150 | self.sort_networks(); 151 | } 152 | KeyCode::Char('k') => { 153 | self.sorting_strategy = SortingStrategy::Dps; 154 | self.sort_networks(); 155 | } 156 | _ => {} 157 | } 158 | } 159 | } 160 | 161 | /// Renders the network table and the info using the provided `Frame`. 162 | /// The layout is split vertically into two chunks: the network table and the information bar. 163 | /// 164 | /// The network table displays the list of networks with their corresponding data while the 165 | /// information bar displays the available user actions, such as quitting the application 166 | /// and changing the sorting strategy. 167 | /// 168 | /// ### Arguments 169 | /// * `f` - The `Frame` to render the TUI. 170 | pub fn render(&mut self, f: &mut Frame) { 171 | // Create the main layout 172 | let chunks = Layout::default() 173 | .direction(Direction::Vertical) 174 | .constraints([Constraint::Percentage(100), Constraint::Min(3)]) 175 | .split(f.size()); 176 | 177 | // Split the layout into two chunks: the network table and the info bar 178 | let (network_layout, info_layout) = (chunks[0], chunks[1]); 179 | 180 | // Render the network table 181 | self.network_table(f, network_layout); 182 | self.render_info_bar(f, info_layout); 183 | } 184 | 185 | fn network_table(&mut self, f: &mut Frame, area: Rect) { 186 | // Create the network table block 187 | let network_block = Block::default() 188 | .borders(Borders::ALL) 189 | .style(Self::TABLE_STYLE) 190 | .border_type(BorderType::Rounded); 191 | 192 | // Generate and collect all rows for the network table 193 | let row_data = self.networks.iter().map(Network::to_row); 194 | 195 | // Initiate the Header row of the table 196 | let row_data_header = Row::new(vec![ 197 | Cell::from("Network"), 198 | Cell::from("Block"), 199 | Cell::from("TPS"), 200 | Cell::from("MGas/s"), 201 | Cell::from("KB/s"), 202 | Cell::from("Stack"), 203 | Cell::from("DA"), 204 | Cell::from("Settlement"), 205 | ]); 206 | 207 | // Create the table widget 208 | let table = Table::new(row_data, &Self::TABLE_WIDTHS) 209 | .block(network_block) 210 | .header(row_data_header) 211 | .highlight_style(Self::TABLE_HIGHLIGHT_STYLE) 212 | .highlight_symbol(">> "); 213 | 214 | // Render it with access to the state, which allows to move through entries 215 | f.render_stateful_widget(table, area, &mut self.selected); 216 | } 217 | 218 | fn render_info_bar(&self, f: &mut Frame, area: Rect) { 219 | // Create the info bar block 220 | let info_block = Block::default() 221 | .borders(Borders::ALL) 222 | .style(Self::TABLE_STYLE) 223 | .border_type(BorderType::Rounded); 224 | 225 | // Create the info bar text 226 | let info_text = Paragraph::new( 227 | "[q] quit | sort: ([g] gas per second | [t] txs per second [k] kb per second)", 228 | ) 229 | .alignment(Alignment::Center) 230 | .block(info_block); 231 | 232 | // Render the info bar 233 | f.render_widget(info_text, area); 234 | } 235 | } 236 | --------------------------------------------------------------------------------