├── .dockerignore ├── .github ├── FUNDING.yml ├── dependabot.yml └── workflows │ ├── dependabot_merge.yml │ ├── periodic.yml │ ├── regression.yml │ └── release.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── example └── prosafe_exporter.service └── src ├── exporter.rs ├── main.rs └── prosafe_switch.rs /.dockerignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | .git 4 | .github 5 | /example -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: dalance 4 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: cargo 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "20:00" 8 | open-pull-requests-limit: 10 9 | ignore: 10 | - dependency-name: combine 11 | versions: 12 | - ">= 4.4.a, < 4.5" 13 | - dependency-name: combine 14 | versions: 15 | - ">= 4.a, < 5" 16 | - dependency-name: hyper 17 | versions: 18 | - ">= 0.13.a, < 0.14" 19 | - dependency-name: hyper 20 | versions: 21 | - ">= 0.14.a, < 0.15" 22 | -------------------------------------------------------------------------------- /.github/workflows/dependabot_merge.yml: -------------------------------------------------------------------------------- 1 | name: Dependabot auto-merge 2 | on: pull_request_target 3 | 4 | permissions: 5 | pull-requests: write 6 | contents: write 7 | 8 | jobs: 9 | dependabot: 10 | runs-on: ubuntu-latest 11 | if: ${{ github.actor == 'dependabot[bot]' }} 12 | steps: 13 | - name: Dependabot metadata 14 | id: metadata 15 | uses: dependabot/fetch-metadata@v2.2.0 16 | with: 17 | github-token: '${{ secrets.GITHUB_TOKEN }}' 18 | - name: Enable auto-merge for Dependabot PRs 19 | if: ${{ steps.metadata.outputs.update-type == 'version-update:semver-patch' || ( !startsWith( steps.metadata.outputs.new-version, '0.' ) && steps.metadata.outputs.update-type == 'version-update:semver-minor' ) }} 20 | run: gh pr merge --auto --merge "$PR_URL" 21 | env: 22 | PR_URL: ${{github.event.pull_request.html_url}} 23 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 24 | -------------------------------------------------------------------------------- /.github/workflows/periodic.yml: -------------------------------------------------------------------------------- 1 | name: Periodic 2 | 3 | on: 4 | schedule: 5 | - cron: 0 0 * * SUN 6 | 7 | jobs: 8 | build: 9 | 10 | strategy: 11 | matrix: 12 | os: [ubuntu-latest] 13 | rust: [stable, beta, nightly] 14 | 15 | runs-on: ${{ matrix.os }} 16 | 17 | steps: 18 | - name: Setup Rust 19 | uses: hecrj/setup-rust-action@v1 20 | with: 21 | rust-version: ${{ matrix.rust }} 22 | - name: Checkout 23 | uses: actions/checkout@v2 24 | - name: Run tests 25 | run: cargo test 26 | -------------------------------------------------------------------------------- /.github/workflows/regression.yml: -------------------------------------------------------------------------------- 1 | name: Regression 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | build: 11 | 12 | strategy: 13 | matrix: 14 | os: [ubuntu-latest, macOS-latest] 15 | rust: [stable] 16 | 17 | runs-on: ${{ matrix.os }} 18 | 19 | steps: 20 | - name: Setup Rust 21 | uses: hecrj/setup-rust-action@v1 22 | with: 23 | rust-version: ${{ matrix.rust }} 24 | - name: Checkout 25 | uses: actions/checkout@v2 26 | - name: Run tests 27 | run: cargo test 28 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*.*.*' 7 | 8 | jobs: 9 | build: 10 | 11 | strategy: 12 | matrix: 13 | os: [ubuntu-latest, macOS-latest] 14 | rust: [stable] 15 | 16 | runs-on: ${{ matrix.os }} 17 | 18 | steps: 19 | - name: Setup Rust 20 | uses: hecrj/setup-rust-action@v1 21 | with: 22 | rust-version: ${{ matrix.rust }} 23 | - name: Checkout 24 | uses: actions/checkout@v2 25 | - name: Setup MUSL 26 | if: matrix.os == 'ubuntu-latest' 27 | run: | 28 | rustup target add x86_64-unknown-linux-musl 29 | sudo apt-get -qq install musl-tools 30 | - name: Build for linux 31 | if: matrix.os == 'ubuntu-latest' 32 | run: make release_lnx 33 | - name: Build for macOS 34 | if: matrix.os == 'macOS-latest' 35 | run: make release_mac 36 | - name: Build for Windows 37 | if: matrix.os == 'windows-latest' 38 | run: make release_win 39 | - name: Release 40 | uses: softprops/action-gh-release@v1 41 | with: 42 | files: '*.zip' 43 | env: 44 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 45 | build-and-push-docker: 46 | runs-on: ubuntu-latest 47 | 48 | permissions: 49 | contents: read 50 | packages: write 51 | 52 | steps: 53 | - name: Checkout code 54 | uses: actions/checkout@v3 55 | - name: Log in to GHCR 56 | uses: docker/login-action@v2 57 | with: 58 | registry: ghcr.io 59 | username: ${{ github.actor }} 60 | password: ${{ secrets.GHCR_TOKEN }} 61 | - name: Extract tag version 62 | id: get_version 63 | run: echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV 64 | - name: Build and tag Docker image 65 | run: | 66 | IMAGE_NAME=ghcr.io/${{ github.repository_owner }}/prosafe_exporter 67 | VERSION_TAG=${{ env.version }} 68 | 69 | echo "Building Docker image with tags: ${VERSION_TAG} and latest" 70 | docker build -t $IMAGE_NAME:$VERSION_TAG -t $IMAGE_NAME:latest . 71 | - name: Push Docker image to GHCR 72 | run: | 73 | IMAGE_NAME=ghcr.io/${{ github.repository_owner }}/prosafe_exporter 74 | VERSION_TAG=${{ env.version }} 75 | 76 | echo "Pushing Docker image tags: ${VERSION_TAG} and latest" 77 | docker push $IMAGE_NAME:$VERSION_TAG 78 | docker push $IMAGE_NAME:latest 79 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | -------------------------------------------------------------------------------- /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.24.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler2" 16 | version = "2.0.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 19 | 20 | [[package]] 21 | name = "ansi_term" 22 | version = "0.12.1" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" 25 | dependencies = [ 26 | "winapi 0.3.9", 27 | ] 28 | 29 | [[package]] 30 | name = "ascii" 31 | version = "0.9.3" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" 34 | 35 | [[package]] 36 | name = "atty" 37 | version = "0.2.14" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 40 | dependencies = [ 41 | "hermit-abi 0.1.19", 42 | "libc", 43 | "winapi 0.3.9", 44 | ] 45 | 46 | [[package]] 47 | name = "autocfg" 48 | version = "1.4.0" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 51 | 52 | [[package]] 53 | name = "backtrace" 54 | version = "0.3.74" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" 57 | dependencies = [ 58 | "addr2line", 59 | "cfg-if 1.0.0", 60 | "libc", 61 | "miniz_oxide", 62 | "object", 63 | "rustc-demangle", 64 | "windows-targets", 65 | ] 66 | 67 | [[package]] 68 | name = "bincode" 69 | version = "1.3.3" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" 72 | dependencies = [ 73 | "serde", 74 | ] 75 | 76 | [[package]] 77 | name = "bitflags" 78 | version = "1.3.2" 79 | source = "registry+https://github.com/rust-lang/crates.io-index" 80 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 81 | 82 | [[package]] 83 | name = "bitflags" 84 | version = "2.6.0" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 87 | 88 | [[package]] 89 | name = "block-buffer" 90 | version = "0.10.4" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 93 | dependencies = [ 94 | "generic-array", 95 | ] 96 | 97 | [[package]] 98 | name = "byteorder" 99 | version = "1.5.0" 100 | source = "registry+https://github.com/rust-lang/crates.io-index" 101 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 102 | 103 | [[package]] 104 | name = "bytes" 105 | version = "0.4.12" 106 | source = "registry+https://github.com/rust-lang/crates.io-index" 107 | checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" 108 | dependencies = [ 109 | "byteorder", 110 | "either", 111 | "iovec", 112 | ] 113 | 114 | [[package]] 115 | name = "cc" 116 | version = "1.2.4" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" 119 | dependencies = [ 120 | "shlex", 121 | ] 122 | 123 | [[package]] 124 | name = "cfg-if" 125 | version = "0.1.10" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 128 | 129 | [[package]] 130 | name = "cfg-if" 131 | version = "1.0.0" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 134 | 135 | [[package]] 136 | name = "clap" 137 | version = "2.34.0" 138 | source = "registry+https://github.com/rust-lang/crates.io-index" 139 | checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" 140 | dependencies = [ 141 | "ansi_term", 142 | "atty", 143 | "bitflags 1.3.2", 144 | "strsim", 145 | "textwrap", 146 | "unicode-width", 147 | "vec_map", 148 | ] 149 | 150 | [[package]] 151 | name = "cloudabi" 152 | version = "0.0.3" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" 155 | dependencies = [ 156 | "bitflags 1.3.2", 157 | ] 158 | 159 | [[package]] 160 | name = "combine" 161 | version = "3.8.1" 162 | source = "registry+https://github.com/rust-lang/crates.io-index" 163 | checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" 164 | dependencies = [ 165 | "ascii", 166 | "byteorder", 167 | "either", 168 | "memchr", 169 | "unreachable", 170 | ] 171 | 172 | [[package]] 173 | name = "cpufeatures" 174 | version = "0.2.16" 175 | source = "registry+https://github.com/rust-lang/crates.io-index" 176 | checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" 177 | dependencies = [ 178 | "libc", 179 | ] 180 | 181 | [[package]] 182 | name = "crossbeam-deque" 183 | version = "0.7.4" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "c20ff29ded3204c5106278a81a38f4b482636ed4fa1e6cfbeef193291beb29ed" 186 | dependencies = [ 187 | "crossbeam-epoch", 188 | "crossbeam-utils", 189 | "maybe-uninit", 190 | ] 191 | 192 | [[package]] 193 | name = "crossbeam-epoch" 194 | version = "0.8.2" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" 197 | dependencies = [ 198 | "autocfg", 199 | "cfg-if 0.1.10", 200 | "crossbeam-utils", 201 | "lazy_static", 202 | "maybe-uninit", 203 | "memoffset 0.5.6", 204 | "scopeguard", 205 | ] 206 | 207 | [[package]] 208 | name = "crossbeam-queue" 209 | version = "0.2.3" 210 | source = "registry+https://github.com/rust-lang/crates.io-index" 211 | checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" 212 | dependencies = [ 213 | "cfg-if 0.1.10", 214 | "crossbeam-utils", 215 | "maybe-uninit", 216 | ] 217 | 218 | [[package]] 219 | name = "crossbeam-utils" 220 | version = "0.7.2" 221 | source = "registry+https://github.com/rust-lang/crates.io-index" 222 | checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" 223 | dependencies = [ 224 | "autocfg", 225 | "cfg-if 0.1.10", 226 | "lazy_static", 227 | ] 228 | 229 | [[package]] 230 | name = "crypto-common" 231 | version = "0.1.6" 232 | source = "registry+https://github.com/rust-lang/crates.io-index" 233 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 234 | dependencies = [ 235 | "generic-array", 236 | "typenum", 237 | ] 238 | 239 | [[package]] 240 | name = "digest" 241 | version = "0.10.7" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 244 | dependencies = [ 245 | "block-buffer", 246 | "crypto-common", 247 | ] 248 | 249 | [[package]] 250 | name = "displaydoc" 251 | version = "0.2.5" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 254 | dependencies = [ 255 | "proc-macro2", 256 | "quote", 257 | "syn 2.0.90", 258 | ] 259 | 260 | [[package]] 261 | name = "either" 262 | version = "1.13.0" 263 | source = "registry+https://github.com/rust-lang/crates.io-index" 264 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 265 | 266 | [[package]] 267 | name = "equivalent" 268 | version = "1.0.1" 269 | source = "registry+https://github.com/rust-lang/crates.io-index" 270 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 271 | 272 | [[package]] 273 | name = "failure" 274 | version = "0.1.8" 275 | source = "registry+https://github.com/rust-lang/crates.io-index" 276 | checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" 277 | dependencies = [ 278 | "backtrace", 279 | "failure_derive", 280 | ] 281 | 282 | [[package]] 283 | name = "failure_derive" 284 | version = "0.1.8" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" 287 | dependencies = [ 288 | "proc-macro2", 289 | "quote", 290 | "syn 1.0.109", 291 | "synstructure 0.12.6", 292 | ] 293 | 294 | [[package]] 295 | name = "fnv" 296 | version = "1.0.7" 297 | source = "registry+https://github.com/rust-lang/crates.io-index" 298 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 299 | 300 | [[package]] 301 | name = "form_urlencoded" 302 | version = "1.2.1" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 305 | dependencies = [ 306 | "percent-encoding", 307 | ] 308 | 309 | [[package]] 310 | name = "fuchsia-zircon" 311 | version = "0.3.3" 312 | source = "registry+https://github.com/rust-lang/crates.io-index" 313 | checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" 314 | dependencies = [ 315 | "bitflags 1.3.2", 316 | "fuchsia-zircon-sys", 317 | ] 318 | 319 | [[package]] 320 | name = "fuchsia-zircon-sys" 321 | version = "0.3.3" 322 | source = "registry+https://github.com/rust-lang/crates.io-index" 323 | checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" 324 | 325 | [[package]] 326 | name = "futures" 327 | version = "0.1.31" 328 | source = "registry+https://github.com/rust-lang/crates.io-index" 329 | checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" 330 | 331 | [[package]] 332 | name = "futures-cpupool" 333 | version = "0.1.8" 334 | source = "registry+https://github.com/rust-lang/crates.io-index" 335 | checksum = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" 336 | dependencies = [ 337 | "futures", 338 | "num_cpus", 339 | ] 340 | 341 | [[package]] 342 | name = "generic-array" 343 | version = "0.14.7" 344 | source = "registry+https://github.com/rust-lang/crates.io-index" 345 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 346 | dependencies = [ 347 | "typenum", 348 | "version_check", 349 | ] 350 | 351 | [[package]] 352 | name = "getrandom" 353 | version = "0.3.0" 354 | source = "registry+https://github.com/rust-lang/crates.io-index" 355 | checksum = "71393ecc86efbf00e4ca13953979ba8b94cfe549a4b74cc26d8b62f4d8feac2b" 356 | dependencies = [ 357 | "cfg-if 1.0.0", 358 | "libc", 359 | "wasi 0.13.3+wasi-0.2.2", 360 | "windows-targets", 361 | ] 362 | 363 | [[package]] 364 | name = "gimli" 365 | version = "0.31.1" 366 | source = "registry+https://github.com/rust-lang/crates.io-index" 367 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 368 | 369 | [[package]] 370 | name = "h2" 371 | version = "0.1.26" 372 | source = "registry+https://github.com/rust-lang/crates.io-index" 373 | checksum = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" 374 | dependencies = [ 375 | "byteorder", 376 | "bytes", 377 | "fnv", 378 | "futures", 379 | "http", 380 | "indexmap 1.9.3", 381 | "log", 382 | "slab", 383 | "string", 384 | "tokio-io", 385 | ] 386 | 387 | [[package]] 388 | name = "handlebars" 389 | version = "3.5.5" 390 | source = "registry+https://github.com/rust-lang/crates.io-index" 391 | checksum = "4498fc115fa7d34de968184e473529abb40eeb6be8bc5f7faba3d08c316cb3e3" 392 | dependencies = [ 393 | "log", 394 | "pest", 395 | "pest_derive", 396 | "quick-error", 397 | "serde", 398 | "serde_json", 399 | ] 400 | 401 | [[package]] 402 | name = "hashbrown" 403 | version = "0.12.3" 404 | source = "registry+https://github.com/rust-lang/crates.io-index" 405 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 406 | 407 | [[package]] 408 | name = "hashbrown" 409 | version = "0.15.2" 410 | source = "registry+https://github.com/rust-lang/crates.io-index" 411 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 412 | 413 | [[package]] 414 | name = "heck" 415 | version = "0.3.3" 416 | source = "registry+https://github.com/rust-lang/crates.io-index" 417 | checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" 418 | dependencies = [ 419 | "unicode-segmentation", 420 | ] 421 | 422 | [[package]] 423 | name = "hermit-abi" 424 | version = "0.1.19" 425 | source = "registry+https://github.com/rust-lang/crates.io-index" 426 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 427 | dependencies = [ 428 | "libc", 429 | ] 430 | 431 | [[package]] 432 | name = "hermit-abi" 433 | version = "0.3.9" 434 | source = "registry+https://github.com/rust-lang/crates.io-index" 435 | checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" 436 | 437 | [[package]] 438 | name = "hex-literal" 439 | version = "1.0.0" 440 | source = "registry+https://github.com/rust-lang/crates.io-index" 441 | checksum = "bcaaec4551594c969335c98c903c1397853d4198408ea609190f420500f6be71" 442 | 443 | [[package]] 444 | name = "http" 445 | version = "0.1.21" 446 | source = "registry+https://github.com/rust-lang/crates.io-index" 447 | checksum = "d6ccf5ede3a895d8856620237b2f02972c1bbc78d2965ad7fe8838d4a0ed41f0" 448 | dependencies = [ 449 | "bytes", 450 | "fnv", 451 | "itoa 0.4.8", 452 | ] 453 | 454 | [[package]] 455 | name = "http-body" 456 | version = "0.1.0" 457 | source = "registry+https://github.com/rust-lang/crates.io-index" 458 | checksum = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" 459 | dependencies = [ 460 | "bytes", 461 | "futures", 462 | "http", 463 | "tokio-buf", 464 | ] 465 | 466 | [[package]] 467 | name = "httparse" 468 | version = "1.9.5" 469 | source = "registry+https://github.com/rust-lang/crates.io-index" 470 | checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" 471 | 472 | [[package]] 473 | name = "hyper" 474 | version = "0.12.36" 475 | source = "registry+https://github.com/rust-lang/crates.io-index" 476 | checksum = "5c843caf6296fc1f93444735205af9ed4e109a539005abb2564ae1d6fad34c52" 477 | dependencies = [ 478 | "bytes", 479 | "futures", 480 | "futures-cpupool", 481 | "h2", 482 | "http", 483 | "http-body", 484 | "httparse", 485 | "iovec", 486 | "itoa 0.4.8", 487 | "log", 488 | "net2", 489 | "rustc_version", 490 | "time", 491 | "tokio", 492 | "tokio-buf", 493 | "tokio-executor", 494 | "tokio-io", 495 | "tokio-reactor", 496 | "tokio-tcp", 497 | "tokio-threadpool", 498 | "tokio-timer", 499 | "want", 500 | ] 501 | 502 | [[package]] 503 | name = "icu_collections" 504 | version = "1.5.0" 505 | source = "registry+https://github.com/rust-lang/crates.io-index" 506 | checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" 507 | dependencies = [ 508 | "displaydoc", 509 | "yoke", 510 | "zerofrom", 511 | "zerovec", 512 | ] 513 | 514 | [[package]] 515 | name = "icu_locid" 516 | version = "1.5.0" 517 | source = "registry+https://github.com/rust-lang/crates.io-index" 518 | checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" 519 | dependencies = [ 520 | "displaydoc", 521 | "litemap", 522 | "tinystr", 523 | "writeable", 524 | "zerovec", 525 | ] 526 | 527 | [[package]] 528 | name = "icu_locid_transform" 529 | version = "1.5.0" 530 | source = "registry+https://github.com/rust-lang/crates.io-index" 531 | checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" 532 | dependencies = [ 533 | "displaydoc", 534 | "icu_locid", 535 | "icu_locid_transform_data", 536 | "icu_provider", 537 | "tinystr", 538 | "zerovec", 539 | ] 540 | 541 | [[package]] 542 | name = "icu_locid_transform_data" 543 | version = "1.5.0" 544 | source = "registry+https://github.com/rust-lang/crates.io-index" 545 | checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" 546 | 547 | [[package]] 548 | name = "icu_normalizer" 549 | version = "1.5.0" 550 | source = "registry+https://github.com/rust-lang/crates.io-index" 551 | checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" 552 | dependencies = [ 553 | "displaydoc", 554 | "icu_collections", 555 | "icu_normalizer_data", 556 | "icu_properties", 557 | "icu_provider", 558 | "smallvec 1.13.2", 559 | "utf16_iter", 560 | "utf8_iter", 561 | "write16", 562 | "zerovec", 563 | ] 564 | 565 | [[package]] 566 | name = "icu_normalizer_data" 567 | version = "1.5.0" 568 | source = "registry+https://github.com/rust-lang/crates.io-index" 569 | checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" 570 | 571 | [[package]] 572 | name = "icu_properties" 573 | version = "1.5.1" 574 | source = "registry+https://github.com/rust-lang/crates.io-index" 575 | checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" 576 | dependencies = [ 577 | "displaydoc", 578 | "icu_collections", 579 | "icu_locid_transform", 580 | "icu_properties_data", 581 | "icu_provider", 582 | "tinystr", 583 | "zerovec", 584 | ] 585 | 586 | [[package]] 587 | name = "icu_properties_data" 588 | version = "1.5.0" 589 | source = "registry+https://github.com/rust-lang/crates.io-index" 590 | checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" 591 | 592 | [[package]] 593 | name = "icu_provider" 594 | version = "1.5.0" 595 | source = "registry+https://github.com/rust-lang/crates.io-index" 596 | checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" 597 | dependencies = [ 598 | "displaydoc", 599 | "icu_locid", 600 | "icu_provider_macros", 601 | "stable_deref_trait", 602 | "tinystr", 603 | "writeable", 604 | "yoke", 605 | "zerofrom", 606 | "zerovec", 607 | ] 608 | 609 | [[package]] 610 | name = "icu_provider_macros" 611 | version = "1.5.0" 612 | source = "registry+https://github.com/rust-lang/crates.io-index" 613 | checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" 614 | dependencies = [ 615 | "proc-macro2", 616 | "quote", 617 | "syn 2.0.90", 618 | ] 619 | 620 | [[package]] 621 | name = "idna" 622 | version = "1.0.3" 623 | source = "registry+https://github.com/rust-lang/crates.io-index" 624 | checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" 625 | dependencies = [ 626 | "idna_adapter", 627 | "smallvec 1.13.2", 628 | "utf8_iter", 629 | ] 630 | 631 | [[package]] 632 | name = "idna_adapter" 633 | version = "1.2.0" 634 | source = "registry+https://github.com/rust-lang/crates.io-index" 635 | checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" 636 | dependencies = [ 637 | "icu_normalizer", 638 | "icu_properties", 639 | ] 640 | 641 | [[package]] 642 | name = "indexmap" 643 | version = "1.9.3" 644 | source = "registry+https://github.com/rust-lang/crates.io-index" 645 | checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" 646 | dependencies = [ 647 | "autocfg", 648 | "hashbrown 0.12.3", 649 | ] 650 | 651 | [[package]] 652 | name = "indexmap" 653 | version = "2.7.0" 654 | source = "registry+https://github.com/rust-lang/crates.io-index" 655 | checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" 656 | dependencies = [ 657 | "equivalent", 658 | "hashbrown 0.15.2", 659 | ] 660 | 661 | [[package]] 662 | name = "interfaces" 663 | version = "0.0.9" 664 | source = "registry+https://github.com/rust-lang/crates.io-index" 665 | checksum = "bb6250a98af259a26fd5a4a6081fccea9ac116e4c3178acf4aeb86d32d2b7715" 666 | dependencies = [ 667 | "bitflags 2.6.0", 668 | "cc", 669 | "handlebars", 670 | "lazy_static", 671 | "libc", 672 | "nix", 673 | "serde", 674 | "serde_derive", 675 | ] 676 | 677 | [[package]] 678 | name = "iovec" 679 | version = "0.1.4" 680 | source = "registry+https://github.com/rust-lang/crates.io-index" 681 | checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" 682 | dependencies = [ 683 | "libc", 684 | ] 685 | 686 | [[package]] 687 | name = "itoa" 688 | version = "0.4.8" 689 | source = "registry+https://github.com/rust-lang/crates.io-index" 690 | checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" 691 | 692 | [[package]] 693 | name = "itoa" 694 | version = "1.0.14" 695 | source = "registry+https://github.com/rust-lang/crates.io-index" 696 | checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" 697 | 698 | [[package]] 699 | name = "kernel32-sys" 700 | version = "0.2.2" 701 | source = "registry+https://github.com/rust-lang/crates.io-index" 702 | checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" 703 | dependencies = [ 704 | "winapi 0.2.8", 705 | "winapi-build", 706 | ] 707 | 708 | [[package]] 709 | name = "lazy_static" 710 | version = "1.5.0" 711 | source = "registry+https://github.com/rust-lang/crates.io-index" 712 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 713 | 714 | [[package]] 715 | name = "libc" 716 | version = "0.2.168" 717 | source = "registry+https://github.com/rust-lang/crates.io-index" 718 | checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" 719 | 720 | [[package]] 721 | name = "litemap" 722 | version = "0.7.4" 723 | source = "registry+https://github.com/rust-lang/crates.io-index" 724 | checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" 725 | 726 | [[package]] 727 | name = "lock_api" 728 | version = "0.3.4" 729 | source = "registry+https://github.com/rust-lang/crates.io-index" 730 | checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" 731 | dependencies = [ 732 | "scopeguard", 733 | ] 734 | 735 | [[package]] 736 | name = "lock_api" 737 | version = "0.4.12" 738 | source = "registry+https://github.com/rust-lang/crates.io-index" 739 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 740 | dependencies = [ 741 | "autocfg", 742 | "scopeguard", 743 | ] 744 | 745 | [[package]] 746 | name = "log" 747 | version = "0.4.22" 748 | source = "registry+https://github.com/rust-lang/crates.io-index" 749 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 750 | 751 | [[package]] 752 | name = "maybe-uninit" 753 | version = "2.0.0" 754 | source = "registry+https://github.com/rust-lang/crates.io-index" 755 | checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" 756 | 757 | [[package]] 758 | name = "memchr" 759 | version = "2.7.4" 760 | source = "registry+https://github.com/rust-lang/crates.io-index" 761 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 762 | 763 | [[package]] 764 | name = "memoffset" 765 | version = "0.5.6" 766 | source = "registry+https://github.com/rust-lang/crates.io-index" 767 | checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" 768 | dependencies = [ 769 | "autocfg", 770 | ] 771 | 772 | [[package]] 773 | name = "memoffset" 774 | version = "0.7.1" 775 | source = "registry+https://github.com/rust-lang/crates.io-index" 776 | checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" 777 | dependencies = [ 778 | "autocfg", 779 | ] 780 | 781 | [[package]] 782 | name = "miniz_oxide" 783 | version = "0.8.0" 784 | source = "registry+https://github.com/rust-lang/crates.io-index" 785 | checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" 786 | dependencies = [ 787 | "adler2", 788 | ] 789 | 790 | [[package]] 791 | name = "mio" 792 | version = "0.6.23" 793 | source = "registry+https://github.com/rust-lang/crates.io-index" 794 | checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" 795 | dependencies = [ 796 | "cfg-if 0.1.10", 797 | "fuchsia-zircon", 798 | "fuchsia-zircon-sys", 799 | "iovec", 800 | "kernel32-sys", 801 | "libc", 802 | "log", 803 | "miow", 804 | "net2", 805 | "slab", 806 | "winapi 0.2.8", 807 | ] 808 | 809 | [[package]] 810 | name = "miow" 811 | version = "0.2.2" 812 | source = "registry+https://github.com/rust-lang/crates.io-index" 813 | checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" 814 | dependencies = [ 815 | "kernel32-sys", 816 | "net2", 817 | "winapi 0.2.8", 818 | "ws2_32-sys", 819 | ] 820 | 821 | [[package]] 822 | name = "net2" 823 | version = "0.2.39" 824 | source = "registry+https://github.com/rust-lang/crates.io-index" 825 | checksum = "b13b648036a2339d06de780866fbdfda0dde886de7b3af2ddeba8b14f4ee34ac" 826 | dependencies = [ 827 | "cfg-if 0.1.10", 828 | "libc", 829 | "winapi 0.3.9", 830 | ] 831 | 832 | [[package]] 833 | name = "nix" 834 | version = "0.26.4" 835 | source = "registry+https://github.com/rust-lang/crates.io-index" 836 | checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" 837 | dependencies = [ 838 | "bitflags 1.3.2", 839 | "cfg-if 1.0.0", 840 | "libc", 841 | "memoffset 0.7.1", 842 | "pin-utils", 843 | ] 844 | 845 | [[package]] 846 | name = "num_cpus" 847 | version = "1.16.0" 848 | source = "registry+https://github.com/rust-lang/crates.io-index" 849 | checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" 850 | dependencies = [ 851 | "hermit-abi 0.3.9", 852 | "libc", 853 | ] 854 | 855 | [[package]] 856 | name = "object" 857 | version = "0.36.5" 858 | source = "registry+https://github.com/rust-lang/crates.io-index" 859 | checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" 860 | dependencies = [ 861 | "memchr", 862 | ] 863 | 864 | [[package]] 865 | name = "once_cell" 866 | version = "1.20.2" 867 | source = "registry+https://github.com/rust-lang/crates.io-index" 868 | checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" 869 | 870 | [[package]] 871 | name = "parking_lot" 872 | version = "0.9.0" 873 | source = "registry+https://github.com/rust-lang/crates.io-index" 874 | checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" 875 | dependencies = [ 876 | "lock_api 0.3.4", 877 | "parking_lot_core 0.6.3", 878 | "rustc_version", 879 | ] 880 | 881 | [[package]] 882 | name = "parking_lot" 883 | version = "0.12.3" 884 | source = "registry+https://github.com/rust-lang/crates.io-index" 885 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 886 | dependencies = [ 887 | "lock_api 0.4.12", 888 | "parking_lot_core 0.9.10", 889 | ] 890 | 891 | [[package]] 892 | name = "parking_lot_core" 893 | version = "0.6.3" 894 | source = "registry+https://github.com/rust-lang/crates.io-index" 895 | checksum = "bda66b810a62be75176a80873726630147a5ca780cd33921e0b5709033e66b0a" 896 | dependencies = [ 897 | "cfg-if 0.1.10", 898 | "cloudabi", 899 | "libc", 900 | "redox_syscall 0.1.57", 901 | "rustc_version", 902 | "smallvec 0.6.14", 903 | "winapi 0.3.9", 904 | ] 905 | 906 | [[package]] 907 | name = "parking_lot_core" 908 | version = "0.9.10" 909 | source = "registry+https://github.com/rust-lang/crates.io-index" 910 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 911 | dependencies = [ 912 | "cfg-if 1.0.0", 913 | "libc", 914 | "redox_syscall 0.5.8", 915 | "smallvec 1.13.2", 916 | "windows-targets", 917 | ] 918 | 919 | [[package]] 920 | name = "percent-encoding" 921 | version = "2.3.1" 922 | source = "registry+https://github.com/rust-lang/crates.io-index" 923 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 924 | 925 | [[package]] 926 | name = "pest" 927 | version = "2.7.15" 928 | source = "registry+https://github.com/rust-lang/crates.io-index" 929 | checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" 930 | dependencies = [ 931 | "memchr", 932 | "thiserror 2.0.7", 933 | "ucd-trie", 934 | ] 935 | 936 | [[package]] 937 | name = "pest_derive" 938 | version = "2.7.15" 939 | source = "registry+https://github.com/rust-lang/crates.io-index" 940 | checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e" 941 | dependencies = [ 942 | "pest", 943 | "pest_generator", 944 | ] 945 | 946 | [[package]] 947 | name = "pest_generator" 948 | version = "2.7.15" 949 | source = "registry+https://github.com/rust-lang/crates.io-index" 950 | checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b" 951 | dependencies = [ 952 | "pest", 953 | "pest_meta", 954 | "proc-macro2", 955 | "quote", 956 | "syn 2.0.90", 957 | ] 958 | 959 | [[package]] 960 | name = "pest_meta" 961 | version = "2.7.15" 962 | source = "registry+https://github.com/rust-lang/crates.io-index" 963 | checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea" 964 | dependencies = [ 965 | "once_cell", 966 | "pest", 967 | "sha2", 968 | ] 969 | 970 | [[package]] 971 | name = "pin-utils" 972 | version = "0.1.0" 973 | source = "registry+https://github.com/rust-lang/crates.io-index" 974 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 975 | 976 | [[package]] 977 | name = "ppv-lite86" 978 | version = "0.2.20" 979 | source = "registry+https://github.com/rust-lang/crates.io-index" 980 | checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" 981 | dependencies = [ 982 | "zerocopy 0.7.35", 983 | ] 984 | 985 | [[package]] 986 | name = "proc-macro-error" 987 | version = "1.0.4" 988 | source = "registry+https://github.com/rust-lang/crates.io-index" 989 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 990 | dependencies = [ 991 | "proc-macro-error-attr", 992 | "proc-macro2", 993 | "quote", 994 | "syn 1.0.109", 995 | "version_check", 996 | ] 997 | 998 | [[package]] 999 | name = "proc-macro-error-attr" 1000 | version = "1.0.4" 1001 | source = "registry+https://github.com/rust-lang/crates.io-index" 1002 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 1003 | dependencies = [ 1004 | "proc-macro2", 1005 | "quote", 1006 | "version_check", 1007 | ] 1008 | 1009 | [[package]] 1010 | name = "proc-macro2" 1011 | version = "1.0.92" 1012 | source = "registry+https://github.com/rust-lang/crates.io-index" 1013 | checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" 1014 | dependencies = [ 1015 | "unicode-ident", 1016 | ] 1017 | 1018 | [[package]] 1019 | name = "prometheus" 1020 | version = "0.13.4" 1021 | source = "registry+https://github.com/rust-lang/crates.io-index" 1022 | checksum = "3d33c28a30771f7f96db69893f78b857f7450d7e0237e9c8fc6427a81bae7ed1" 1023 | dependencies = [ 1024 | "cfg-if 1.0.0", 1025 | "fnv", 1026 | "lazy_static", 1027 | "memchr", 1028 | "parking_lot 0.12.3", 1029 | "protobuf", 1030 | "thiserror 1.0.69", 1031 | ] 1032 | 1033 | [[package]] 1034 | name = "prosafe_exporter" 1035 | version = "0.2.9" 1036 | dependencies = [ 1037 | "bincode", 1038 | "combine", 1039 | "failure", 1040 | "hex-literal", 1041 | "hyper", 1042 | "interfaces", 1043 | "lazy_static", 1044 | "prometheus", 1045 | "rand", 1046 | "serde", 1047 | "structopt", 1048 | "toml", 1049 | "url", 1050 | ] 1051 | 1052 | [[package]] 1053 | name = "protobuf" 1054 | version = "2.28.0" 1055 | source = "registry+https://github.com/rust-lang/crates.io-index" 1056 | checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" 1057 | 1058 | [[package]] 1059 | name = "quick-error" 1060 | version = "2.0.1" 1061 | source = "registry+https://github.com/rust-lang/crates.io-index" 1062 | checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" 1063 | 1064 | [[package]] 1065 | name = "quote" 1066 | version = "1.0.37" 1067 | source = "registry+https://github.com/rust-lang/crates.io-index" 1068 | checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" 1069 | dependencies = [ 1070 | "proc-macro2", 1071 | ] 1072 | 1073 | [[package]] 1074 | name = "rand" 1075 | version = "0.9.1" 1076 | source = "registry+https://github.com/rust-lang/crates.io-index" 1077 | checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" 1078 | dependencies = [ 1079 | "rand_chacha", 1080 | "rand_core", 1081 | ] 1082 | 1083 | [[package]] 1084 | name = "rand_chacha" 1085 | version = "0.9.0" 1086 | source = "registry+https://github.com/rust-lang/crates.io-index" 1087 | checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" 1088 | dependencies = [ 1089 | "ppv-lite86", 1090 | "rand_core", 1091 | ] 1092 | 1093 | [[package]] 1094 | name = "rand_core" 1095 | version = "0.9.0" 1096 | source = "registry+https://github.com/rust-lang/crates.io-index" 1097 | checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff" 1098 | dependencies = [ 1099 | "getrandom", 1100 | "zerocopy 0.8.14", 1101 | ] 1102 | 1103 | [[package]] 1104 | name = "redox_syscall" 1105 | version = "0.1.57" 1106 | source = "registry+https://github.com/rust-lang/crates.io-index" 1107 | checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" 1108 | 1109 | [[package]] 1110 | name = "redox_syscall" 1111 | version = "0.5.8" 1112 | source = "registry+https://github.com/rust-lang/crates.io-index" 1113 | checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" 1114 | dependencies = [ 1115 | "bitflags 2.6.0", 1116 | ] 1117 | 1118 | [[package]] 1119 | name = "rustc-demangle" 1120 | version = "0.1.24" 1121 | source = "registry+https://github.com/rust-lang/crates.io-index" 1122 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 1123 | 1124 | [[package]] 1125 | name = "rustc_version" 1126 | version = "0.2.3" 1127 | source = "registry+https://github.com/rust-lang/crates.io-index" 1128 | checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 1129 | dependencies = [ 1130 | "semver", 1131 | ] 1132 | 1133 | [[package]] 1134 | name = "ryu" 1135 | version = "1.0.18" 1136 | source = "registry+https://github.com/rust-lang/crates.io-index" 1137 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 1138 | 1139 | [[package]] 1140 | name = "scopeguard" 1141 | version = "1.2.0" 1142 | source = "registry+https://github.com/rust-lang/crates.io-index" 1143 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1144 | 1145 | [[package]] 1146 | name = "semver" 1147 | version = "0.9.0" 1148 | source = "registry+https://github.com/rust-lang/crates.io-index" 1149 | checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 1150 | dependencies = [ 1151 | "semver-parser", 1152 | ] 1153 | 1154 | [[package]] 1155 | name = "semver-parser" 1156 | version = "0.7.0" 1157 | source = "registry+https://github.com/rust-lang/crates.io-index" 1158 | checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 1159 | 1160 | [[package]] 1161 | name = "serde" 1162 | version = "1.0.219" 1163 | source = "registry+https://github.com/rust-lang/crates.io-index" 1164 | checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" 1165 | dependencies = [ 1166 | "serde_derive", 1167 | ] 1168 | 1169 | [[package]] 1170 | name = "serde_derive" 1171 | version = "1.0.219" 1172 | source = "registry+https://github.com/rust-lang/crates.io-index" 1173 | checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" 1174 | dependencies = [ 1175 | "proc-macro2", 1176 | "quote", 1177 | "syn 2.0.90", 1178 | ] 1179 | 1180 | [[package]] 1181 | name = "serde_json" 1182 | version = "1.0.133" 1183 | source = "registry+https://github.com/rust-lang/crates.io-index" 1184 | checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" 1185 | dependencies = [ 1186 | "itoa 1.0.14", 1187 | "memchr", 1188 | "ryu", 1189 | "serde", 1190 | ] 1191 | 1192 | [[package]] 1193 | name = "serde_spanned" 1194 | version = "0.6.8" 1195 | source = "registry+https://github.com/rust-lang/crates.io-index" 1196 | checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" 1197 | dependencies = [ 1198 | "serde", 1199 | ] 1200 | 1201 | [[package]] 1202 | name = "sha2" 1203 | version = "0.10.8" 1204 | source = "registry+https://github.com/rust-lang/crates.io-index" 1205 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 1206 | dependencies = [ 1207 | "cfg-if 1.0.0", 1208 | "cpufeatures", 1209 | "digest", 1210 | ] 1211 | 1212 | [[package]] 1213 | name = "shlex" 1214 | version = "1.3.0" 1215 | source = "registry+https://github.com/rust-lang/crates.io-index" 1216 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1217 | 1218 | [[package]] 1219 | name = "slab" 1220 | version = "0.4.9" 1221 | source = "registry+https://github.com/rust-lang/crates.io-index" 1222 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 1223 | dependencies = [ 1224 | "autocfg", 1225 | ] 1226 | 1227 | [[package]] 1228 | name = "smallvec" 1229 | version = "0.6.14" 1230 | source = "registry+https://github.com/rust-lang/crates.io-index" 1231 | checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0" 1232 | dependencies = [ 1233 | "maybe-uninit", 1234 | ] 1235 | 1236 | [[package]] 1237 | name = "smallvec" 1238 | version = "1.13.2" 1239 | source = "registry+https://github.com/rust-lang/crates.io-index" 1240 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 1241 | 1242 | [[package]] 1243 | name = "stable_deref_trait" 1244 | version = "1.2.0" 1245 | source = "registry+https://github.com/rust-lang/crates.io-index" 1246 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 1247 | 1248 | [[package]] 1249 | name = "string" 1250 | version = "0.2.1" 1251 | source = "registry+https://github.com/rust-lang/crates.io-index" 1252 | checksum = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" 1253 | dependencies = [ 1254 | "bytes", 1255 | ] 1256 | 1257 | [[package]] 1258 | name = "strsim" 1259 | version = "0.8.0" 1260 | source = "registry+https://github.com/rust-lang/crates.io-index" 1261 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 1262 | 1263 | [[package]] 1264 | name = "structopt" 1265 | version = "0.3.26" 1266 | source = "registry+https://github.com/rust-lang/crates.io-index" 1267 | checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" 1268 | dependencies = [ 1269 | "clap", 1270 | "lazy_static", 1271 | "structopt-derive", 1272 | ] 1273 | 1274 | [[package]] 1275 | name = "structopt-derive" 1276 | version = "0.4.18" 1277 | source = "registry+https://github.com/rust-lang/crates.io-index" 1278 | checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" 1279 | dependencies = [ 1280 | "heck", 1281 | "proc-macro-error", 1282 | "proc-macro2", 1283 | "quote", 1284 | "syn 1.0.109", 1285 | ] 1286 | 1287 | [[package]] 1288 | name = "syn" 1289 | version = "1.0.109" 1290 | source = "registry+https://github.com/rust-lang/crates.io-index" 1291 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 1292 | dependencies = [ 1293 | "proc-macro2", 1294 | "quote", 1295 | "unicode-ident", 1296 | ] 1297 | 1298 | [[package]] 1299 | name = "syn" 1300 | version = "2.0.90" 1301 | source = "registry+https://github.com/rust-lang/crates.io-index" 1302 | checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" 1303 | dependencies = [ 1304 | "proc-macro2", 1305 | "quote", 1306 | "unicode-ident", 1307 | ] 1308 | 1309 | [[package]] 1310 | name = "synstructure" 1311 | version = "0.12.6" 1312 | source = "registry+https://github.com/rust-lang/crates.io-index" 1313 | checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" 1314 | dependencies = [ 1315 | "proc-macro2", 1316 | "quote", 1317 | "syn 1.0.109", 1318 | "unicode-xid", 1319 | ] 1320 | 1321 | [[package]] 1322 | name = "synstructure" 1323 | version = "0.13.1" 1324 | source = "registry+https://github.com/rust-lang/crates.io-index" 1325 | checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" 1326 | dependencies = [ 1327 | "proc-macro2", 1328 | "quote", 1329 | "syn 2.0.90", 1330 | ] 1331 | 1332 | [[package]] 1333 | name = "textwrap" 1334 | version = "0.11.0" 1335 | source = "registry+https://github.com/rust-lang/crates.io-index" 1336 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 1337 | dependencies = [ 1338 | "unicode-width", 1339 | ] 1340 | 1341 | [[package]] 1342 | name = "thiserror" 1343 | version = "1.0.69" 1344 | source = "registry+https://github.com/rust-lang/crates.io-index" 1345 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 1346 | dependencies = [ 1347 | "thiserror-impl 1.0.69", 1348 | ] 1349 | 1350 | [[package]] 1351 | name = "thiserror" 1352 | version = "2.0.7" 1353 | source = "registry+https://github.com/rust-lang/crates.io-index" 1354 | checksum = "93605438cbd668185516ab499d589afb7ee1859ea3d5fc8f6b0755e1c7443767" 1355 | dependencies = [ 1356 | "thiserror-impl 2.0.7", 1357 | ] 1358 | 1359 | [[package]] 1360 | name = "thiserror-impl" 1361 | version = "1.0.69" 1362 | source = "registry+https://github.com/rust-lang/crates.io-index" 1363 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 1364 | dependencies = [ 1365 | "proc-macro2", 1366 | "quote", 1367 | "syn 2.0.90", 1368 | ] 1369 | 1370 | [[package]] 1371 | name = "thiserror-impl" 1372 | version = "2.0.7" 1373 | source = "registry+https://github.com/rust-lang/crates.io-index" 1374 | checksum = "e1d8749b4531af2117677a5fcd12b1348a3fe2b81e36e61ffeac5c4aa3273e36" 1375 | dependencies = [ 1376 | "proc-macro2", 1377 | "quote", 1378 | "syn 2.0.90", 1379 | ] 1380 | 1381 | [[package]] 1382 | name = "time" 1383 | version = "0.1.45" 1384 | source = "registry+https://github.com/rust-lang/crates.io-index" 1385 | checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" 1386 | dependencies = [ 1387 | "libc", 1388 | "wasi 0.10.0+wasi-snapshot-preview1", 1389 | "winapi 0.3.9", 1390 | ] 1391 | 1392 | [[package]] 1393 | name = "tinystr" 1394 | version = "0.7.6" 1395 | source = "registry+https://github.com/rust-lang/crates.io-index" 1396 | checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" 1397 | dependencies = [ 1398 | "displaydoc", 1399 | "zerovec", 1400 | ] 1401 | 1402 | [[package]] 1403 | name = "tokio" 1404 | version = "0.1.22" 1405 | source = "registry+https://github.com/rust-lang/crates.io-index" 1406 | checksum = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" 1407 | dependencies = [ 1408 | "bytes", 1409 | "futures", 1410 | "mio", 1411 | "num_cpus", 1412 | "tokio-current-thread", 1413 | "tokio-executor", 1414 | "tokio-io", 1415 | "tokio-reactor", 1416 | "tokio-threadpool", 1417 | "tokio-timer", 1418 | ] 1419 | 1420 | [[package]] 1421 | name = "tokio-buf" 1422 | version = "0.1.1" 1423 | source = "registry+https://github.com/rust-lang/crates.io-index" 1424 | checksum = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46" 1425 | dependencies = [ 1426 | "bytes", 1427 | "either", 1428 | "futures", 1429 | ] 1430 | 1431 | [[package]] 1432 | name = "tokio-current-thread" 1433 | version = "0.1.7" 1434 | source = "registry+https://github.com/rust-lang/crates.io-index" 1435 | checksum = "b1de0e32a83f131e002238d7ccde18211c0a5397f60cbfffcb112868c2e0e20e" 1436 | dependencies = [ 1437 | "futures", 1438 | "tokio-executor", 1439 | ] 1440 | 1441 | [[package]] 1442 | name = "tokio-executor" 1443 | version = "0.1.10" 1444 | source = "registry+https://github.com/rust-lang/crates.io-index" 1445 | checksum = "fb2d1b8f4548dbf5e1f7818512e9c406860678f29c300cdf0ebac72d1a3a1671" 1446 | dependencies = [ 1447 | "crossbeam-utils", 1448 | "futures", 1449 | ] 1450 | 1451 | [[package]] 1452 | name = "tokio-io" 1453 | version = "0.1.13" 1454 | source = "registry+https://github.com/rust-lang/crates.io-index" 1455 | checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" 1456 | dependencies = [ 1457 | "bytes", 1458 | "futures", 1459 | "log", 1460 | ] 1461 | 1462 | [[package]] 1463 | name = "tokio-reactor" 1464 | version = "0.1.12" 1465 | source = "registry+https://github.com/rust-lang/crates.io-index" 1466 | checksum = "09bc590ec4ba8ba87652da2068d150dcada2cfa2e07faae270a5e0409aa51351" 1467 | dependencies = [ 1468 | "crossbeam-utils", 1469 | "futures", 1470 | "lazy_static", 1471 | "log", 1472 | "mio", 1473 | "num_cpus", 1474 | "parking_lot 0.9.0", 1475 | "slab", 1476 | "tokio-executor", 1477 | "tokio-io", 1478 | "tokio-sync", 1479 | ] 1480 | 1481 | [[package]] 1482 | name = "tokio-sync" 1483 | version = "0.1.8" 1484 | source = "registry+https://github.com/rust-lang/crates.io-index" 1485 | checksum = "edfe50152bc8164fcc456dab7891fa9bf8beaf01c5ee7e1dd43a397c3cf87dee" 1486 | dependencies = [ 1487 | "fnv", 1488 | "futures", 1489 | ] 1490 | 1491 | [[package]] 1492 | name = "tokio-tcp" 1493 | version = "0.1.4" 1494 | source = "registry+https://github.com/rust-lang/crates.io-index" 1495 | checksum = "98df18ed66e3b72e742f185882a9e201892407957e45fbff8da17ae7a7c51f72" 1496 | dependencies = [ 1497 | "bytes", 1498 | "futures", 1499 | "iovec", 1500 | "mio", 1501 | "tokio-io", 1502 | "tokio-reactor", 1503 | ] 1504 | 1505 | [[package]] 1506 | name = "tokio-threadpool" 1507 | version = "0.1.18" 1508 | source = "registry+https://github.com/rust-lang/crates.io-index" 1509 | checksum = "df720b6581784c118f0eb4310796b12b1d242a7eb95f716a8367855325c25f89" 1510 | dependencies = [ 1511 | "crossbeam-deque", 1512 | "crossbeam-queue", 1513 | "crossbeam-utils", 1514 | "futures", 1515 | "lazy_static", 1516 | "log", 1517 | "num_cpus", 1518 | "slab", 1519 | "tokio-executor", 1520 | ] 1521 | 1522 | [[package]] 1523 | name = "tokio-timer" 1524 | version = "0.2.13" 1525 | source = "registry+https://github.com/rust-lang/crates.io-index" 1526 | checksum = "93044f2d313c95ff1cb7809ce9a7a05735b012288a888b62d4434fd58c94f296" 1527 | dependencies = [ 1528 | "crossbeam-utils", 1529 | "futures", 1530 | "slab", 1531 | "tokio-executor", 1532 | ] 1533 | 1534 | [[package]] 1535 | name = "toml" 1536 | version = "0.8.22" 1537 | source = "registry+https://github.com/rust-lang/crates.io-index" 1538 | checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" 1539 | dependencies = [ 1540 | "serde", 1541 | "serde_spanned", 1542 | "toml_datetime", 1543 | "toml_edit", 1544 | ] 1545 | 1546 | [[package]] 1547 | name = "toml_datetime" 1548 | version = "0.6.9" 1549 | source = "registry+https://github.com/rust-lang/crates.io-index" 1550 | checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" 1551 | dependencies = [ 1552 | "serde", 1553 | ] 1554 | 1555 | [[package]] 1556 | name = "toml_edit" 1557 | version = "0.22.26" 1558 | source = "registry+https://github.com/rust-lang/crates.io-index" 1559 | checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" 1560 | dependencies = [ 1561 | "indexmap 2.7.0", 1562 | "serde", 1563 | "serde_spanned", 1564 | "toml_datetime", 1565 | "toml_write", 1566 | "winnow", 1567 | ] 1568 | 1569 | [[package]] 1570 | name = "toml_write" 1571 | version = "0.1.1" 1572 | source = "registry+https://github.com/rust-lang/crates.io-index" 1573 | checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" 1574 | 1575 | [[package]] 1576 | name = "try-lock" 1577 | version = "0.2.5" 1578 | source = "registry+https://github.com/rust-lang/crates.io-index" 1579 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 1580 | 1581 | [[package]] 1582 | name = "typenum" 1583 | version = "1.17.0" 1584 | source = "registry+https://github.com/rust-lang/crates.io-index" 1585 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 1586 | 1587 | [[package]] 1588 | name = "ucd-trie" 1589 | version = "0.1.7" 1590 | source = "registry+https://github.com/rust-lang/crates.io-index" 1591 | checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" 1592 | 1593 | [[package]] 1594 | name = "unicode-ident" 1595 | version = "1.0.14" 1596 | source = "registry+https://github.com/rust-lang/crates.io-index" 1597 | checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" 1598 | 1599 | [[package]] 1600 | name = "unicode-segmentation" 1601 | version = "1.12.0" 1602 | source = "registry+https://github.com/rust-lang/crates.io-index" 1603 | checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" 1604 | 1605 | [[package]] 1606 | name = "unicode-width" 1607 | version = "0.1.14" 1608 | source = "registry+https://github.com/rust-lang/crates.io-index" 1609 | checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" 1610 | 1611 | [[package]] 1612 | name = "unicode-xid" 1613 | version = "0.2.6" 1614 | source = "registry+https://github.com/rust-lang/crates.io-index" 1615 | checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" 1616 | 1617 | [[package]] 1618 | name = "unreachable" 1619 | version = "1.0.0" 1620 | source = "registry+https://github.com/rust-lang/crates.io-index" 1621 | checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" 1622 | dependencies = [ 1623 | "void", 1624 | ] 1625 | 1626 | [[package]] 1627 | name = "url" 1628 | version = "2.5.4" 1629 | source = "registry+https://github.com/rust-lang/crates.io-index" 1630 | checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" 1631 | dependencies = [ 1632 | "form_urlencoded", 1633 | "idna", 1634 | "percent-encoding", 1635 | ] 1636 | 1637 | [[package]] 1638 | name = "utf16_iter" 1639 | version = "1.0.5" 1640 | source = "registry+https://github.com/rust-lang/crates.io-index" 1641 | checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" 1642 | 1643 | [[package]] 1644 | name = "utf8_iter" 1645 | version = "1.0.4" 1646 | source = "registry+https://github.com/rust-lang/crates.io-index" 1647 | checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 1648 | 1649 | [[package]] 1650 | name = "vec_map" 1651 | version = "0.8.2" 1652 | source = "registry+https://github.com/rust-lang/crates.io-index" 1653 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 1654 | 1655 | [[package]] 1656 | name = "version_check" 1657 | version = "0.9.5" 1658 | source = "registry+https://github.com/rust-lang/crates.io-index" 1659 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 1660 | 1661 | [[package]] 1662 | name = "void" 1663 | version = "1.0.2" 1664 | source = "registry+https://github.com/rust-lang/crates.io-index" 1665 | checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 1666 | 1667 | [[package]] 1668 | name = "want" 1669 | version = "0.2.0" 1670 | source = "registry+https://github.com/rust-lang/crates.io-index" 1671 | checksum = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" 1672 | dependencies = [ 1673 | "futures", 1674 | "log", 1675 | "try-lock", 1676 | ] 1677 | 1678 | [[package]] 1679 | name = "wasi" 1680 | version = "0.10.0+wasi-snapshot-preview1" 1681 | source = "registry+https://github.com/rust-lang/crates.io-index" 1682 | checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" 1683 | 1684 | [[package]] 1685 | name = "wasi" 1686 | version = "0.13.3+wasi-0.2.2" 1687 | source = "registry+https://github.com/rust-lang/crates.io-index" 1688 | checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" 1689 | dependencies = [ 1690 | "wit-bindgen-rt", 1691 | ] 1692 | 1693 | [[package]] 1694 | name = "winapi" 1695 | version = "0.2.8" 1696 | source = "registry+https://github.com/rust-lang/crates.io-index" 1697 | checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" 1698 | 1699 | [[package]] 1700 | name = "winapi" 1701 | version = "0.3.9" 1702 | source = "registry+https://github.com/rust-lang/crates.io-index" 1703 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1704 | dependencies = [ 1705 | "winapi-i686-pc-windows-gnu", 1706 | "winapi-x86_64-pc-windows-gnu", 1707 | ] 1708 | 1709 | [[package]] 1710 | name = "winapi-build" 1711 | version = "0.1.1" 1712 | source = "registry+https://github.com/rust-lang/crates.io-index" 1713 | checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" 1714 | 1715 | [[package]] 1716 | name = "winapi-i686-pc-windows-gnu" 1717 | version = "0.4.0" 1718 | source = "registry+https://github.com/rust-lang/crates.io-index" 1719 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1720 | 1721 | [[package]] 1722 | name = "winapi-x86_64-pc-windows-gnu" 1723 | version = "0.4.0" 1724 | source = "registry+https://github.com/rust-lang/crates.io-index" 1725 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1726 | 1727 | [[package]] 1728 | name = "windows-targets" 1729 | version = "0.52.6" 1730 | source = "registry+https://github.com/rust-lang/crates.io-index" 1731 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1732 | dependencies = [ 1733 | "windows_aarch64_gnullvm", 1734 | "windows_aarch64_msvc", 1735 | "windows_i686_gnu", 1736 | "windows_i686_gnullvm", 1737 | "windows_i686_msvc", 1738 | "windows_x86_64_gnu", 1739 | "windows_x86_64_gnullvm", 1740 | "windows_x86_64_msvc", 1741 | ] 1742 | 1743 | [[package]] 1744 | name = "windows_aarch64_gnullvm" 1745 | version = "0.52.6" 1746 | source = "registry+https://github.com/rust-lang/crates.io-index" 1747 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1748 | 1749 | [[package]] 1750 | name = "windows_aarch64_msvc" 1751 | version = "0.52.6" 1752 | source = "registry+https://github.com/rust-lang/crates.io-index" 1753 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1754 | 1755 | [[package]] 1756 | name = "windows_i686_gnu" 1757 | version = "0.52.6" 1758 | source = "registry+https://github.com/rust-lang/crates.io-index" 1759 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1760 | 1761 | [[package]] 1762 | name = "windows_i686_gnullvm" 1763 | version = "0.52.6" 1764 | source = "registry+https://github.com/rust-lang/crates.io-index" 1765 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1766 | 1767 | [[package]] 1768 | name = "windows_i686_msvc" 1769 | version = "0.52.6" 1770 | source = "registry+https://github.com/rust-lang/crates.io-index" 1771 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1772 | 1773 | [[package]] 1774 | name = "windows_x86_64_gnu" 1775 | version = "0.52.6" 1776 | source = "registry+https://github.com/rust-lang/crates.io-index" 1777 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1778 | 1779 | [[package]] 1780 | name = "windows_x86_64_gnullvm" 1781 | version = "0.52.6" 1782 | source = "registry+https://github.com/rust-lang/crates.io-index" 1783 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1784 | 1785 | [[package]] 1786 | name = "windows_x86_64_msvc" 1787 | version = "0.52.6" 1788 | source = "registry+https://github.com/rust-lang/crates.io-index" 1789 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1790 | 1791 | [[package]] 1792 | name = "winnow" 1793 | version = "0.7.7" 1794 | source = "registry+https://github.com/rust-lang/crates.io-index" 1795 | checksum = "6cb8234a863ea0e8cd7284fcdd4f145233eb00fee02bbdd9861aec44e6477bc5" 1796 | dependencies = [ 1797 | "memchr", 1798 | ] 1799 | 1800 | [[package]] 1801 | name = "wit-bindgen-rt" 1802 | version = "0.33.0" 1803 | source = "registry+https://github.com/rust-lang/crates.io-index" 1804 | checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" 1805 | dependencies = [ 1806 | "bitflags 2.6.0", 1807 | ] 1808 | 1809 | [[package]] 1810 | name = "write16" 1811 | version = "1.0.0" 1812 | source = "registry+https://github.com/rust-lang/crates.io-index" 1813 | checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" 1814 | 1815 | [[package]] 1816 | name = "writeable" 1817 | version = "0.5.5" 1818 | source = "registry+https://github.com/rust-lang/crates.io-index" 1819 | checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" 1820 | 1821 | [[package]] 1822 | name = "ws2_32-sys" 1823 | version = "0.2.1" 1824 | source = "registry+https://github.com/rust-lang/crates.io-index" 1825 | checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" 1826 | dependencies = [ 1827 | "winapi 0.2.8", 1828 | "winapi-build", 1829 | ] 1830 | 1831 | [[package]] 1832 | name = "yoke" 1833 | version = "0.7.5" 1834 | source = "registry+https://github.com/rust-lang/crates.io-index" 1835 | checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" 1836 | dependencies = [ 1837 | "serde", 1838 | "stable_deref_trait", 1839 | "yoke-derive", 1840 | "zerofrom", 1841 | ] 1842 | 1843 | [[package]] 1844 | name = "yoke-derive" 1845 | version = "0.7.5" 1846 | source = "registry+https://github.com/rust-lang/crates.io-index" 1847 | checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" 1848 | dependencies = [ 1849 | "proc-macro2", 1850 | "quote", 1851 | "syn 2.0.90", 1852 | "synstructure 0.13.1", 1853 | ] 1854 | 1855 | [[package]] 1856 | name = "zerocopy" 1857 | version = "0.7.35" 1858 | source = "registry+https://github.com/rust-lang/crates.io-index" 1859 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 1860 | dependencies = [ 1861 | "byteorder", 1862 | "zerocopy-derive 0.7.35", 1863 | ] 1864 | 1865 | [[package]] 1866 | name = "zerocopy" 1867 | version = "0.8.14" 1868 | source = "registry+https://github.com/rust-lang/crates.io-index" 1869 | checksum = "a367f292d93d4eab890745e75a778da40909cab4d6ff8173693812f79c4a2468" 1870 | dependencies = [ 1871 | "zerocopy-derive 0.8.14", 1872 | ] 1873 | 1874 | [[package]] 1875 | name = "zerocopy-derive" 1876 | version = "0.7.35" 1877 | source = "registry+https://github.com/rust-lang/crates.io-index" 1878 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 1879 | dependencies = [ 1880 | "proc-macro2", 1881 | "quote", 1882 | "syn 2.0.90", 1883 | ] 1884 | 1885 | [[package]] 1886 | name = "zerocopy-derive" 1887 | version = "0.8.14" 1888 | source = "registry+https://github.com/rust-lang/crates.io-index" 1889 | checksum = "d3931cb58c62c13adec22e38686b559c86a30565e16ad6e8510a337cedc611e1" 1890 | dependencies = [ 1891 | "proc-macro2", 1892 | "quote", 1893 | "syn 2.0.90", 1894 | ] 1895 | 1896 | [[package]] 1897 | name = "zerofrom" 1898 | version = "0.1.5" 1899 | source = "registry+https://github.com/rust-lang/crates.io-index" 1900 | checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" 1901 | dependencies = [ 1902 | "zerofrom-derive", 1903 | ] 1904 | 1905 | [[package]] 1906 | name = "zerofrom-derive" 1907 | version = "0.1.5" 1908 | source = "registry+https://github.com/rust-lang/crates.io-index" 1909 | checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" 1910 | dependencies = [ 1911 | "proc-macro2", 1912 | "quote", 1913 | "syn 2.0.90", 1914 | "synstructure 0.13.1", 1915 | ] 1916 | 1917 | [[package]] 1918 | name = "zerovec" 1919 | version = "0.10.4" 1920 | source = "registry+https://github.com/rust-lang/crates.io-index" 1921 | checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" 1922 | dependencies = [ 1923 | "yoke", 1924 | "zerofrom", 1925 | "zerovec-derive", 1926 | ] 1927 | 1928 | [[package]] 1929 | name = "zerovec-derive" 1930 | version = "0.10.3" 1931 | source = "registry+https://github.com/rust-lang/crates.io-index" 1932 | checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" 1933 | dependencies = [ 1934 | "proc-macro2", 1935 | "quote", 1936 | "syn 2.0.90", 1937 | ] 1938 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "prosafe_exporter" 3 | version = "0.2.9" 4 | authors = ["dalance "] 5 | repository = "https://github.com/dalance/prosafe_exporter" 6 | license = "MIT" 7 | readme = "README.md" 8 | description = "Prometheus exporter for NETGEAR switches supported by ProSAFE Plus utility" 9 | categories = ["network-programming", "web-programming"] 10 | edition = "2018" 11 | 12 | [badges] 13 | travis-ci = { repository = "dalance/prosafe_exporter" } 14 | 15 | [dependencies] 16 | bincode = "1" 17 | combine = "3" 18 | failure = "0.1" 19 | lazy_static = "1" 20 | hyper = "0.12" 21 | interfaces = "0.0.9" 22 | prometheus = "0.13" 23 | rand = "0.9" 24 | serde = {version = "1.0", features = ["derive"]} 25 | structopt = "0.3" 26 | toml = "0.8" 27 | url = "2" 28 | 29 | [dev-dependencies] 30 | hex-literal = "1.0" 31 | 32 | [package.metadata.release] 33 | pre-release-commit-message = "Prepare to v{{version}}" 34 | tag-message = "Bump version to {{version}}" 35 | tag-prefix = "" 36 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:alpine as cargo-build 2 | 3 | RUN apk add --no-cache -U libc-dev 4 | RUN rustup target add x86_64-unknown-linux-musl 5 | 6 | WORKDIR /build 7 | 8 | COPY . . 9 | 10 | RUN cargo build --release --target=x86_64-unknown-linux-musl 11 | 12 | FROM alpine 13 | 14 | WORKDIR /app 15 | 16 | COPY --from=cargo-build /build/target/x86_64-unknown-linux-musl/release/prosafe_exporter . 17 | 18 | EXPOSE 9493/tcp 19 | ENTRYPOINT ["/app/prosafe_exporter"] 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 dalance 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | VERSION = $(patsubst "%",%, $(word 3, $(shell grep version Cargo.toml))) 2 | BUILD_TIME = $(shell date +"%Y/%m/%d %H:%M:%S") 3 | GIT_REVISION = $(shell git log -1 --format="%h") 4 | RUST_VERSION = $(word 2, $(shell rustc -V)) 5 | LONG_VERSION = "$(VERSION) ( rev: $(GIT_REVISION), rustc: $(RUST_VERSION), build at: $(BUILD_TIME) )" 6 | BIN_NAME = prosafe_exporter 7 | 8 | export LONG_VERSION 9 | 10 | .PHONY: all test clean release_lnx release_win release_mac 11 | 12 | all: test 13 | 14 | test: 15 | cargo test 16 | 17 | watch: 18 | cargo watch 19 | 20 | clean: 21 | cargo clean 22 | 23 | release_lnx: 24 | cargo build --release --target=x86_64-unknown-linux-musl 25 | zip -j ${BIN_NAME}-v${VERSION}-x86_64-lnx.zip target/x86_64-unknown-linux-musl/release/${BIN_NAME} 26 | 27 | release_win: 28 | cargo build --release --target=x86_64-pc-windows-gnu 29 | zip -j ${BIN_NAME}-v${VERSION}-x86_64-win.zip target/x86_64-pc-windows-gnu/release/${BIN_NAME}.exe 30 | 31 | release_mac: 32 | cargo build --release --target=aarch64-apple-darwin 33 | zip -j ${BIN_NAME}-v${VERSION}-aarch64-mac.zip target/aarch64-apple-darwin/release/${BIN_NAME} 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # prosafe_exporter 2 | [Prometheus](https://prometheus.io) exporter for NETGEAR switches supported by ProSAFE Plus utility. 3 | 4 | [![Actions Status](https://github.com/dalance/prosafe_exporter/workflows/Regression/badge.svg)](https://github.com/dalance/prosafe_exporter/actions) 5 | [![Crates.io](https://img.shields.io/crates/v/prosafe_exporter.svg)](https://crates.io/crates/prosafe_exporter) 6 | [![codecov](https://codecov.io/gh/dalance/prosafe_exporter/branch/master/graph/badge.svg)](https://codecov.io/gh/dalance/prosafe_exporter) 7 | 8 | ## Exported Metrics 9 | 10 | | metric | description | labels | 11 | | ---------------------------- | ---------------------------------- | ------------------------------ | 12 | | prosafe_up | The last query is successful | | 13 | | prosafe_receive_bytes_total | Incoming transfer in bytes | port | 14 | | prosafe_transmit_bytes_total | Outgoing transfer in bytes | port | 15 | | prosafe_error_packets_total | Transfer error in packets | port | 16 | | prosafe_link_speed | Link speed in Mbps | port | 17 | | prosafe_build_info | prosafe_exporter Build information | version, revision, rustversion | 18 | 19 | ## Tested Switches 20 | 21 | - XS708E 22 | - GS308E 23 | - GS116Ev2 24 | - GS108Ev3 25 | - GS105Ev2 26 | - GS108PEv3 27 | - JGS524PE 28 | 29 | ## Install 30 | Download from [release page](https://github.com/dalance/prosafe_exporter/releases/latest), and extract to any directory ( e.g. `/usr/local/bin` ). 31 | See the example files in `example` directory as below. 32 | 33 | | File | Description | 34 | | -------------------------------- | ---------------------------- | 35 | | example/prosafe_exporter.service | systemd unit file | 36 | 37 | 38 | If the release build doesn't fit your environment, you can build and install from source code. 39 | 40 | ``` 41 | cargo install prosafe_exporter 42 | ``` 43 | 44 | ## Usage 45 | 46 | ``` 47 | prosafe_exporter --web.listen-address=":9493" 48 | ``` 49 | 50 | The default listen port is 9493. 51 | It can be changed by `--web.listen-address` option. 52 | 53 | The ProSAFE switches need to have the Switch Management Mode set to "Web browser and Plus Utility" for the exporter to work correctly. 54 | 55 | ## Prometheus Server Configuration 56 | 57 | The target switches of prosafe_exporter can be configured by the pair of hostname and network interface name ( e.g. `switch1:eth0` ). 58 | The network interface must be belonged to the same subnet as the switch. 59 | 60 | The Prometheus server configuration is like [SNMP exporter](https://github.com/prometheus/snmp_exporter). 61 | The example of a configuration is below: 62 | 63 | ```yaml 64 | - job_name: 'prosafe' 65 | static_configs: 66 | - targets: ['switch1:eth0', '192.128.0.100:enp1s0', 'switch2:*'] # target switches by hostname:if_name. 67 | metrics_path: /probe 68 | relabel_configs: 69 | - source_labels: [__address__] 70 | target_label: __param_target 71 | - source_labels: [__param_target] 72 | target_label: instance 73 | - target_label: __address__ 74 | replacement: 127.0.0.1:9493 # The prosafe_exporter's real hostname:port. 75 | ``` 76 | 77 | `if_name` can be `*`. If `*` is used, prosafe_exporter will search an accessible network interface automatically. 78 | 79 | ## Query Example 80 | 81 | Outgoing data rate of `port1` on `switch1:eth0` is below. 82 | 83 | ``` 84 | rate(prosafe_transmit_bytes_total{instance="switch1:eth0", port="1"}[1m]) 85 | ``` 86 | -------------------------------------------------------------------------------- /example/prosafe_exporter.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Prometheus ProSAFE Exporter 3 | After=network.target 4 | 5 | [Service] 6 | ExecStart=/usr/local/bin/prosafe_exporter 7 | User=nobody 8 | 9 | [Install] 10 | WantedBy=multi-user.target 11 | -------------------------------------------------------------------------------- /src/exporter.rs: -------------------------------------------------------------------------------- 1 | use crate::prosafe_switch::{Link, ProSafeSwitch}; 2 | use failure::Error; 3 | use hyper::rt::{self, Future}; 4 | use hyper::service::service_fn_ok; 5 | use hyper::{Body, Response, Server, Uri}; 6 | use lazy_static::lazy_static; 7 | use prometheus::{Encoder, GaugeVec, Opts, Registry, TextEncoder}; 8 | use std::sync::{Arc, Mutex}; 9 | use url::form_urlencoded; 10 | 11 | // --------------------------------------------------------------------------------------------------------------------- 12 | // Metrics 13 | // --------------------------------------------------------------------------------------------------------------------- 14 | 15 | lazy_static! { 16 | static ref UP_OPT: Opts = Opts::new("prosafe_up", "The last query is successful."); 17 | static ref RECEIVE_BYTES_OPT: Opts = 18 | Opts::new("prosafe_receive_bytes_total", "Incoming transfer in bytes."); 19 | static ref TRANSMIT_BYTES_OPT: Opts = Opts::new( 20 | "prosafe_transmit_bytes_total", 21 | "Outgoing transfer in bytes." 22 | ); 23 | static ref ERROR_PACKETS_OPT: Opts = 24 | Opts::new("prosafe_error_packets_total", "Transfer error in packets."); 25 | static ref LINK_SPEED_OPT: Opts = Opts::new("prosafe_link_speed", "Link speed in Mbps."); 26 | static ref BUILD_INFO_OPT: Opts = Opts::new( 27 | "prosafe_build_info", 28 | "A metric with a constant '1' value labeled by version, revision and rustversion." 29 | ); 30 | } 31 | 32 | // --------------------------------------------------------------------------------------------------------------------- 33 | // Landing Page HTML 34 | // --------------------------------------------------------------------------------------------------------------------- 35 | 36 | static LANDING_PAGE: &'static str = r#" 37 | ProSAFE Exporter 38 | 39 |

ProSAFE Exporter

40 |
41 |
42 | 43 |
44 | 45 | "#; 46 | 47 | // --------------------------------------------------------------------------------------------------------------------- 48 | // Build info 49 | // --------------------------------------------------------------------------------------------------------------------- 50 | 51 | static VERSION: &'static str = env!("CARGO_PKG_VERSION"); 52 | static GIT_REVISION: Option<&'static str> = option_env!("GIT_REVISION"); 53 | static RUST_VERSION: Option<&'static str> = option_env!("RUST_VERSION"); 54 | 55 | // --------------------------------------------------------------------------------------------------------------------- 56 | // Exporter 57 | // --------------------------------------------------------------------------------------------------------------------- 58 | 59 | pub struct Exporter; 60 | 61 | impl Exporter { 62 | pub fn start(listen_address: &str, target: Option, verbose: bool) -> Result<(), Error> { 63 | let addr = format!("0.0.0.0{}", listen_address).parse()?; 64 | 65 | if verbose { 66 | println!("Server started: {:?}", addr); 67 | } 68 | 69 | let mutex = Arc::new(Mutex::new(())); 70 | 71 | let service = move || { 72 | let mutex = Arc::clone(&mutex); 73 | let target = target.clone(); 74 | service_fn_ok(move |req| { 75 | let mutex = Arc::clone(&mutex); 76 | let uri = req.uri(); 77 | 78 | let static_uri = if let Some(ref target) = target { 79 | let uri = format!("/probe?target={}", target).parse::(); 80 | if let Ok(uri) = uri { 81 | Some(uri) 82 | } else { 83 | None 84 | } 85 | } else { 86 | None 87 | }; 88 | 89 | if uri.path() == "/probe" { 90 | Exporter::probe(uri, false, verbose, mutex) 91 | } else if uri.path() == "/metrics" { 92 | if let Some(static_uri) = static_uri { 93 | Exporter::probe(&static_uri, true, verbose, mutex) 94 | } else { 95 | Response::new(Body::from(LANDING_PAGE)) 96 | } 97 | } else { 98 | Response::new(Body::from(LANDING_PAGE)) 99 | } 100 | }) 101 | }; 102 | 103 | let server = Server::bind(&addr) 104 | .serve(service) 105 | .map_err(|e| eprintln!("Server error: {}", e)); 106 | 107 | rt::run(server); 108 | 109 | Ok(()) 110 | } 111 | 112 | fn probe( 113 | uri: &Uri, 114 | instance_label: bool, 115 | verbose: bool, 116 | mutex: Arc>, 117 | ) -> Response { 118 | let registry = Registry::new(); 119 | 120 | let build_info = GaugeVec::new( 121 | BUILD_INFO_OPT.clone(), 122 | &["version", "revision", "rustversion"], 123 | ) 124 | .unwrap(); 125 | 126 | let up_label = if instance_label { 127 | vec!["instance"] 128 | } else { 129 | vec![] 130 | }; 131 | 132 | let label = if instance_label { 133 | vec!["instance", "port"] 134 | } else { 135 | vec!["port"] 136 | }; 137 | 138 | let up = GaugeVec::new(UP_OPT.clone(), &up_label).unwrap(); 139 | let receive_bytes = GaugeVec::new(RECEIVE_BYTES_OPT.clone(), &label).unwrap(); 140 | let transmit_bytes = GaugeVec::new(TRANSMIT_BYTES_OPT.clone(), &label).unwrap(); 141 | let error_packets = GaugeVec::new(ERROR_PACKETS_OPT.clone(), &label).unwrap(); 142 | let link_speed = GaugeVec::new(LINK_SPEED_OPT.clone(), &label).unwrap(); 143 | 144 | let _ = registry.register(Box::new(build_info.clone())); 145 | let _ = registry.register(Box::new(up.clone())); 146 | let _ = registry.register(Box::new(receive_bytes.clone())); 147 | let _ = registry.register(Box::new(transmit_bytes.clone())); 148 | let _ = registry.register(Box::new(error_packets.clone())); 149 | let _ = registry.register(Box::new(link_speed.clone())); 150 | 151 | let git_revision = GIT_REVISION.unwrap_or(""); 152 | let rust_version = RUST_VERSION.unwrap_or(""); 153 | build_info 154 | .with_label_values(&[&VERSION, &git_revision, &rust_version]) 155 | .set(1.0); 156 | 157 | if let Some(query) = uri.query() { 158 | let mut target = None; 159 | let query = form_urlencoded::parse(query.as_bytes()); 160 | for (k, v) in query { 161 | if k == "target" && v.contains(':') { 162 | target = Some(v); 163 | } 164 | } 165 | if let Some(target) = target { 166 | let instance_string = String::from(target.clone()); 167 | let label = if instance_label { 168 | vec![instance_string.as_str()] 169 | } else { 170 | vec![] 171 | }; 172 | 173 | let target: Vec<&str> = target.split(':').collect(); 174 | 175 | let host = &target[0]; 176 | let if_name = &target[1]; 177 | 178 | if verbose { 179 | println!("Access to switch: {} though {}", host, if_name); 180 | } 181 | 182 | { 183 | let _guard = mutex.lock(); 184 | 185 | let if_name = if if_name == &"*" { 186 | let sw = ProSafeSwitch::new(&host, &if_name); 187 | match sw.find_iface() { 188 | Ok(iface) => iface, 189 | Err(_) => { 190 | eprintln!("Fail to find accessible network interface to {}", host); 191 | String::from(*if_name) 192 | } 193 | } 194 | } else { 195 | String::from(*if_name) 196 | }; 197 | 198 | let sw = ProSafeSwitch::new(&host, &if_name); 199 | match sw.port_stat() { 200 | Ok(stats) => { 201 | for s in stats.stats { 202 | let port = format!("{}", s.port_no); 203 | let label = if instance_label { 204 | vec![instance_string.as_str(), port.as_str()] 205 | } else { 206 | vec![port.as_str()] 207 | }; 208 | 209 | receive_bytes 210 | .with_label_values(&label) 211 | .set(s.recv_bytes as f64); 212 | transmit_bytes 213 | .with_label_values(&label) 214 | .set(s.send_bytes as f64); 215 | error_packets 216 | .with_label_values(&label) 217 | .set(s.error_pkts as f64); 218 | } 219 | 220 | up.with_label_values(&label).set(1.0); 221 | } 222 | Err(x) => { 223 | up.with_label_values(&label).set(0.0); 224 | eprintln!("Fail to access: {}", x); 225 | } 226 | } 227 | match sw.speed_stat() { 228 | Ok(stats) => { 229 | for s in stats.stats { 230 | let port = format!("{}", s.port_no); 231 | let label = if instance_label { 232 | vec![instance_string.as_str(), port.as_str()] 233 | } else { 234 | vec![port.as_str()] 235 | }; 236 | 237 | let speed = match s.link { 238 | Link::None => 0, 239 | Link::Speed10Mbps => 10, 240 | Link::Speed100Mbps => 100, 241 | Link::Speed1Gbps => 1000, 242 | Link::Speed10Gbps => 10000, 243 | Link::Unknown => 0, 244 | }; 245 | link_speed.with_label_values(&label).set(f64::from(speed)); 246 | } 247 | } 248 | Err(x) => { 249 | eprintln!("Fail to access: {}", x); 250 | } 251 | } 252 | } 253 | } 254 | } 255 | 256 | let metric_familys = registry.gather(); 257 | let mut buffer = vec![]; 258 | let encoder = TextEncoder::new(); 259 | encoder.encode(&metric_familys, &mut buffer).unwrap(); 260 | Response::builder() 261 | .header("Content-Type", "text/plain; version=0.0.4") 262 | .body(Body::from(buffer)) 263 | .unwrap() 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod exporter; 2 | mod prosafe_switch; 3 | 4 | use crate::exporter::Exporter; 5 | use failure::Error; 6 | use structopt::{clap, StructOpt}; 7 | 8 | // ------------------------------------------------------------------------------------------------- 9 | // Opt 10 | // ------------------------------------------------------------------------------------------------- 11 | 12 | #[derive(Debug, StructOpt)] 13 | #[structopt(name = "prosafe_exporter")] 14 | #[structopt(long_version = option_env!("LONG_VERSION").unwrap_or(env!("CARGO_PKG_VERSION")))] 15 | #[structopt(setting = clap::AppSettings::ColoredHelp)] 16 | #[structopt(setting = clap::AppSettings::DeriveDisplayOrder)] 17 | pub struct Opt { 18 | /// Address on which to expose metrics and web interface. 19 | #[structopt(long = "web.listen-address", default_value = ":9493")] 20 | pub listen_address: String, 21 | 22 | /// Static target probed through /metrics. 23 | #[structopt(long = "target")] 24 | pub target: Option, 25 | 26 | /// Show verbose message 27 | #[structopt(short = "v", long = "verbose")] 28 | pub verbose: bool, 29 | } 30 | 31 | // ------------------------------------------------------------------------------------------------- 32 | // Main 33 | // ------------------------------------------------------------------------------------------------- 34 | 35 | fn run() -> Result<(), Error> { 36 | let opt = Opt::from_args(); 37 | let _ = Exporter::start(&opt.listen_address, opt.target, opt.verbose); 38 | Ok(()) 39 | } 40 | 41 | fn main() { 42 | if let Err(x) = run() { 43 | println!("{}", x); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/prosafe_switch.rs: -------------------------------------------------------------------------------- 1 | use bincode::Options; 2 | use combine::byte::bytes; 3 | use combine::byte::num::{be_u16, be_u64}; 4 | use combine::{any, count, skip_count}; 5 | use combine::{ParseError, Parser, Stream}; 6 | use failure::format_err; 7 | use failure::Error; 8 | use interfaces::{HardwareAddr, Interface}; 9 | use rand; 10 | use serde::{Deserialize, Serialize}; 11 | use std::net::{ToSocketAddrs, UdpSocket}; 12 | use std::time::Duration; 13 | 14 | // --------------------------------------------------------------------------------------------------------------------- 15 | // QueryRequest 16 | // --------------------------------------------------------------------------------------------------------------------- 17 | 18 | #[repr(u32)] 19 | enum Cmd { 20 | PortStat = 0x1000_0000, 21 | SpeedStat = 0x0c00_0000, 22 | End = 0xffff_0000, 23 | } 24 | 25 | #[derive(Serialize, Deserialize, Debug)] 26 | struct QueryRequest { 27 | ctype: u16, 28 | padding1: [u8; 6], 29 | src_mac: [u8; 6], 30 | dst_mac: [u8; 6], 31 | padding2: [u8; 2], 32 | seq: u16, 33 | fix: [u8; 8], 34 | cmd: [u32; 2], 35 | } 36 | 37 | impl QueryRequest { 38 | fn new(cmd: Cmd, src_mac: HardwareAddr, dst_mac: HardwareAddr) -> Self { 39 | let mut src: [u8; 6] = Default::default(); 40 | let mut dst: [u8; 6] = Default::default(); 41 | src.copy_from_slice(src_mac.as_bytes()); 42 | dst.copy_from_slice(dst_mac.as_bytes()); 43 | QueryRequest { 44 | ctype: 0x0101u16, 45 | padding1: [0; 6], 46 | src_mac: src, 47 | dst_mac: dst, 48 | padding2: [0; 2], 49 | seq: rand::random(), 50 | fix: [b'N', b'S', b'D', b'P', 0, 0, 0, 0], 51 | cmd: [cmd as u32, Cmd::End as u32], 52 | } 53 | } 54 | 55 | fn encode(&self) -> Result, Error> { 56 | let config = bincode::options().with_big_endian().with_fixint_encoding(); 57 | Ok(config.serialize(&self)?) 58 | } 59 | } 60 | 61 | // --------------------------------------------------------------------------------------------------------------------- 62 | // Parser 63 | // --------------------------------------------------------------------------------------------------------------------- 64 | 65 | struct ResponseParser; 66 | 67 | impl ResponseParser { 68 | fn header<'a, I>() -> impl Parser 69 | where 70 | I: Stream, 71 | I::Error: ParseError, 72 | { 73 | bytes(&[0x01, 0x02]) 74 | .and(be_u16()) 75 | .and(be_u16()) 76 | .and(skip_count(26, any())) 77 | .map(|(((_a, b), c), _d)| (b, c)) 78 | } 79 | 80 | fn payload_header<'a, I>() -> impl Parser 81 | where 82 | I: Stream, 83 | I::Error: ParseError, 84 | { 85 | be_u16().and(be_u16()) 86 | } 87 | 88 | fn payload_body<'a, I>(len: u16) -> impl Parser> 89 | where 90 | I: Stream, 91 | I::Error: ParseError, 92 | { 93 | count::, _>(len as usize, any()) 94 | } 95 | 96 | fn port_stats<'a, I>() -> impl Parser)> 97 | where 98 | I: Stream, 99 | I::Error: ParseError, 100 | { 101 | any().and(count::, _>(6, be_u64())) 102 | } 103 | 104 | fn speed_stats<'a, I>() -> impl Parser)> 105 | where 106 | I: Stream, 107 | I::Error: ParseError, 108 | { 109 | any().and(count::, _>(2, any())) 110 | } 111 | } 112 | 113 | // --------------------------------------------------------------------------------------------------------------------- 114 | // QueryResponse 115 | // --------------------------------------------------------------------------------------------------------------------- 116 | 117 | struct QueryResponse; 118 | 119 | impl QueryResponse { 120 | fn decode(dat: &[u8]) -> Result>, Error> { 121 | let (_, rest) = ResponseParser::header() 122 | .parse(dat) 123 | .map_err(|x| format_err!("failed to parse: {:?}", x))?; 124 | let mut ret = Vec::new(); 125 | let mut buf = rest; 126 | while !buf.is_empty() { 127 | let ((cmd, len), rest) = ResponseParser::payload_header() 128 | .parse(buf) 129 | .map_err(|x| format_err!("failed to parse: {:?}", x))?; 130 | buf = rest; 131 | 132 | let (dat, rest) = ResponseParser::payload_body(len) 133 | .parse(buf) 134 | .map_err(|x| format_err!("failed to parse: {:?}", x))?; 135 | buf = rest; 136 | 137 | if cmd == 0xffff { 138 | break; 139 | } 140 | 141 | ret.push(dat); 142 | } 143 | 144 | Ok(ret) 145 | } 146 | } 147 | 148 | // --------------------------------------------------------------------------------------------------------------------- 149 | // PortStats 150 | // --------------------------------------------------------------------------------------------------------------------- 151 | 152 | #[derive(Debug, PartialEq)] 153 | pub struct PortStats { 154 | pub stats: Vec, 155 | } 156 | 157 | #[derive(Debug, PartialEq)] 158 | pub struct PortStat { 159 | pub port_no: u8, 160 | pub recv_bytes: u64, 161 | pub send_bytes: u64, 162 | pub error_pkts: u64, 163 | } 164 | 165 | impl PortStats { 166 | fn decode(dat: &[u8]) -> Result { 167 | let dat = QueryResponse::decode(dat)?; 168 | let mut stats = Vec::new(); 169 | for d in dat { 170 | let ((port_no, metrics), _rest) = ResponseParser::port_stats() 171 | .parse(&d as &[u8]) 172 | .map_err(|x| format_err!("failed to parse: {:?}", x))?; 173 | 174 | let stat = PortStat { 175 | port_no, 176 | recv_bytes: metrics[0], 177 | send_bytes: metrics[1], 178 | error_pkts: metrics[5], 179 | }; 180 | stats.push(stat); 181 | } 182 | 183 | Ok(PortStats { stats }) 184 | } 185 | } 186 | 187 | // --------------------------------------------------------------------------------------------------------------------- 188 | // SpeedStats 189 | // --------------------------------------------------------------------------------------------------------------------- 190 | 191 | #[derive(Debug, PartialEq)] 192 | pub struct SpeedStats { 193 | pub stats: Vec, 194 | } 195 | 196 | #[derive(Debug, PartialEq)] 197 | pub struct SpeedStat { 198 | pub port_no: u8, 199 | pub link: Link, 200 | } 201 | 202 | #[derive(Debug, PartialEq)] 203 | pub enum Link { 204 | None, 205 | Speed10Mbps, 206 | Speed100Mbps, 207 | Speed1Gbps, 208 | Speed10Gbps, 209 | Unknown, 210 | } 211 | 212 | impl SpeedStats { 213 | fn decode(dat: &[u8]) -> Result { 214 | let dat = QueryResponse::decode(dat)?; 215 | let mut stats = Vec::new(); 216 | for d in dat { 217 | let ((port_no, metrics), _rest) = ResponseParser::speed_stats() 218 | .parse(&d as &[u8]) 219 | .map_err(|x| format_err!("failed to parse: {:?}", x))?; 220 | 221 | let link = match metrics[0] { 222 | 0 => Link::None, 223 | 1 => Link::Speed10Mbps, 224 | 2 => Link::Speed10Mbps, 225 | 3 => Link::Speed100Mbps, 226 | 4 => Link::Speed100Mbps, 227 | 5 => Link::Speed1Gbps, 228 | 6 => Link::Speed10Gbps, 229 | _ => Link::Unknown, 230 | }; 231 | 232 | let stat = SpeedStat { port_no, link }; 233 | stats.push(stat); 234 | } 235 | 236 | Ok(SpeedStats { stats }) 237 | } 238 | } 239 | 240 | // --------------------------------------------------------------------------------------------------------------------- 241 | // ProSafeSwitch 242 | // --------------------------------------------------------------------------------------------------------------------- 243 | 244 | pub struct ProSafeSwitch { 245 | hostname: String, 246 | if_name: String, 247 | timeout: Duration, 248 | } 249 | 250 | impl ProSafeSwitch { 251 | pub fn new(hostname: &str, if_name: &str) -> Self { 252 | ProSafeSwitch { 253 | hostname: String::from(hostname), 254 | if_name: String::from(if_name), 255 | timeout: Duration::new(1, 0), 256 | } 257 | } 258 | 259 | fn request( 260 | hostname: &str, 261 | if_name: &str, 262 | timeout: &Duration, 263 | cmd: Cmd, 264 | ) -> Result, Error> { 265 | let iface = Interface::get_by_name(if_name)? 266 | .ok_or_else(|| format_err!("failed to get network interface '{}'", if_name))?; 267 | 268 | let req = QueryRequest::new(cmd, iface.hardware_addr()?, HardwareAddr::zero()); 269 | let req = req.encode()?; 270 | 271 | let socket = UdpSocket::bind("0.0.0.0:63321")?; 272 | let _ = socket.set_read_timeout(Some(*timeout)); 273 | 274 | let sw_addr = format!("{}:{}", hostname, 63322) 275 | .to_socket_addrs() 276 | .unwrap() 277 | .next() 278 | .unwrap(); 279 | socket.send_to(&req, sw_addr)?; 280 | 281 | let mut buf = [0; 1308]; 282 | let (_len, _src_addr) = socket.recv_from(&mut buf)?; 283 | 284 | Ok(Vec::from(&buf as &[u8])) 285 | } 286 | 287 | pub fn find_iface(&self) -> Result { 288 | let ifaces = 289 | Interface::get_all().map_err(|_| format_err!("failed to get network interfaces"))?; 290 | 291 | for iface in ifaces { 292 | let ret = 293 | ProSafeSwitch::request(&self.hostname, &iface.name, &self.timeout, Cmd::PortStat)?; 294 | let stat = PortStats::decode(&ret)?; 295 | if stat.stats.len() > 0 { 296 | return Ok(iface.name.clone()); 297 | } 298 | } 299 | 300 | Err(format_err!("failed to find accessible network interface")) 301 | } 302 | 303 | pub fn port_stat(&self) -> Result { 304 | let ret = 305 | ProSafeSwitch::request(&self.hostname, &self.if_name, &self.timeout, Cmd::PortStat)?; 306 | Ok(PortStats::decode(&ret)?) 307 | } 308 | 309 | pub fn speed_stat(&self) -> Result { 310 | let ret = 311 | ProSafeSwitch::request(&self.hostname, &self.if_name, &self.timeout, Cmd::SpeedStat)?; 312 | Ok(SpeedStats::decode(&ret)?) 313 | } 314 | } 315 | 316 | // --------------------------------------------------------------------------------------------------------------------- 317 | // Test 318 | // --------------------------------------------------------------------------------------------------------------------- 319 | 320 | #[cfg(test)] 321 | mod tests { 322 | use super::*; 323 | use hex_literal::*; 324 | 325 | #[test] 326 | fn test_query_encode() { 327 | let req = QueryRequest::new(Cmd::PortStat, HardwareAddr::zero(), HardwareAddr::zero()); 328 | let dat = req.encode().unwrap(); 329 | let expected = hex!( 330 | "010100000000000000000000000000000000000000000a0a4e5344500000000010000000ffff0000" 331 | ); 332 | assert_eq!(dat[0..22], expected[0..22]); 333 | assert_eq!(dat[24..], expected[24..]); 334 | } 335 | 336 | #[test] 337 | fn test_port_stat_decode() { 338 | let dat = hex!( 339 | "01020000000000000cc47a3a39a808bd436a1596000000804e5344500000000010000031010000001c7e67379200000021fc85e1c40000000000000000000000000000000000000000000000000000000000000000100000310200000053ff78f7460000003581ed74c700000000000000000000000000000000000000000000000000000000000dce56100000310300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000031040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000003105000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000310600000177e8658769000001cae4c262b90000000000000000000000000000000000000000000000000000000000000000100000310700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000031080000000027f5c6f700000000450e67bd0000000000000000000000000000000000000000000000000000000000000000ffff0000" 340 | ); 341 | let stat = PortStats::decode(&dat).unwrap(); 342 | 343 | let expected = PortStats { 344 | stats: vec![ 345 | PortStat { 346 | port_no: 1, 347 | recv_bytes: 122379777938, 348 | send_bytes: 145970553284, 349 | error_pkts: 0, 350 | }, 351 | PortStat { 352 | port_no: 2, 353 | recv_bytes: 360768403270, 354 | send_bytes: 229813089479, 355 | error_pkts: 904790, 356 | }, 357 | PortStat { 358 | port_no: 3, 359 | recv_bytes: 0, 360 | send_bytes: 0, 361 | error_pkts: 0, 362 | }, 363 | PortStat { 364 | port_no: 4, 365 | recv_bytes: 0, 366 | send_bytes: 0, 367 | error_pkts: 0, 368 | }, 369 | PortStat { 370 | port_no: 5, 371 | recv_bytes: 0, 372 | send_bytes: 0, 373 | error_pkts: 0, 374 | }, 375 | PortStat { 376 | port_no: 6, 377 | recv_bytes: 1614511703913, 378 | send_bytes: 1970932966073, 379 | error_pkts: 0, 380 | }, 381 | PortStat { 382 | port_no: 7, 383 | recv_bytes: 0, 384 | send_bytes: 0, 385 | error_pkts: 0, 386 | }, 387 | PortStat { 388 | port_no: 8, 389 | recv_bytes: 670418679, 390 | send_bytes: 1158571965, 391 | error_pkts: 0, 392 | }, 393 | ], 394 | }; 395 | assert_eq!(stat, expected); 396 | } 397 | 398 | #[test] 399 | fn test_speed_stat_decode() { 400 | let dat = hex!( 401 | "01020000000000000cc47a3a39a828c68e6c2ebc000005ab4e534450000000000c0000030100010c0000030201010c0000030302010c0000030403010c0000030504010c0000030605010c0000030706010c000003080701ffff0000" 402 | ); 403 | let stat = SpeedStats::decode(&dat).unwrap(); 404 | 405 | let expected = SpeedStats { 406 | stats: vec![ 407 | SpeedStat { 408 | port_no: 1, 409 | link: Link::None, 410 | }, 411 | SpeedStat { 412 | port_no: 2, 413 | link: Link::Speed10Mbps, 414 | }, 415 | SpeedStat { 416 | port_no: 3, 417 | link: Link::Speed10Mbps, 418 | }, 419 | SpeedStat { 420 | port_no: 4, 421 | link: Link::Speed100Mbps, 422 | }, 423 | SpeedStat { 424 | port_no: 5, 425 | link: Link::Speed100Mbps, 426 | }, 427 | SpeedStat { 428 | port_no: 6, 429 | link: Link::Speed1Gbps, 430 | }, 431 | SpeedStat { 432 | port_no: 7, 433 | link: Link::Speed10Gbps, 434 | }, 435 | SpeedStat { 436 | port_no: 8, 437 | link: Link::Unknown, 438 | }, 439 | ], 440 | }; 441 | assert_eq!(stat, expected); 442 | } 443 | } 444 | --------------------------------------------------------------------------------