├── .gitignore
├── src
├── cfst_rpc.rs
├── args.rs
├── ping.rs
├── speed.rs
├── main.rs
├── server_comm.rs
└── install_upgrade.rs
├── .idea
├── .gitignore
├── vcs.xml
├── modules.xml
└── CloudflareSpeedtest-Slave.iml
├── Cross.toml
├── LICENSE
├── Dockerfile
├── .github
└── workflows
│ ├── windows.yaml
│ └── linux.yaml
├── Cargo.toml
├── tls_cert
├── server.pem
└── server.key
├── proto
├── cfst_rpc.proto
└── cfst_rpc.rs
├── README.md
└── Cargo.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 | /binary
3 | /build.sh
4 |
--------------------------------------------------------------------------------
/src/cfst_rpc.rs:
--------------------------------------------------------------------------------
1 | tonic::include_proto!("cfst_rpc");
2 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Cross.toml:
--------------------------------------------------------------------------------
1 | [target.x86_64-unknown-linux-musl]
2 | pre-build = [
3 | "apt-get update",
4 | "apt-get install --assume-yes musl musl-dev musl-tools protobuf-compiler"
5 | ]
6 |
7 | [target.aarch64-unknown-linux-musl]
8 | pre-build = [
9 | "apt-get update",
10 | "apt-get install --assume-yes musl musl-dev musl-tools protobuf-compiler"
11 | ]
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (C) 2004 Sam Hocevar
2 |
3 | Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long as the name is changed.
4 |
5 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
6 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
7 |
8 | 0. You just DO WHAT THE FUCK YOU WANT TO.
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM alpine:latest
2 |
3 | ARG TARGETARCH
4 |
5 | ENV SERVER=backend.cloudflare.su:2333
6 | ENV TOKEN=cfst1234
7 | ENV MAX_MBPS=500
8 |
9 | ## 你必须要先将二进制文件保存在 ./binary/linux/{amd|arm}64 目录下
10 | COPY ./binary/$TARGETARCH /CloudflareSpeedtest-Slave
11 |
12 | RUN chmod +x /CloudflareSpeedtest-Slave
13 |
14 | CMD /CloudflareSpeedtest-Slave -s "$SERVER" -t "$TOKEN" -m "${MAX_MBPS}" --debug --disable-auto-upgrade
15 |
--------------------------------------------------------------------------------
/.idea/CloudflareSpeedtest-Slave.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.github/workflows/windows.yaml:
--------------------------------------------------------------------------------
1 | name: Windows Build
2 |
3 | on:
4 | push:
5 | branches:
6 | - "main"
7 |
8 | jobs:
9 | release:
10 | name: Release - Windows
11 | runs-on: windows-latest
12 | steps:
13 | - name: Checkout
14 | uses: actions/checkout@v3
15 | - name: Install Protoc
16 | uses: arduino/setup-protoc@v3
17 | - name: Set up nasm
18 | uses: ilammy/setup-nasm@v1
19 | - name: Set up Rust
20 | uses: actions-rs/toolchain@v1
21 | with:
22 | toolchain: stable
23 | profile: minimal
24 | override: true
25 | - name: Build
26 | run: cargo build --release
27 | - name: Upload binary
28 | uses: actions/upload-artifact@v3
29 | with:
30 | name: x86_64-pc-windows-msvc
31 | path: target/release/CloudflareSpeedtest-Slave.exe
32 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "CloudflareSpeedtest-Slave"
3 | version = "0.0.6"
4 | authors = ["GenshinMinecrat "]
5 | edition = "2021"
6 | description = "A tool, written in Rust, for testing the speed of Cloudflare IPs."
7 | readme = "README.md"
8 | repository = "https://github.com/GenshinMinecraft/CloudflareSpeedtest-Slave"
9 | license = "WTFPL"
10 | keywords = ["Cloudflare", "Speedtest"]
11 |
12 |
13 | [dependencies]
14 | clap = { version = "4.5.9", features = ["derive"] }
15 | ipnetwork = "0.20.0"
16 | log = "0.4.22"
17 | prost = "0.13.1"
18 | reqwest = { version = "0.12.5", features = ["json", "blocking", "rustls-tls"], default-features = false }
19 | rustls = "0.23.11"
20 | simple_logger = "5.0.0"
21 | tokio = { version = "1.38.0", features = ["full"] }
22 | tokio-stream = "0.1.15"
23 | tonic = "0.12.0"
24 | tonic-build = "0.12.0"
25 | url = "2.5.2"
26 | uuid = { version = "1.10.0", features = [ "v4" ] }
27 | webpki-roots = "0.26.3"
28 | rand = "0.9.0-alpha.1"
29 | futures = "0.3.30"
30 | tokio-rustls = "0.26.0"
31 |
32 | [build-dependencies]
33 | tonic-build = "0.12.0"
34 |
35 | [profile.release]
36 | codegen-units = 1
37 | lto = "fat"
38 | opt-level = "s"
39 | panic = "abort"
40 |
--------------------------------------------------------------------------------
/tls_cert/server.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIEBDCCAuygAwIBAgIEZW3j1TANBgkqhkiG9w0BAQsFADCBmjELMAkGA1UEBhMC
3 | R0IxGjAYBgNVBAMMEUhpZ2ggUGluZyBOZXR3b3JrMQ8wDQYDVQQIDAZMb25kb24x
4 | DzANBgNVBAcMBkxvbmRvbjEXMBUGA1UECgwOSElHSCBQSU5HIExURC4xFzAVBgNV
5 | BAsMDkhJR0ggUElORyBMVEQuMRswGQYJKoZIhvcNAQkBFgxnbUBoaWdocC5pbmcw
6 | HhcNMjQwNzAyMTIzMTIzWhcNMzQwNjMwMTIzMTIzWjCBmjELMAkGA1UEBhMCR0Ix
7 | GjAYBgNVBAMMEUhpZ2ggUGluZyBOZXR3b3JrMQ8wDQYDVQQIDAZMb25kb24xDzAN
8 | BgNVBAcMBkxvbmRvbjEXMBUGA1UECgwOSElHSCBQSU5HIExURC4xFzAVBgNVBAsM
9 | DkhJR0ggUElORyBMVEQuMRswGQYJKoZIhvcNAQkBFgxnbUBoaWdocC5pbmcwggEi
10 | MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDAm6Wsu6DitzLj52DPWrjGRcYI
11 | zbpJZ3fRatnAgyCyfBSFEWP3s4nn0EXf8LH7HAnSOS2XD81DJ+I92PMmLAm9+Ynn
12 | DyelOHuudGb/ndB64Be3OIEe3+hluYPt7V7Dl7azTUJh7vYT9KdLfaOO4vZoLHPl
13 | Wmx7b9cSIyQKBu7Vz07Vo/Z4aKUWSLYFGtcoa/0ao6rE4R5c/a0hS2W0GeSvmYWe
14 | ZJRHSHoIeDsv9ob8xlkPa2k8S6eiSwh3Vb0cGeE4LPZ1UDF3XeymEdgPDsLtMIzY
15 | x3dUHQIPiBVWtFON8QsME7Eq3OPtchlBt+GZ6RVKgTZsucqV5FB0Mx1twzNFAgMB
16 | AAGjUDBOMB0GA1UdDgQWBBT3e5ICWXokWniWHu3saUx5cv5vhDAfBgNVHSMEGDAW
17 | gBT3e5ICWXokWniWHu3saUx5cv5vhDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
18 | CwUAA4IBAQBTjQbLr9uv7N8kE7UEV35uhuWB8379Fr4j/ACF+Hye02w3j1DQ+Fem
19 | V4PvxBixaK0AFKam/TDfQrfYrGpAW5hK5fcohTp9OBkHimmCiS/JE2vpQFwXYGk7
20 | Y0Cqdw9/jW7VasMLJ4qFdxO464918r+7H8bQK8OsmAq0C/24R6TG9T21AxwbxUic
21 | 1sMBa38npvHJxbQ84kwCoN40xrZyxZ9Yy0VDIpF7cG+QYqKVDy/sgv9T3VbAAh8f
22 | tkBGy4frBisZNAvYFwHzB7d09MuIHBF+7Z9rp2ZLnyWh+UA7jkRWzmlqt9Vg1HcY
23 | 2g89uAA0j7T+owgPeWmCV6713WqWYUED
24 | -----END CERTIFICATE-----
25 |
--------------------------------------------------------------------------------
/.github/workflows/linux.yaml:
--------------------------------------------------------------------------------
1 | # 定义一个名为Rust Release的GitHub Actions工作流,用于发布Rust程序
2 | name: Linux Build
3 |
4 | # 工作流在push到main分支时触发
5 | on:
6 | push:
7 | branches:
8 | - "main"
9 |
10 | jobs:
11 | release:
12 | name: Release - ${{ matrix.platform.release_for }}
13 | strategy:
14 | matrix:
15 | platform:
16 | - release_for: linux_x86_64
17 | os: ubuntu-latest
18 | target: x86_64-unknown-linux-musl
19 | bin: CloudflareSpeedtest-Slave
20 | name: CloudflareSpeedtest-Slave-linux-x86_64.tar.gz
21 | command: build
22 | - release_for: linux_aarch64
23 | os: ubuntu-latest
24 | target: aarch64-unknown-linux-musl
25 | bin: CloudflareSpeedtest-Slave
26 | name: CloudflareSpeedtest-Slave-linux-aarch64.tar.gz
27 | command: build
28 | runs-on: ${{ matrix.platform.os }}
29 | steps:
30 | - name: Checkout
31 | uses: actions/checkout@v3
32 | - name: Install Lib
33 | run: sudo apt update && sudo apt install -y protobuf-compiler musl-tools musl-dev musl
34 | - name: Build binary
35 | uses: houseabsolute/actions-rust-cross@v0
36 | with:
37 | command: ${{ matrix.platform.command }}
38 | target: ${{ matrix.platform.target }}
39 | args: "--locked --release"
40 | strip: true
41 | - name: Upload binary
42 | uses: actions/upload-artifact@v3
43 | with:
44 | name: ${{ matrix.platform.target }}
45 | path: target/${{ matrix.platform.target }}/release/${{ matrix.platform.bin }}
46 |
--------------------------------------------------------------------------------
/proto/cfst_rpc.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package cfst_rpc;
4 |
5 | service CloudflareSpeedtest {
6 | rpc Bootstrap(BootstrapRequest) returns (BootstrapResponse);
7 | rpc Speedtest(SpeedtestRequest) returns (stream SpeedtestResponse);
8 | rpc SpeedtestResult(SpeedtestResultRequest) returns (SpeedtestResultResponse);
9 | rpc Upgrade(UpgradeRequest) returns (UpgradeResponse);
10 | rpc Alive(Ping) returns (Pong);
11 | }
12 |
13 | message BootstrapRequest {
14 | int32 maximum_mbps = 1;
15 | string client_version = 2;
16 | string bootstrap_token = 3;
17 | string node_id = 4;
18 | }
19 |
20 | message BootstrapResponse {
21 | bool success = 1;
22 | bool should_upgrade = 2;
23 | string message = 3;
24 | string session_token = 4; // token to use for communicating with the control node thereafter until the exit of the process
25 | }
26 |
27 | message UpgradeRequest {}
28 |
29 | message UpgradeResponse {
30 | bool success = 1;
31 | string message = 2;
32 | string upgrade_url = 3;
33 | }
34 |
35 | message IPResult {
36 | string ip_address = 1;
37 | int32 latency = 2;
38 | int32 speed = 3;
39 | }
40 |
41 | message SpeedtestRequest {
42 | string session_token = 1;
43 | string node_id = 2;
44 | }
45 |
46 | message SpeedtestResponse {
47 | repeated string ip_ranges = 1;
48 | int32 minimum_mbps = 2;
49 | int32 maximum_ping = 3;
50 | string speed_url = 4;
51 | }
52 |
53 | message SpeedtestResultRequest {
54 | repeated IPResult ip_results = 1;
55 | string session_token = 2;
56 | string node_id = 3;
57 | }
58 |
59 | message SpeedtestResultResponse {
60 | bool success = 1;
61 | string message = 2;
62 | }
63 |
64 | message Ping{}
65 | message Pong{}
--------------------------------------------------------------------------------
/tls_cert/server.key:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDAm6Wsu6DitzLj
3 | 52DPWrjGRcYIzbpJZ3fRatnAgyCyfBSFEWP3s4nn0EXf8LH7HAnSOS2XD81DJ+I9
4 | 2PMmLAm9+YnnDyelOHuudGb/ndB64Be3OIEe3+hluYPt7V7Dl7azTUJh7vYT9KdL
5 | faOO4vZoLHPlWmx7b9cSIyQKBu7Vz07Vo/Z4aKUWSLYFGtcoa/0ao6rE4R5c/a0h
6 | S2W0GeSvmYWeZJRHSHoIeDsv9ob8xlkPa2k8S6eiSwh3Vb0cGeE4LPZ1UDF3Xeym
7 | EdgPDsLtMIzYx3dUHQIPiBVWtFON8QsME7Eq3OPtchlBt+GZ6RVKgTZsucqV5FB0
8 | Mx1twzNFAgMBAAECggEAI1Noy4mONIbNOqeRRfaptRPPAoZZCGWFwE8MqRZjxNil
9 | GtLZtvCi9nVom24V9qxp0LjT98TaLNr/z8AeuH2TO9isxkgtSUxWwuRuj6tuNVss
10 | flpKtFL02NNxsw26N713sOMWrceaMobIuDvO58IQ14Jvrz0qcGlO1PDFB2HGJEiT
11 | sbS9H2/cm9IAoV/Jh3t5VBd8+oz37psOihO2ecT8z9WKKPhJeps7STwoSXt23x+7
12 | AHBRabvr4HL9o+MqNKEupTwIxRY/PRlX86evBvWrDglVMXaA0nOFfcSOz+WUjoPG
13 | lk2u3ENp23LyNA9UN0ug6UzUeMKfRUMRKPMYaGNaAQKBgQDyxsibqhGnF8Z2TpP6
14 | nZneSQwkqfV7OectFs1Qywya1o41dLY/zcqrMn9bVff2oUPEZIGvMYiyN7MR6cMD
15 | X7IkEFv7h+DdfJO9wJjBQTbmhlcvXWAOP3C2SNw59or4na24FNaTtxFsIz3SqIMk
16 | bu4h3Z2dk4+xlaf9KO34e1SxIQKBgQDLGVN/3EpMNOP0KVsYs/JkANsOyzmeoYiM
17 | B2CtzBkpCBrcVZZsm3e4FG3lGTYvsgJSjjfOyPcliqZQ4TbCbgrPgWFsCad2U2Ba
18 | aGt8jSsMy/aEWt4IieOWHuLLAluF9Ug94RVOT4pAWsG+UD/kpApduXBhcKdp2Zgc
19 | LMQivjbppQKBgGGYvAioA9SyYBwrVp3HQZX0s6cBlCfnjSG5Kuyx0+1jF2Qx+RoJ
20 | NtI/yKcFFlvVVJLc/K1bMmLCtYAcA0OV8t1AnlmttB4V+KatiDsYZmOh2ea2mOjh
21 | ZARDohTDIfb0HGQGLITRcXWRbUcEa0P4PE7s8nHoYjm3ugKxs4jSu6dBAoGAAPRZ
22 | hBxQ7RLCj38yQmd2GCo43VTvLGOt9JqERczTwXGcTrTIRDJm2aKe8ZiwvIClqiWo
23 | 9XvUTYTdSzwDud4yhs8g2hUhiFjT9xjOiINRVHoQ6oZSzM95FleG0VVtgK+qa0AH
24 | jZqqF6tVhcNyyWxL8CzS7mJNJx4yrM85DMDAGVECgYAydI7iyW8WGKfr0m5lP+IY
25 | OEPXDmmwcBm3IzuI/xIsbEsJf8ZffsOR1Krvf17PEYkAMezNVBg6IVkRWZ/5MWC3
26 | rVrYsUqkfqcqSKzizXaPCGRG1mJ0pdjp+OZIf33bj+TXg0H4u9XTDoM73SNobErB
27 | t2oXP/DQhz4pG6vDyxZZ+Q==
28 | -----END PRIVATE KEY-----
29 |
--------------------------------------------------------------------------------
/src/args.rs:
--------------------------------------------------------------------------------
1 | use clap::Parser;
2 |
3 | /// Cloudflare IP Speedtest Backend
4 | #[derive(Parser, Debug, Clone)]
5 | #[command(version, about, long_about = None)]
6 | pub struct Args {
7 | // 主端地址
8 | /// Frontend Server Address
9 | #[arg(short, long, default_value_t = return_default_server())]
10 | pub server: String,
11 |
12 | // Bootstrap Token 设置
13 | /// Token Setting
14 | #[arg(short, long, default_value_t = return_default_bootstrap_token())]
15 | pub token: String,
16 |
17 | // 最大带宽
18 | /// Bandwidth (in Mbps)
19 | #[arg(short, long, default_value_t = 114514)]
20 | pub max_mbps: i32,
21 |
22 | // Debug Log 设置
23 | /// Enable Debug Log
24 | #[arg(long, default_value_t = false)]
25 | pub debug: bool,
26 |
27 | // 开始 Install
28 | /// Install For Systemd
29 | #[arg(long, default_value_t = false)]
30 | pub install: bool,
31 |
32 | // 关闭自动更新
33 | /// Disable Auto Upgrade Mode
34 | #[arg(long, default_value_t = false)]
35 | pub disable_auto_upgrade: bool,
36 | }
37 |
38 | /**
39 | * 返回默认服务器的地址。
40 | *
41 | * 该函数生成并返回一个字符串, 包含了默认服务器的IP地址和端口号。
42 | * 这是一个硬编码的值, 用于在没有特定服务器配置的情况下提供一个默认的选择。
43 | *
44 | * @return String 返回一个字符串, 格式为"IP地址:端口号"。
45 | */
46 | fn return_default_server() -> String {
47 | return "backend.cloudflare.su:2333".to_string();
48 | }
49 |
50 | /**
51 | * 返回默认的启动令牌字符串。
52 | *
53 | * 此函数生成一个固定的字符串作为默认的启动令牌。这个令牌用于应用程序启动时的特定验证或配置过程。
54 | * 选择“cfst1234”作为默认值是因为它是一个预先定义的、不会引起混淆的值。
55 | *
56 | * @return 字符串类型的默认启动令牌。
57 | */
58 | fn return_default_bootstrap_token() -> String {
59 | return "cfst1234".to_string();
60 | }
61 |
62 | /**
63 | * 初始化程序的参数对象。
64 | *
65 | * 该函数通过解析命令行参数, 创建并返回一个Args对象。
66 | * Args对象包含了程序运行时的所有配置参数, 这些参数可以通过命令行进行定制。
67 | *
68 | * 返回值:
69 | * Args - 一个包含了程序运行参数的数据结构。
70 | */
71 | pub fn init_args() -> Args {
72 | // 使用Args::parse方法从命令行参数中构建Args对象。
73 | let args: Args = Args::parse();
74 | // 返回构建好的Args对象。
75 | return args;
76 | }
77 |
--------------------------------------------------------------------------------
/src/ping.rs:
--------------------------------------------------------------------------------
1 | use futures::{stream::iter, StreamExt};
2 | use ipnetwork::IpNetwork;
3 | use log::debug;
4 | use std::{collections::HashMap, error::Error, time::Duration};
5 | use tokio::io::AsyncWriteExt;
6 | use tokio::{
7 | net::TcpStream,
8 | sync::Mutex,
9 | time::{timeout, Instant},
10 | };
11 |
12 | async fn ping_single_ip(ip: String, timeout_ms: i32) -> i32 {
13 | let addr = format!("{}:80", ip);
14 | let time_out = Duration::from_millis(timeout_ms as u64);
15 | let start = Instant::now();
16 | match timeout(time_out, TcpStream::connect(&addr)).await {
17 | Ok(tmp) => match tmp {
18 | Ok(mut tcpstream) => {
19 | let duration = start.elapsed().as_millis() as i32;
20 | tcpstream.shutdown().await.unwrap();
21 | drop(tcpstream);
22 | if duration <= 10 {
23 | -1
24 | } else {
25 | duration
26 | }
27 | }
28 | Err(_) => -1,
29 | },
30 | Err(_) => -1,
31 | }
32 | }
33 |
34 | pub async fn ping_ips(ips: Vec, maximum_ping: i32) -> HashMap {
35 | let ip_and_ping_map = std::sync::Arc::new(Mutex::new(HashMap::new()));
36 | iter(ips)
37 | .for_each_concurrent(Some(100), |ip| {
38 | let clone_map = ip_and_ping_map.clone();
39 | async move {
40 | let duration = ping_single_ip(ip.clone(), maximum_ping).await;
41 | if duration != -1 {
42 | debug!("IP {} Ping {}ms", ip, duration);
43 | let mut map_lock = clone_map.lock().await;
44 | map_lock.insert(ip, duration as u128);
45 | } else {
46 | debug!("IP {} 不可达", ip);
47 | let mut map_lock = clone_map.lock().await;
48 | map_lock.insert(ip, u128::MAX);
49 | }
50 | }
51 | })
52 | .await;
53 | let mut inner_map = ip_and_ping_map.lock().await;
54 | std::mem::take(&mut *inner_map)
55 | }
56 |
57 | pub async fn ip_cidr_to_ips(ip_cidr: Vec) -> Result, Box> {
58 | let ip_cidr_string: Vec = ip_cidr.into_iter().map(|fs| fs.to_string()).collect();
59 |
60 | let mut ip_addresses: Vec = Vec::new();
61 |
62 | for ips in ip_cidr_string {
63 | let network = ips.parse::()?;
64 | for single_ip in network.iter() {
65 | ip_addresses.push(single_ip.to_string());
66 | }
67 | }
68 |
69 | Ok(ip_addresses)
70 | }
71 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CloudflareSpeedtest-Slave
2 |
3 | 
4 | 
5 | 
6 | 
7 |
8 | 一个轻量级、高性能的 Cloudflare IP Speedtest 后端, 采用 Rust 编写
9 |
10 | ## 简介
11 |
12 | 本后端适用于 Moohr 开发的 Cloudflare Speedtest 主端, 用于分布式 Cloudflare 测速
13 |
14 | 为 Moohr 开发的 Cloudflare Speedtest 主端**官方钦定**后端, 如果有需要自行编写后端的需求可参考该项目
15 |
16 | ## 使用
17 |
18 | ```
19 | A tool, written in Rust, for testing the speed of Cloudflare IPs.
20 |
21 | Usage: CloudflareSpeedtest-Slave [OPTIONS]
22 |
23 | Options:
24 | -s, --server Frontend Server Address [default: 47.238.130.86:2333]
25 | -t, --token Token Setting [default: cfst1234]
26 | -m, --max-mbps Bandwidth (in Mbps) [default: 500]
27 | --debug Enable Debug Log
28 | --install Install For Systemd
29 | --disable-auto-upgrade Disable Auto Upgrade ModeD
30 | -h, --help Print help
31 | -V, --version Print version
32 | ```
33 |
34 | - `-s`/`--server`: 指定主端服务器, 默认为该项目官方服务器, 请自行更改
35 | - `-t`/`--token`: 连接主端时的鉴权 Token, 请自行更改
36 | - `-m`/`--max-mbps`: 报告给主端的最大带宽, 单位 Mbps
37 | - `--debug`: 开启 Debug Log
38 | - `--install`: 使用 Systemd 安装 CloudflareSpeedtest-Slave, 仅限于使用 Systemd 的 Linux
39 | - `--disable-auto-upgrade`: 禁用自动升级, 默认为开启
40 | - `-h`: 显示此帮助
41 | - `-V`/`--version`: 显示版本
42 |
43 | ## Docker 使用
44 |
45 | 首先, 请安装 Docker:
46 |
47 | ```bash
48 | curl -fsSL https://test.docker.com -o test-docker.sh
49 | sudo sh test-docker.sh
50 |
51 | # 如果您在中国大陆, 可能需要 Docker 镜像:
52 | curl -fsSL https://gdk.rtc.ovh | bash -s docker --mirror Aliyun
53 | ```
54 |
55 | 随后运行 Docker:
56 |
57 | ```bash
58 | docker run -d --restart=always --name CloudflareSpeedtest-Slave \
59 | -e TOKEN=cfst1234 \
60 | -e MAX_MBPS=500 \
61 | -e SERVER=backend.cloudflare.su:2333 \
62 | dp.rtc.ovh/genshinminecraft/cloudflarespeedtest-slave:v0.0.6
63 | ```
64 |
65 | 目前, 我们只提供了 `arm64` / `amd64` 架构的镜像, 如果需要其他架构的镜像, 请自行编译主程序后编写 Dockerfile
66 |
67 | ## 贡献
68 |
69 | 我们欢迎 Issue 和 Pull Request, 也可以前往我们的[内测群组](https://t.me/+Gbqf_XAhVIphZmY1)反馈
70 |
71 | ## 编译
72 |
73 | ### Cargo
74 |
75 | ```bash
76 | git clone https://github.com/GenshinMinecraft/CloudflareSpeedtest-Slave.git
77 | cd CloudflareSpeedtest-Slave
78 | cargo build --release --target x86_64-unknown-linux-musl # Or aarch64-unknown-linux-musl
79 | ./target/x86_64-unknown-linux-musl/release/CloudflareSpeedtest-Slave # Or aarch64-unknown-linux-musl
80 | ```
81 |
82 | 请注意: 当前我们尚未测试除了 `linux-x86_64` 与 `linux-arm64` 还有 `windows-x86_64` 的其他平台, 当您有其他系统 / 架构的需求, 请自行编译
83 |
84 | ### Docker
85 |
86 | 请事先将已经编译好的 `arm64` / `amd64` 二进制文件放入本项目根目录下的 `binary/` 文件夹 (没有请自行创建)
87 |
88 | 需要: `binary/arm64` 与 `binary/amd64`
89 |
90 | ```bash
91 | docker buildx build --platform linux/amd64,linux/arm64 .
92 | ```
93 |
94 | ## 鸣谢
95 |
96 | 感谢所有开源工作者!
97 |
98 | - Cloudflare: 赞美大爹!
99 | - 通义灵码: 为本项目提供了详细的注释编写, 所以该项目中几乎所有的注释都是它写的
--------------------------------------------------------------------------------
/src/speed.rs:
--------------------------------------------------------------------------------
1 | use log::{error, info};
2 | use std::net::ToSocketAddrs;
3 | use std::process::exit;
4 | use std::sync::Arc;
5 | use tokio::io::{AsyncReadExt, AsyncWriteExt};
6 | use tokio::net::TcpStream;
7 | use tokio::time::Instant;
8 | use tokio_rustls::{rustls, TlsConnector};
9 | use url::Url;
10 |
11 | /**
12 | * 测量给定IP地址和URL的下载速度。
13 | *
14 | * @param speedtest_url 测速URL, 用于发起下载请求。
15 | * @param ip 要测试速度的IP地址。
16 | * @param speed_time 测速时间(秒), 用于限制下载时间。
17 | * @return 返回下载速度(Mbps)。
18 | */
19 | pub async fn speed_one_ip(speedtest_url: String, ip: String, speed_time: u32) -> f64 {
20 | let url = match Url::parse(speedtest_url.as_str()) {
21 | Ok(parsed_url) => parsed_url,
22 | Err(e) => {
23 | error!("无法正确解析 Speedtest URL: {}", e);
24 | return -1.0;
25 | }
26 | };
27 |
28 | let domain = match &url.domain() {
29 | Some(tmp) => match rustls::pki_types::ServerName::try_from(tmp.to_string()) {
30 | Ok(tmp) => tmp,
31 | Err(e) => {
32 | error!("无法获取 Speedtest URL 中的域名: {}", e);
33 | return -1.0;
34 | }
35 | },
36 | None => {
37 | error!("无法获取 Speedtest URL 中的域名");
38 | return -1.0;
39 | }
40 | };
41 |
42 | let port = url.port().unwrap_or(443);
43 |
44 | let addr = match (ip.as_str(), port).to_socket_addrs() {
45 | Ok(mut iter) => match iter.next() {
46 | Some(addr) => addr,
47 | None => {
48 | error!("无法正确解析 Speedtest URL");
49 | return -1.0;
50 | }
51 | },
52 | Err(e) => {
53 | error!("无法正确解析 Speedtest URL: {}", e);
54 | return -1.0;
55 | }
56 | };
57 |
58 | let path = url.path();
59 |
60 | let request = format!(
61 | "GET {} HTTP/1.1\r\nHost: {}\r\nConnection: close\r\n\r\n",
62 | path,
63 | domain.to_str()
64 | );
65 |
66 | let mut root_cert_store = rustls::RootCertStore::empty();
67 | root_cert_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
68 |
69 | let config = rustls::ClientConfig::builder()
70 | .with_root_certificates(root_cert_store)
71 | .with_no_client_auth();
72 |
73 | let connector = TlsConnector::from(Arc::new(config));
74 |
75 | let stream = match TcpStream::connect(&addr).await {
76 | Ok(tmp) => tmp,
77 | Err(e) => {
78 | error!("无法创立 Tcp 连接: {}", e);
79 | return -1.0;
80 | }
81 | };
82 |
83 | let mut stream = match connector.connect(domain, stream).await {
84 | Ok(tmp) => tmp,
85 | Err(e) => {
86 | error!("无法创立 Tls 连接: {}", e);
87 | return -1.0;
88 | }
89 | };
90 |
91 | match stream.write_all(request.as_bytes()).await {
92 | Ok(_) => {}
93 | Err(e) => {
94 | error!("无法写入请求: {}", e)
95 | }
96 | }
97 |
98 | let start_time = Instant::now();
99 |
100 | let mut buffer = [0; 1024];
101 |
102 | let mut data = 0;
103 |
104 | loop {
105 | match stream.read(&mut buffer).await {
106 | // 读取结束, 退出循环。
107 | // 没有则退出
108 | Ok(0) => break,
109 | // 成功读取数据, 累加到总下载大小。
110 | // 有则把接收到的放到计数器里
111 | Ok(n) => {
112 | data += n;
113 | if start_time.elapsed().as_secs_f64() >= speed_time as f64 {
114 | break;
115 | }
116 | }
117 | Err(e) => {
118 | eprintln!("下载文件出现错误: {}", e);
119 | exit(1);
120 | }
121 | }
122 | }
123 |
124 | stream.shutdown().await.unwrap();
125 | drop(stream);
126 |
127 | // 计算下载速度(Mbps)。
128 | // 已下载
129 | let bytes_downloaded = data;
130 |
131 | // 总用时
132 | let time_taken: f64 = start_time.elapsed().as_secs_f64();
133 |
134 | // 下载总 Bits
135 | let bits_downloaded: f64 = bytes_downloaded as f64 * 8.0;
136 |
137 | // bps 计算
138 | let download_speed_bps: f64 = bits_downloaded / time_taken;
139 |
140 | // bps -> kbps
141 | let download_speed_kbps: f64 = download_speed_bps / 1000.0;
142 |
143 | // kbps -> mbps
144 | let download_speed_mbps: f64 = download_speed_kbps / 1000.0;
145 |
146 | // 记录测速结果。
147 | info!("IP: {}, 速度: {}mbps", addr.ip(), download_speed_mbps);
148 |
149 | download_speed_mbps
150 | }
151 |
--------------------------------------------------------------------------------
/src/main.rs:
--------------------------------------------------------------------------------
1 | mod args;
2 | mod cfst_rpc;
3 | mod install_upgrade;
4 | mod ping;
5 | mod server_comm;
6 | mod speed;
7 |
8 | use crate::{args::*, cfst_rpc::*, install_upgrade::*, ping::*, server_comm::*, speed::*};
9 |
10 | use cloudflare_speedtest_client::CloudflareSpeedtestClient;
11 | use log::{debug, error, info, warn};
12 | use rustls::crypto::aws_lc_rs;
13 | use simple_logger::init_with_level;
14 | use std::{process::exit, time::Duration};
15 | use tokio::time::timeout;
16 | use tonic::transport::Channel;
17 |
18 | #[tokio::main]
19 | async fn main() {
20 | // 初始化命令行参数
21 | let args: Args = init_args();
22 |
23 | // 根据调试模式设置日志级别
24 | if args.debug {
25 | init_with_level(log::Level::Debug).unwrap();
26 | } else {
27 | init_with_level(log::Level::Info).unwrap();
28 | }
29 |
30 | if args.max_mbps == 114514 && args.install == false {
31 | error!("必须设置 Max Mbps 参数: -m / --max-mbps ");
32 | exit(1);
33 | }
34 |
35 | // 如果命令行参数包含安装选项, 则执行安装操作并退出
36 | if args.install {
37 | install_systemd(args);
38 | exit(1);
39 | }
40 |
41 | let _ = aws_lc_rs::default_provider().install_default().unwrap();
42 |
43 | // 主循环, 用于定期执行速度测试
44 | loop {
45 | // 初始化Cloudflare Speedtest客户端
46 | let client: CloudflareSpeedtestClient =
47 | match init_client(args.clone().server).await {
48 | Ok(tmp) => {
49 | info!("成功初始化 Cloudflare Speedtest 客户端");
50 | tmp
51 | }
52 | Err(e) => {
53 | error!(
54 | "未能成功初始化 Cloudflare Speedtest 客户端, 15sec 后重新连接服务器: {}",
55 | e
56 | );
57 | tokio::time::sleep(Duration::from_secs(15)).await;
58 | continue;
59 | }
60 | };
61 |
62 | // 发送启动请求, 获取节点ID和会话令牌
63 | let (bootstrap_res, node_id, session_token) =
64 | match send_bootstrap(client.clone(), args.max_mbps, args.token.clone()).await {
65 | Ok(tmp) => {
66 | info!("成功获取 Bootstrap 信息");
67 | tmp
68 | }
69 | Err(e) => {
70 | error!("未能成功获取 Bootstrap 信息, 15sec 后重新连接服务器: {}", e);
71 | tokio::time::sleep(Duration::from_secs(15)).await;
72 | continue;
73 | }
74 | };
75 |
76 | // 日志记录当前节点ID和会话令牌
77 | info!(
78 | "当前 Node_ID: {}, Session_token: {}",
79 | node_id, session_token
80 | );
81 |
82 | // 升级客户端二进制文件
83 | upgrade_bin(client.clone(), args.clone(), bootstrap_res.clone()).await;
84 |
85 | loop {
86 | // 发送速度测试请求, 获取测试结果和需要ping的IP列表
87 | let (speedtest_response, need_ping_ips) = match send_speedtest(
88 | client.clone(),
89 | node_id.clone(),
90 | session_token.clone(),
91 | )
92 | .await
93 | {
94 | Ok((res, str)) => {
95 | info!("成功获取 Speedtest 信息, 开始启动测速程序");
96 | (res, str)
97 | }
98 | Err(e) => {
99 | error!("未能成功获取需要测试的 IP, 正在重新连接服务器: {}", e);
100 | break;
101 | }
102 | };
103 |
104 | // 对需要ping的IP进行ping测试, 记录延迟
105 | let mut ips_ping: std::collections::HashMap =
106 | ping_ips(need_ping_ips, speedtest_response.maximum_ping).await;
107 | info!("获取到 {} 个 IP, 开始测试", ips_ping.len());
108 | // 移除延迟过高的IP
109 | ips_ping.retain(|_, &mut value| value != u128::MAX);
110 | info!("符合条件 IP 有 {} 个", ips_ping.len());
111 | debug!("符合条件 IP: {:?}", ips_ping);
112 |
113 | // 测试每个IP的速度, 选择最快且符合最小速度要求的IP
114 | let mut the_last_ip: String = String::new();
115 | let mut the_last_ip_ping: i32 = -1;
116 | let mut the_last_ip_speed: i32 = -1;
117 |
118 | for (speed_ip, ping) in ips_ping.clone() {
119 | let tmp_speed = match timeout(
120 | Duration::from_secs(12),
121 | speed_one_ip(speedtest_response.speed_url.clone(), speed_ip.clone(), 10),
122 | )
123 | .await
124 | {
125 | Ok(tmp) => tmp,
126 | Err(e) => {
127 | error!("IP {} 测速超时: {}", speed_ip, e);
128 | continue;
129 | }
130 | };
131 | if tmp_speed.round() as i32 >= speedtest_response.minimum_mbps {
132 | the_last_ip = speed_ip;
133 | the_last_ip_ping = ping as i32;
134 | the_last_ip_speed = tmp_speed.round() as i32;
135 | break;
136 | } else {
137 | continue;
138 | }
139 | }
140 |
141 | if the_last_ip.is_empty() {
142 | warn!("在测试完所有的 IP 后, 没有发现符合条件的 IP, 请检查您的网络环境, 或请求主端提供者降低最小带宽要求与 Ping 要求");
143 | }
144 |
145 | // 发送速度测试结果
146 | match send_speedtest_result(
147 | the_last_ip,
148 | the_last_ip_ping,
149 | the_last_ip_speed,
150 | client.clone(),
151 | node_id.clone(),
152 | session_token.clone(),
153 | )
154 | .await
155 | {
156 | Ok(_) => info!("成功完成一次 Speedtest, 开始继续接受 Speedtest 信息"),
157 | Err(e) => {
158 | error!("无法发送测试结果, 将会跳过本次测试: {}", e);
159 | continue;
160 | }
161 | }
162 | }
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/src/server_comm.rs:
--------------------------------------------------------------------------------
1 | use std::{error::Error, process::exit, time::Duration};
2 |
3 | use crate::{
4 | cfst_rpc::*, cloudflare_speedtest_client::CloudflareSpeedtestClient, ping::ip_cidr_to_ips,
5 | };
6 |
7 | use log::{debug, error, info, warn};
8 | use tonic::transport::{Channel, Endpoint};
9 | use uuid::Uuid;
10 |
11 | /**
12 | * 异步初始化CloudflareSpeedtest客户端。
13 | *
14 | * 本函数尝试与指定的服务器建立连接, 并返回一个CloudflareSpeedtestClient实例。
15 | * 如果连接成功, 它将打印一条成功连接的消息, 并返回客户端实例。
16 | * 如果连接失败, 它将打印连接错误的消息, 并退出程序。
17 | *
18 | * @param server_url 服务器URL, 用于建立连接。
19 | * @return CloudflareSpeedtestClient实例, 用于后续速度测试操作。
20 | */
21 | pub async fn init_client(
22 | server_url: String,
23 | ) -> Result, Box> {
24 | // 尝试连接到指定的服务器
25 | let endpoint = match Endpoint::from_shared("http://".to_string() + &server_url) {
26 | Ok(tmp) => tmp,
27 | Err(e) => {
28 | error!("无法解析服务器地址: {}", e);
29 | return Err(Box::new(tonic::Status::aborted("无法解析服务器地址")));
30 | }
31 | };
32 |
33 | let client = match CloudflareSpeedtestClient::connect(
34 | endpoint
35 | .timeout(Duration::from_secs(5))
36 | .connect_timeout(Duration::from_secs(5))
37 | .tcp_keepalive(Some(Duration::from_secs(5)))
38 | .http2_keep_alive_interval(Duration::from_secs(5))
39 | .keep_alive_timeout(Duration::from_secs(5))
40 | .keep_alive_while_idle(true),
41 | )
42 | .await
43 | {
44 | Ok(tmp) => {
45 | // 连接成功, 打印成功消息并返回客户端实例
46 | info!("成功连接服务器");
47 | tmp
48 | }
49 | Err(e) => {
50 | // 连接失败, 打印错误消息并返回错误
51 | error!("无法连接服务器: {}", e);
52 | return Err(Box::new(tonic::Status::aborted("无法连接服务器")));
53 | }
54 | };
55 | return Ok(client);
56 | }
57 |
58 | /// 异步发送启动配置请求并处理响应。
59 | ///
60 | /// 此函数创建一个唯一的节点ID, 构造一个启动请求, 并使用给定的CloudflareSpeedtestClient发送该请求。
61 | /// 它处理可能的错误, 检查响应是否成功, 并返回相关的响应数据。
62 | ///
63 | /// 参数:
64 | /// - client: 用于发送启动请求的CloudflareSpeedtestClient实例。
65 | /// - maximum_mbps: 测试允许的最大Mbps值。
66 | /// - bootstrap_token: 用于身份验证的启动令牌。
67 | ///
68 | /// 返回:
69 | /// - BootstrapResponse: 启动请求的响应。
70 | /// - String: 生成的节点ID。
71 | /// - String: 响应中的会话令牌。
72 | pub async fn send_bootstrap(
73 | client: CloudflareSpeedtestClient,
74 | maximum_mbps: i32,
75 | bootstrap_token: String,
76 | ) -> Result<(BootstrapResponse, String, String), Box> {
77 | // 生成一个唯一的节点ID
78 | let node_id: String = Uuid::new_v4().to_string();
79 |
80 | // 构造启动请求对象
81 | let reqwest: BootstrapRequest = BootstrapRequest {
82 | maximum_mbps,
83 | client_version: env!("CARGO_PKG_VERSION").to_string(),
84 | bootstrap_token,
85 | node_id: node_id.clone(),
86 | };
87 |
88 | // 在发送请求前记录请求详情
89 | debug!("BootStrapRequest Message: {:?}", reqwest);
90 |
91 | // 尝试发送启动请求并处理可能的错误
92 | let response: BootstrapResponse = match client.clone().bootstrap(reqwest).await {
93 | Ok(res) => res.get_ref().clone(),
94 | Err(e) => {
95 | error!("发送 Bootstrap 时发送错误: {}", e);
96 | return Err(Box::new(tonic::Status::aborted("Bootstrap Boomed!")));
97 | }
98 | };
99 |
100 | // 记录响应详情
101 | debug!("BootStrapResponse Message: {:?}", response);
102 |
103 | // 检查启动请求是否成功
104 | if response.clone().success != true {
105 | error!(
106 | "Bootstrap 信息已成功, 但返回错误 (也许是 Bootstrap Token 设置错误): {:?}",
107 | response.clone()
108 | );
109 | exit(1);
110 | }
111 |
112 | // 从响应中提取会话令牌
113 | let session_token: String = response.clone().session_token;
114 |
115 | // 如果响应指示需要升级, 则发出警告
116 | if response.clone().should_upgrade == true {
117 | warn!("该后端需更新, 建议更新至最新版本");
118 | }
119 |
120 | // 返回响应、节点ID和会话令牌
121 | return Ok((response, node_id, session_token));
122 | }
123 |
124 | /// 异步发送速度测试请求到主端, 并返回速度测试响应和IP范围列表。
125 | ///
126 | /// 此函数使用提供的Cloudflare Speedtest客户端、节点ID和会话令牌来发起速度测试请求。
127 | /// 它首先构建一个速度测试请求, 然后发送该请求并处理响应。如果请求成功, 它将解析响应中的IP范围,
128 | /// 并将这些信息以及原始响应一起返回。
129 | ///
130 | /// 参数:
131 | /// - `client`: 用于与主端通信的客户端。
132 | /// - `node_id`: 用于速度测试的节点ID。
133 | /// - `session_token`: 用于验证会话的令牌。
134 | ///
135 | /// 返回值:
136 | /// - `Result<(SpeedtestResponse, Vec), Box>`: 包含速度测试响应和IP范围列表的结果。
137 | /// 如果发生错误, 返回一个包含错误详情的Box。
138 | pub async fn send_speedtest(
139 | client: CloudflareSpeedtestClient,
140 | node_id: String,
141 | session_token: String,
142 | ) -> Result<(SpeedtestResponse, Vec), Box> {
143 | // 构建速度测试请求
144 | let reqwest: SpeedtestRequest = SpeedtestRequest {
145 | session_token,
146 | node_id,
147 | };
148 |
149 | // 在发送请求前, 记录请求的详细信息
150 | debug!("SpeedtestRequest Message: {:?}", reqwest);
151 |
152 | // 发送速度测试请求并处理响应
153 | let mut stream = match client.clone().speedtest(reqwest).await {
154 | Ok(tmp) => tmp.into_inner(),
155 | Err(e) => return Err(Box::new(e)),
156 | };
157 |
158 | // 该代码解决了无法检测是否与主端断开连接的问题
159 | // 让我们感谢 Moohr!
160 | // 尝试读取流中的消息并处理可能的错误
161 | loop {
162 | return match stream.message().await {
163 | Ok(Some(response)) => {
164 | // Process the valid response message here
165 | debug!("SpeedtestResponse Message: {:?}", response);
166 |
167 | // Convert IP ranges to specific IP addresses list
168 | let ip_ranges_ips = ip_cidr_to_ips(response.clone().ip_ranges).await?;
169 |
170 | // Exit the loop after processing the message or continue as needed
171 | Ok((response, ip_ranges_ips))
172 | }
173 | Ok(None) => {
174 | // The stream was closed by the sender
175 | error!("与主端的流传输被迫关闭, 这可能是因为后端网络波动或主端崩溃, 正在尝试重新连接...");
176 | // Handle the closure of the stream, possibly attempt to reconnect or exit
177 | Err(Box::new(tonic::Status::aborted(
178 | "Stream was closed by the sender.",
179 | )))
180 | }
181 | Err(e) => {
182 | // An error occurred while fetching the next message
183 | error!("无法接收主端发送的消息, 正在尝试重新连接: {}", e);
184 | Err(Box::new(e))
185 | }
186 | };
187 | }
188 | }
189 |
190 | /// 异步发送速度测试结果到主端。
191 | ///
192 | /// 此函数接收速度测试的IP地址、ping值和速度, 以及一个Cloudflare速度测试客户端,
193 | /// 用于向主端发送速度测试结果。它还接收一个节点ID和会话令牌, 这些可能是用于
194 | /// 鉴权或标识测试来源的。
195 | ///
196 | /// 返回结果为速度测试响应, 或者一个错误盒子。如果成功发送了测试结果, 它将返回测试结果的副本。
197 | pub async fn send_speedtest_result(
198 | ip: String,
199 | ping: i32,
200 | speed: i32,
201 | mut client: CloudflareSpeedtestClient,
202 | node_id: String,
203 | session_token: String,
204 | ) -> Result> {
205 | // 构建IP结果对象, 包含IP地址、延迟和速度信息。
206 | let ipresult = IpResult {
207 | ip_address: ip,
208 | latency: ping,
209 | speed,
210 | };
211 |
212 | // 将IP结果对象封装成一个vector, 以满足请求格式的要求。
213 | let ipresult_vec: Vec = vec![ipresult];
214 |
215 | // 构建速度测试结果请求, 包含IP结果、会话令牌和节点ID。
216 | let reqwest = SpeedtestResultRequest {
217 | ip_results: ipresult_vec,
218 | session_token,
219 | node_id,
220 | };
221 |
222 | // 打印调试信息, 显示即将发送的速度测试结果请求。
223 | debug!("SpeedtestResultResponse Message: {:?}", reqwest);
224 |
225 | // 尝试发送速度测试结果请求, 并处理结果。
226 | return match client.speedtest_result(reqwest).await {
227 | Ok(tmp) => {
228 | // 如果发送成功, 记录信息并返回结果的副本。
229 | info!("成功发送 Speedtest Result 信息");
230 | Ok(tmp.get_ref().clone())
231 | }
232 | Err(e) => {
233 | // 如果发送失败, 记录错误并返回错误盒子。
234 | error!("无法发送 Speedtest Result 信息: {}", e);
235 | Err(Box::new(e))
236 | }
237 | };
238 | }
239 |
--------------------------------------------------------------------------------
/src/install_upgrade.rs:
--------------------------------------------------------------------------------
1 | use std::{
2 | env,
3 | fs::{self, File},
4 | io::{self, Write},
5 | process::{exit, Command},
6 | };
7 |
8 | use crate::{args::Args, cfst_rpc::*, cloudflare_speedtest_client::CloudflareSpeedtestClient};
9 |
10 | use log::{error, info, warn};
11 | use reqwest::Client;
12 | use tonic::transport::Channel;
13 |
14 | /// 安装并配置 Systemd 服务。
15 | ///
16 | /// 此函数检查当前系统是否为 Linux, 并确认是否使用 Systemd 作为服务管理器。
17 | /// 它还需要以 root 用户身份运行, 以复制可执行文件并修改系统服务配置。
18 | /// 最后, 它将根据提供的参数配置并启动一个名为 cfst_slave.service 的 Systemd 服务。
19 | pub fn install_systemd(args: Args) {
20 | // 检查操作系统是否为 Linux
21 | if env::consts::OS != "linux" {
22 | error!("Install 功能仅适用于 Linux 系统");
23 | exit(1);
24 | }
25 |
26 | // 检查系统是否使用 Systemd
27 | match fs::metadata("/usr/bin/systemctl") {
28 | Ok(_) => {
29 | info!("您的系统使用的是 Systemd 服务管理器, 可以正常使用 Install 功能")
30 | }
31 | Err(_) => {
32 | error!("您的系统并非使用 Systemd 作为服务管理器, 无法使用 Install 功能, 请自行配置进程守护");
33 | exit(1);
34 | }
35 | }
36 |
37 | // 确认以 root 用户身份运行
38 | if env::var("USER") == Ok("root".to_string()) {
39 | info!("正在使用 root 用户");
40 | } else {
41 | error!("非 root 用户, 请使用 root 用户运行 Install 功能");
42 | exit(1);
43 | }
44 |
45 | // 检查是否已存在相同名称的服务文件
46 | match fs::metadata("/etc/systemd/system/cfst_slave.service") {
47 | Ok(_) => loop {
48 | warn!("您的当前系统曾经配置过 Systemd 保活服务, 是否覆盖? (Y/N)");
49 | let mut input = String::new();
50 | io::stdin().read_line(&mut input).unwrap();
51 | input = input.trim().to_uppercase();
52 |
53 | if input == "Y" {
54 | info!("正在为您覆盖先前的文件");
55 | break;
56 | } else if input == "N" {
57 | info!("不覆盖, 退出程序");
58 | exit(1);
59 | } else {
60 | warn!("输入错误, 请重新输入 Y 或 N。");
61 | }
62 | },
63 | Err(_) => {}
64 | }
65 |
66 | // 复制可执行文件到 /usr/bin
67 | match env::current_exe() {
68 | Ok(path_to_bin) => {
69 | if path_to_bin.to_str().unwrap() == "/usr/bin/CloudflareSpeedtest-Slave" {
70 | info!("无需复制可执行文件");
71 | } else {
72 | match fs::copy(path_to_bin, "/usr/bin/CloudflareSpeedtest-Slave") {
73 | Ok(_) => {
74 | info!("成功将可执行文件复制到 /usr/bin/CloudflareSpeedtest-Slave");
75 | }
76 | Err(e) => {
77 | error!(
78 | "无法将可执行文件复制到 /usr/bin/CloudflareSpeedtest-Slave: {}",
79 | e
80 | );
81 | exit(1);
82 | }
83 | }
84 | }
85 | }
86 | Err(e) => {
87 | error!("无法获取可执行文件路径: {}", e);
88 | exit(1);
89 | }
90 | }
91 | info!("请输入您机器的最高带宽值(单位:megabit/s mbps):");
92 | let mut max_mbps = String::new();
93 | match io::stdin().read_line(&mut max_mbps) {
94 | Ok(_) => {
95 | let _ = max_mbps
96 | .trim()
97 | .parse::()
98 | .expect("寄! 你输入的不是个合法数值");
99 | }
100 | Err(_) => {
101 | error!("请输入一个合法的最高带宽数值! ");
102 | exit(1);
103 | }
104 | }
105 | let mut debug = "";
106 | if args.debug {
107 | debug = "--debug";
108 | }
109 | // 配置服务文件的内容
110 | let service_config = format!(
111 | "[Unit]
112 | Description=Cloudflare Speedtest Slave
113 | After=network.target
114 |
115 | [Install]
116 | WantedBy=multi-user.target
117 |
118 | [Service]
119 | Type=simple
120 | ExecStart=/usr/bin/CloudflareSpeedtest-Slave -s SERVERURL -t TOKEN -m {} {}
121 | Restart=always
122 | ",
123 | max_mbps, debug
124 | );
125 |
126 | // 根据参数替换服务文件中的占位符
127 | let mut replaced_service_config = service_config.replace("SERVERURL", args.server.as_str());
128 | replaced_service_config = replaced_service_config.replace("TOKEN", args.token.as_str());
129 | /*else {
130 | replaced_service_config =
131 | replaced_service_config.replace("MAXMBPS", args.max_mbps.to_string().as_str());
132 | }
133 | */
134 |
135 | // 删除旧的服务文件
136 | match fs::remove_file("/etc/systemd/system/cfst_slave.service") {
137 | Ok(_) => {
138 | info!("成功删除 /etc/systemd/system/cfst_slave.service");
139 | }
140 | Err(e) => {
141 | error!("无法删除 /etc/systemd/system/cfst_slave.service: {}", e);
142 | }
143 | }
144 |
145 | // 创建并写入新的服务文件
146 | let mut service_file = match File::create("/etc/systemd/system/cfst_slave.service") {
147 | Ok(tmp) => tmp,
148 | Err(e) => {
149 | error!("无法新建 /etc/systemd/system/cfst_slave.service: {}", e);
150 | exit(1);
151 | }
152 | };
153 |
154 | match service_file.write_all(replaced_service_config.as_bytes()) {
155 | Ok(_) => {
156 | info!("成功写入 Systemd 配置文件")
157 | }
158 | Err(e) => {
159 | error!("无法写入 Systemd 配置文件: {}", e);
160 | exit(1);
161 | }
162 | }
163 |
164 | // 重新加载 Systemd 配置
165 | match Command::new("systemctl").arg("daemon-reload").output() {
166 | Ok(tmp) => {
167 | if tmp.status.success() {
168 | info!("成功运行 systemctl daemon-reload");
169 | } else {
170 | error!("无法运行 systemctl daemon-reload")
171 | }
172 | }
173 | Err(e) => {
174 | error!("无法运行 systemctl daemon-reload: {}", e);
175 | exit(1);
176 | }
177 | }
178 |
179 | // 启动服务
180 | match Command::new("systemctl")
181 | .arg("start")
182 | .arg("cfst_slave.service")
183 | .output()
184 | {
185 | Ok(tmp) => {
186 | if tmp.status.success() {
187 | info!("成功启动 Cloudflare Speedtest Slave");
188 | } else {
189 | error!("无法启动 Cloudflare Speedtest Slave")
190 | }
191 | }
192 | Err(e) => {
193 | error!("无法启动 Cloudflare Speedtest Slave: {}", e);
194 | exit(1);
195 | }
196 | }
197 |
198 | // 询问用户是否开启开机自启动
199 | loop {
200 | info!("是否打开开机自启? (Y/N)");
201 | let mut input = String::new();
202 | io::stdin().read_line(&mut input).unwrap();
203 | input = input.trim().to_uppercase();
204 |
205 | if input == "Y" {
206 | match Command::new("systemctl")
207 | .arg("enable")
208 | .arg("cfst_slave.service")
209 | .output()
210 | {
211 | Ok(tmp) => {
212 | if tmp.status.success() {
213 | info!("成功打开开机自启");
214 | } else {
215 | error!("无法打开开机自启")
216 | }
217 | }
218 | Err(e) => {
219 | error!("无法打开开机自启: {}", e);
220 | exit(1);
221 | }
222 | }
223 | break;
224 | } else if input == "N" {
225 | info!("不打开, 退出程序");
226 | exit(1);
227 | } else {
228 | warn!("输入错误, 请重新输入 Y 或 N。");
229 | }
230 | }
231 | }
232 |
233 | // 异步函数, 负责检查并执行云flare速度测试客户端的更新。
234 | // 参数:
235 | // - client: 云flare速度测试客户端实例, 使用channel进行通信。
236 | // - args: 命令行参数, 包含是否禁用自动升级等信息。
237 | // - bootstrapres: 启动时从服务器获取的响应, 包含是否需要升级的信息。
238 | pub async fn upgrade_bin(
239 | mut client: CloudflareSpeedtestClient,
240 | args: Args,
241 | bootstrapres: BootstrapResponse,
242 | ) {
243 | // 检查是否需要升级, 如果不需升级则直接返回。
244 | if !bootstrapres.should_upgrade {
245 | info!("该后端为最新版本, 无需更新");
246 | return;
247 | } else {
248 | info!("准备开始更新后端");
249 | }
250 |
251 | // 如果配置了禁用自动升级, 则即使需要升级也不执行更新。
252 | if args.disable_auto_upgrade {
253 | warn!("该后端版本需更新, 但由于配置了 Disable Auto Upgrade, 不予更新");
254 | return;
255 | }
256 |
257 | info!("开始更新后端");
258 |
259 | // 尝试从客户端获取更新信息。
260 | let upgrade_message = match client.upgrade(UpgradeRequest {}).await {
261 | Ok(tmp) => {
262 | let result = tmp.into_inner();
263 | // 如果更新请求成功, 检查是否成功获取了更新链接。
264 | if result.success {
265 | info!("成功获取更新链接: {}", result.message);
266 | result
267 | } else {
268 | error!("无法获取更新链接, 终止更新继续运行: {}", result.message);
269 | return;
270 | }
271 | }
272 | Err(e) => {
273 | error!("无法获取更新链接, 终止更新继续运行: {}", e);
274 | return;
275 | }
276 | };
277 |
278 | // 根据更新信息下载对应的操作系统和架构的更新文件。
279 | let version_bin = match Client::new()
280 | .get(format!(
281 | "{}-{}-{}",
282 | upgrade_message.upgrade_url,
283 | env::consts::OS,
284 | env::consts::ARCH
285 | ))
286 | .send()
287 | .await
288 | {
289 | Ok(tmp) => {
290 | // 检查下载是否成功。
291 | if tmp.status().is_success() {
292 | tmp
293 | } else {
294 | error!(
295 | "无法下载文件 URL: {}, Code: {}, 终止更新继续运行",
296 | tmp.url().to_string(),
297 | tmp.status().to_string()
298 | );
299 | return;
300 | }
301 | }
302 | Err(e) => {
303 | error!(
304 | "无法下载文件 URL: {}, 终止更新并继续运行: {}",
305 | format!(
306 | "{}-{}-{}",
307 | upgrade_message.upgrade_url,
308 | env::consts::OS,
309 | env::consts::ARCH
310 | ),
311 | e
312 | );
313 | return;
314 | }
315 | };
316 |
317 | // 在临时目录创建一个文件用于存储下载的更新二进制文件。
318 | let tmp_dir = env::temp_dir();
319 | let file_path = tmp_dir.join("CloudflareSpeedtest-Slave");
320 |
321 | match File::create(&file_path) {
322 | Ok(mut tmp) => {
323 | // 下载二进制文件内容。
324 | let binary = match version_bin.bytes().await {
325 | Ok(tmp) => tmp,
326 | Err(e) => {
327 | error!("无法获取 Binary, 终止更新并继续运行: {}", e);
328 | return;
329 | }
330 | };
331 | // 将二进制文件内容写入到临时文件。
332 | match tmp.write_all(&binary) {
333 | Ok(_) => {
334 | info!("成功将 Binary 保存到 Temp Dir");
335 | }
336 | Err(e) => {
337 | error!("无法将 Binary 保存到 Temp Dir, 终止更新并继续运行: {}", e);
338 | return;
339 | }
340 | }
341 | }
342 | Err(e) => {
343 | error!("无法将 Binary 保存到 Temp Dir, 终止更新并继续运行: {}", e);
344 | return;
345 | }
346 | }
347 |
348 | // 为临时文件添加可执行权限。
349 | match Command::new("chmod")
350 | .arg("+x")
351 | .arg(file_path.clone())
352 | .output()
353 | {
354 | Ok(_) => {
355 | info!("成功添加可执行权限");
356 | }
357 | Err(e) => {
358 | error!("无法添加可执行权限, 终止更新并继续运行: {}", e);
359 | return;
360 | }
361 | }
362 |
363 | // 复制临时文件到当前执行程序的路径, 以替换旧版本。
364 | match env::current_exe() {
365 | Ok(path_to_bin) => match fs::copy(file_path, path_to_bin) {
366 | Ok(_) => {
367 | info!("成功将可执行文件替换");
368 | }
369 | Err(e) => {
370 | error!("无法将可执行文件替换, 终止更新并继续运行: {}", e);
371 | return;
372 | }
373 | },
374 | Err(e) => {
375 | error!("无法获取当前运行程序路径, 终止更新并继续运行: {}", e);
376 | return;
377 | }
378 | }
379 |
380 | // 启动新的可执行文件, 替换当前进程。
381 | let mut command = Command::new(env::current_exe().unwrap());
382 | command.args(env::args().skip(1));
383 |
384 | let _ = match command.spawn() {
385 | Ok(_) => {
386 | info!("成功启动新程序");
387 | exit(1);
388 | }
389 | Err(e) => {
390 | error!(
391 | "无法启动新程序, 主程序将退出, 请自行重新启动新版本程序: {}",
392 | e
393 | );
394 | exit(1);
395 | }
396 | };
397 | }
398 |
--------------------------------------------------------------------------------
/proto/cfst_rpc.rs:
--------------------------------------------------------------------------------
1 | // This file is @generated by prost-build.
2 | #[allow(clippy::derive_partial_eq_without_eq)]
3 | #[derive(Clone, PartialEq, ::prost::Message)]
4 | pub struct BootstrapRequest {
5 | #[prost(int32, tag = "1")]
6 | pub province_id: i32,
7 | #[prost(int32, tag = "2")]
8 | pub isp_type: i32,
9 | #[prost(int32, tag = "3")]
10 | pub maximum_mbps: i32,
11 | #[prost(string, tag = "4")]
12 | pub client_version: ::prost::alloc::string::String,
13 | #[prost(string, tag = "5")]
14 | pub bootstrap_token: ::prost::alloc::string::String,
15 | }
16 | #[allow(clippy::derive_partial_eq_without_eq)]
17 | #[derive(Clone, PartialEq, ::prost::Message)]
18 | pub struct BootstrapResponse {
19 | #[prost(bool, tag = "1")]
20 | pub success: bool,
21 | #[prost(bool, tag = "2")]
22 | pub should_upgrade: bool,
23 | #[prost(string, tag = "3")]
24 | pub message: ::prost::alloc::string::String,
25 | /// token to use for communicating with the control node thereafter until the exit of the process
26 | #[prost(string, tag = "4")]
27 | pub session_token: ::prost::alloc::string::String,
28 | }
29 | #[allow(clippy::derive_partial_eq_without_eq)]
30 | #[derive(Clone, PartialEq, ::prost::Message)]
31 | pub struct UpgradeRequest {
32 | #[prost(int32, tag = "1")]
33 | pub province_id: i32,
34 | #[prost(int32, tag = "2")]
35 | pub isp_type: i32,
36 | #[prost(string, tag = "3")]
37 | pub session_token: ::prost::alloc::string::String,
38 | }
39 | #[allow(clippy::derive_partial_eq_without_eq)]
40 | #[derive(Clone, PartialEq, ::prost::Message)]
41 | pub struct UpgradeResponse {
42 | #[prost(bool, tag = "1")]
43 | pub success: bool,
44 | #[prost(string, tag = "2")]
45 | pub message: ::prost::alloc::string::String,
46 | #[prost(string, tag = "3")]
47 | pub upgrade_url: ::prost::alloc::string::String,
48 | }
49 | #[allow(clippy::derive_partial_eq_without_eq)]
50 | #[derive(Clone, PartialEq, ::prost::Message)]
51 | pub struct IpResult {
52 | #[prost(string, tag = "1")]
53 | pub ip_address: ::prost::alloc::string::String,
54 | #[prost(int32, tag = "2")]
55 | pub latency: i32,
56 | #[prost(int32, tag = "3")]
57 | pub speed: i32,
58 | }
59 | #[allow(clippy::derive_partial_eq_without_eq)]
60 | #[derive(Clone, PartialEq, ::prost::Message)]
61 | pub struct SpeedtestRequest {
62 | #[prost(string, repeated, tag = "1")]
63 | pub ip_ranges: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
64 | }
65 | #[allow(clippy::derive_partial_eq_without_eq)]
66 | #[derive(Clone, PartialEq, ::prost::Message)]
67 | pub struct SpeedtestResponse {
68 | #[prost(bool, tag = "1")]
69 | pub success: bool,
70 | #[prost(string, tag = "2")]
71 | pub message: ::prost::alloc::string::String,
72 | #[prost(int32, tag = "3")]
73 | pub province_id: i32,
74 | #[prost(int32, tag = "4")]
75 | pub isp_type: i32,
76 | #[prost(message, repeated, tag = "5")]
77 | pub ip_results: ::prost::alloc::vec::Vec,
78 | #[prost(string, tag = "6")]
79 | pub session_token: ::prost::alloc::string::String,
80 | }
81 | /// Generated client implementations.
82 | pub mod cloudflare_speedtest_service_client {
83 | #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)]
84 | use tonic::codegen::*;
85 | use tonic::codegen::http::Uri;
86 | #[derive(Debug, Clone)]
87 | pub struct CloudflareSpeedtestServiceClient {
88 | inner: tonic::client::Grpc,
89 | }
90 | impl CloudflareSpeedtestServiceClient {
91 | /// Attempt to create a new client by connecting to a given endpoint.
92 | pub async fn connect(dst: D) -> Result
93 | where
94 | D: TryInto,
95 | D::Error: Into,
96 | {
97 | let conn = tonic::transport::Endpoint::new(dst)?.connect().await?;
98 | Ok(Self::new(conn))
99 | }
100 | }
101 | impl CloudflareSpeedtestServiceClient
102 | where
103 | T: tonic::client::GrpcService,
104 | T::Error: Into,
105 | T::ResponseBody: Body + Send + 'static,
106 | ::Error: Into + Send,
107 | {
108 | pub fn new(inner: T) -> Self {
109 | let inner = tonic::client::Grpc::new(inner);
110 | Self { inner }
111 | }
112 | pub fn with_origin(inner: T, origin: Uri) -> Self {
113 | let inner = tonic::client::Grpc::with_origin(inner, origin);
114 | Self { inner }
115 | }
116 | pub fn with_interceptor(
117 | inner: T,
118 | interceptor: F,
119 | ) -> CloudflareSpeedtestServiceClient>
120 | where
121 | F: tonic::service::Interceptor,
122 | T::ResponseBody: Default,
123 | T: tonic::codegen::Service<
124 | http::Request,
125 | Response = http::Response<
126 | >::ResponseBody,
127 | >,
128 | >,
129 | ,
131 | >>::Error: Into + Send + Sync,
132 | {
133 | CloudflareSpeedtestServiceClient::new(
134 | InterceptedService::new(inner, interceptor),
135 | )
136 | }
137 | /// Compress requests with the given encoding.
138 | ///
139 | /// This requires the server to support it otherwise it might respond with an
140 | /// error.
141 | #[must_use]
142 | pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {
143 | self.inner = self.inner.send_compressed(encoding);
144 | self
145 | }
146 | /// Enable decompressing responses.
147 | #[must_use]
148 | pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {
149 | self.inner = self.inner.accept_compressed(encoding);
150 | self
151 | }
152 | /// Limits the maximum size of a decoded message.
153 | ///
154 | /// Default: `4MB`
155 | #[must_use]
156 | pub fn max_decoding_message_size(mut self, limit: usize) -> Self {
157 | self.inner = self.inner.max_decoding_message_size(limit);
158 | self
159 | }
160 | /// Limits the maximum size of an encoded message.
161 | ///
162 | /// Default: `usize::MAX`
163 | #[must_use]
164 | pub fn max_encoding_message_size(mut self, limit: usize) -> Self {
165 | self.inner = self.inner.max_encoding_message_size(limit);
166 | self
167 | }
168 | pub async fn bootstrap(
169 | &mut self,
170 | request: impl tonic::IntoRequest,
171 | ) -> std::result::Result<
172 | tonic::Response,
173 | tonic::Status,
174 | > {
175 | self.inner
176 | .ready()
177 | .await
178 | .map_err(|e| {
179 | tonic::Status::new(
180 | tonic::Code::Unknown,
181 | format!("Service was not ready: {}", e.into()),
182 | )
183 | })?;
184 | let codec = tonic::codec::ProstCodec::default();
185 | let path = http::uri::PathAndQuery::from_static(
186 | "/cfst_rpc.CloudflareSpeedtestService/Bootstrap",
187 | );
188 | let mut req = request.into_request();
189 | req.extensions_mut()
190 | .insert(
191 | GrpcMethod::new("cfst_rpc.CloudflareSpeedtestService", "Bootstrap"),
192 | );
193 | self.inner.unary(req, path, codec).await
194 | }
195 | /// Deprecated
196 | /// rpc GetCandidateIPRanges(CandidateIPRangesRequest) returns (CandidateIPRangesResponse);
197 | /// rpc SpeedtestResultUpload(SpeedtestResultUploadRequest) returns (SpeedtestResultUploadResponse);
198 | pub async fn speedtest(
199 | &mut self,
200 | request: impl tonic::IntoRequest,
201 | ) -> std::result::Result<
202 | tonic::Response,
203 | tonic::Status,
204 | > {
205 | self.inner
206 | .ready()
207 | .await
208 | .map_err(|e| {
209 | tonic::Status::new(
210 | tonic::Code::Unknown,
211 | format!("Service was not ready: {}", e.into()),
212 | )
213 | })?;
214 | let codec = tonic::codec::ProstCodec::default();
215 | let path = http::uri::PathAndQuery::from_static(
216 | "/cfst_rpc.CloudflareSpeedtestService/Speedtest",
217 | );
218 | let mut req = request.into_request();
219 | req.extensions_mut()
220 | .insert(
221 | GrpcMethod::new("cfst_rpc.CloudflareSpeedtestService", "Speedtest"),
222 | );
223 | self.inner.unary(req, path, codec).await
224 | }
225 | pub async fn upgrade(
226 | &mut self,
227 | request: impl tonic::IntoRequest,
228 | ) -> std::result::Result<
229 | tonic::Response,
230 | tonic::Status,
231 | > {
232 | self.inner
233 | .ready()
234 | .await
235 | .map_err(|e| {
236 | tonic::Status::new(
237 | tonic::Code::Unknown,
238 | format!("Service was not ready: {}", e.into()),
239 | )
240 | })?;
241 | let codec = tonic::codec::ProstCodec::default();
242 | let path = http::uri::PathAndQuery::from_static(
243 | "/cfst_rpc.CloudflareSpeedtestService/Upgrade",
244 | );
245 | let mut req = request.into_request();
246 | req.extensions_mut()
247 | .insert(
248 | GrpcMethod::new("cfst_rpc.CloudflareSpeedtestService", "Upgrade"),
249 | );
250 | self.inner.unary(req, path, codec).await
251 | }
252 | }
253 | }
254 | /// Generated server implementations.
255 | pub mod cloudflare_speedtest_service_server {
256 | #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)]
257 | use tonic::codegen::*;
258 | /// Generated trait containing gRPC methods that should be implemented for use with CloudflareSpeedtestServiceServer.
259 | #[async_trait]
260 | pub trait CloudflareSpeedtestService: Send + Sync + 'static {
261 | async fn bootstrap(
262 | &self,
263 | request: tonic::Request,
264 | ) -> std::result::Result<
265 | tonic::Response,
266 | tonic::Status,
267 | >;
268 | /// Deprecated
269 | /// rpc GetCandidateIPRanges(CandidateIPRangesRequest) returns (CandidateIPRangesResponse);
270 | /// rpc SpeedtestResultUpload(SpeedtestResultUploadRequest) returns (SpeedtestResultUploadResponse);
271 | async fn speedtest(
272 | &self,
273 | request: tonic::Request,
274 | ) -> std::result::Result<
275 | tonic::Response,
276 | tonic::Status,
277 | >;
278 | async fn upgrade(
279 | &self,
280 | request: tonic::Request,
281 | ) -> std::result::Result, tonic::Status>;
282 | }
283 | #[derive(Debug)]
284 | pub struct CloudflareSpeedtestServiceServer {
285 | inner: _Inner,
286 | accept_compression_encodings: EnabledCompressionEncodings,
287 | send_compression_encodings: EnabledCompressionEncodings,
288 | max_decoding_message_size: Option,
289 | max_encoding_message_size: Option,
290 | }
291 | struct _Inner(Arc);
292 | impl CloudflareSpeedtestServiceServer {
293 | pub fn new(inner: T) -> Self {
294 | Self::from_arc(Arc::new(inner))
295 | }
296 | pub fn from_arc(inner: Arc) -> Self {
297 | let inner = _Inner(inner);
298 | Self {
299 | inner,
300 | accept_compression_encodings: Default::default(),
301 | send_compression_encodings: Default::default(),
302 | max_decoding_message_size: None,
303 | max_encoding_message_size: None,
304 | }
305 | }
306 | pub fn with_interceptor(
307 | inner: T,
308 | interceptor: F,
309 | ) -> InterceptedService
310 | where
311 | F: tonic::service::Interceptor,
312 | {
313 | InterceptedService::new(Self::new(inner), interceptor)
314 | }
315 | /// Enable decompressing requests with the given encoding.
316 | #[must_use]
317 | pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {
318 | self.accept_compression_encodings.enable(encoding);
319 | self
320 | }
321 | /// Compress responses with the given encoding, if the client supports it.
322 | #[must_use]
323 | pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {
324 | self.send_compression_encodings.enable(encoding);
325 | self
326 | }
327 | /// Limits the maximum size of a decoded message.
328 | ///
329 | /// Default: `4MB`
330 | #[must_use]
331 | pub fn max_decoding_message_size(mut self, limit: usize) -> Self {
332 | self.max_decoding_message_size = Some(limit);
333 | self
334 | }
335 | /// Limits the maximum size of an encoded message.
336 | ///
337 | /// Default: `usize::MAX`
338 | #[must_use]
339 | pub fn max_encoding_message_size(mut self, limit: usize) -> Self {
340 | self.max_encoding_message_size = Some(limit);
341 | self
342 | }
343 | }
344 | impl tonic::codegen::Service>
345 | for CloudflareSpeedtestServiceServer
346 | where
347 | T: CloudflareSpeedtestService,
348 | B: Body + Send + 'static,
349 | B::Error: Into + Send + 'static,
350 | {
351 | type Response = http::Response;
352 | type Error = std::convert::Infallible;
353 | type Future = BoxFuture;
354 | fn poll_ready(
355 | &mut self,
356 | _cx: &mut Context<'_>,
357 | ) -> Poll> {
358 | Poll::Ready(Ok(()))
359 | }
360 | fn call(&mut self, req: http::Request) -> Self::Future {
361 | let inner = self.inner.clone();
362 | match req.uri().path() {
363 | "/cfst_rpc.CloudflareSpeedtestService/Bootstrap" => {
364 | #[allow(non_camel_case_types)]
365 | struct BootstrapSvc(pub Arc);
366 | impl<
367 | T: CloudflareSpeedtestService,
368 | > tonic::server::UnaryService
369 | for BootstrapSvc {
370 | type Response = super::BootstrapResponse;
371 | type Future = BoxFuture<
372 | tonic::Response,
373 | tonic::Status,
374 | >;
375 | fn call(
376 | &mut self,
377 | request: tonic::Request,
378 | ) -> Self::Future {
379 | let inner = Arc::clone(&self.0);
380 | let fut = async move {
381 | ::bootstrap(
382 | &inner,
383 | request,
384 | )
385 | .await
386 | };
387 | Box::pin(fut)
388 | }
389 | }
390 | let accept_compression_encodings = self.accept_compression_encodings;
391 | let send_compression_encodings = self.send_compression_encodings;
392 | let max_decoding_message_size = self.max_decoding_message_size;
393 | let max_encoding_message_size = self.max_encoding_message_size;
394 | let inner = self.inner.clone();
395 | let fut = async move {
396 | let inner = inner.0;
397 | let method = BootstrapSvc(inner);
398 | let codec = tonic::codec::ProstCodec::default();
399 | let mut grpc = tonic::server::Grpc::new(codec)
400 | .apply_compression_config(
401 | accept_compression_encodings,
402 | send_compression_encodings,
403 | )
404 | .apply_max_message_size_config(
405 | max_decoding_message_size,
406 | max_encoding_message_size,
407 | );
408 | let res = grpc.unary(method, req).await;
409 | Ok(res)
410 | };
411 | Box::pin(fut)
412 | }
413 | "/cfst_rpc.CloudflareSpeedtestService/Speedtest" => {
414 | #[allow(non_camel_case_types)]
415 | struct SpeedtestSvc(pub Arc);
416 | impl<
417 | T: CloudflareSpeedtestService,
418 | > tonic::server::UnaryService
419 | for SpeedtestSvc {
420 | type Response = super::SpeedtestResponse;
421 | type Future = BoxFuture<
422 | tonic::Response,
423 | tonic::Status,
424 | >;
425 | fn call(
426 | &mut self,
427 | request: tonic::Request,
428 | ) -> Self::Future {
429 | let inner = Arc::clone(&self.0);
430 | let fut = async move {
431 | ::speedtest(
432 | &inner,
433 | request,
434 | )
435 | .await
436 | };
437 | Box::pin(fut)
438 | }
439 | }
440 | let accept_compression_encodings = self.accept_compression_encodings;
441 | let send_compression_encodings = self.send_compression_encodings;
442 | let max_decoding_message_size = self.max_decoding_message_size;
443 | let max_encoding_message_size = self.max_encoding_message_size;
444 | let inner = self.inner.clone();
445 | let fut = async move {
446 | let inner = inner.0;
447 | let method = SpeedtestSvc(inner);
448 | let codec = tonic::codec::ProstCodec::default();
449 | let mut grpc = tonic::server::Grpc::new(codec)
450 | .apply_compression_config(
451 | accept_compression_encodings,
452 | send_compression_encodings,
453 | )
454 | .apply_max_message_size_config(
455 | max_decoding_message_size,
456 | max_encoding_message_size,
457 | );
458 | let res = grpc.unary(method, req).await;
459 | Ok(res)
460 | };
461 | Box::pin(fut)
462 | }
463 | "/cfst_rpc.CloudflareSpeedtestService/Upgrade" => {
464 | #[allow(non_camel_case_types)]
465 | struct UpgradeSvc(pub Arc);
466 | impl<
467 | T: CloudflareSpeedtestService,
468 | > tonic::server::UnaryService
469 | for UpgradeSvc {
470 | type Response = super::UpgradeResponse;
471 | type Future = BoxFuture<
472 | tonic::Response,
473 | tonic::Status,
474 | >;
475 | fn call(
476 | &mut self,
477 | request: tonic::Request,
478 | ) -> Self::Future {
479 | let inner = Arc::clone(&self.0);
480 | let fut = async move {
481 | ::upgrade(&inner, request)
482 | .await
483 | };
484 | Box::pin(fut)
485 | }
486 | }
487 | let accept_compression_encodings = self.accept_compression_encodings;
488 | let send_compression_encodings = self.send_compression_encodings;
489 | let max_decoding_message_size = self.max_decoding_message_size;
490 | let max_encoding_message_size = self.max_encoding_message_size;
491 | let inner = self.inner.clone();
492 | let fut = async move {
493 | let inner = inner.0;
494 | let method = UpgradeSvc(inner);
495 | let codec = tonic::codec::ProstCodec::default();
496 | let mut grpc = tonic::server::Grpc::new(codec)
497 | .apply_compression_config(
498 | accept_compression_encodings,
499 | send_compression_encodings,
500 | )
501 | .apply_max_message_size_config(
502 | max_decoding_message_size,
503 | max_encoding_message_size,
504 | );
505 | let res = grpc.unary(method, req).await;
506 | Ok(res)
507 | };
508 | Box::pin(fut)
509 | }
510 | _ => {
511 | Box::pin(async move {
512 | Ok(
513 | http::Response::builder()
514 | .status(200)
515 | .header("grpc-status", "12")
516 | .header("content-type", "application/grpc")
517 | .body(empty_body())
518 | .unwrap(),
519 | )
520 | })
521 | }
522 | }
523 | }
524 | }
525 | impl Clone for CloudflareSpeedtestServiceServer {
526 | fn clone(&self) -> Self {
527 | let inner = self.inner.clone();
528 | Self {
529 | inner,
530 | accept_compression_encodings: self.accept_compression_encodings,
531 | send_compression_encodings: self.send_compression_encodings,
532 | max_decoding_message_size: self.max_decoding_message_size,
533 | max_encoding_message_size: self.max_encoding_message_size,
534 | }
535 | }
536 | }
537 | impl Clone for _Inner {
538 | fn clone(&self) -> Self {
539 | Self(Arc::clone(&self.0))
540 | }
541 | }
542 | impl std::fmt::Debug for _Inner {
543 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
544 | write!(f, "{:?}", self.0)
545 | }
546 | }
547 | impl tonic::server::NamedService
548 | for CloudflareSpeedtestServiceServer {
549 | const NAME: &'static str = "cfst_rpc.CloudflareSpeedtestService";
550 | }
551 | }
552 |
--------------------------------------------------------------------------------
/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | version = 3
4 |
5 | [[package]]
6 | name = "CloudflareSpeedtest-Slave"
7 | version = "0.0.6"
8 | dependencies = [
9 | "clap",
10 | "futures",
11 | "ipnetwork",
12 | "log",
13 | "prost",
14 | "rand 0.9.0-alpha.1",
15 | "reqwest",
16 | "rustls",
17 | "simple_logger",
18 | "tokio",
19 | "tokio-rustls",
20 | "tokio-stream",
21 | "tonic",
22 | "tonic-build",
23 | "url",
24 | "uuid",
25 | "webpki-roots",
26 | ]
27 |
28 | [[package]]
29 | name = "addr2line"
30 | version = "0.22.0"
31 | source = "registry+https://github.com/rust-lang/crates.io-index"
32 | checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
33 | dependencies = [
34 | "gimli",
35 | ]
36 |
37 | [[package]]
38 | name = "adler"
39 | version = "1.0.2"
40 | source = "registry+https://github.com/rust-lang/crates.io-index"
41 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
42 |
43 | [[package]]
44 | name = "aho-corasick"
45 | version = "1.1.3"
46 | source = "registry+https://github.com/rust-lang/crates.io-index"
47 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
48 | dependencies = [
49 | "memchr",
50 | ]
51 |
52 | [[package]]
53 | name = "anstream"
54 | version = "0.6.14"
55 | source = "registry+https://github.com/rust-lang/crates.io-index"
56 | checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b"
57 | dependencies = [
58 | "anstyle",
59 | "anstyle-parse",
60 | "anstyle-query",
61 | "anstyle-wincon",
62 | "colorchoice",
63 | "is_terminal_polyfill",
64 | "utf8parse",
65 | ]
66 |
67 | [[package]]
68 | name = "anstyle"
69 | version = "1.0.7"
70 | source = "registry+https://github.com/rust-lang/crates.io-index"
71 | checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
72 |
73 | [[package]]
74 | name = "anstyle-parse"
75 | version = "0.2.4"
76 | source = "registry+https://github.com/rust-lang/crates.io-index"
77 | checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
78 | dependencies = [
79 | "utf8parse",
80 | ]
81 |
82 | [[package]]
83 | name = "anstyle-query"
84 | version = "1.1.0"
85 | source = "registry+https://github.com/rust-lang/crates.io-index"
86 | checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391"
87 | dependencies = [
88 | "windows-sys 0.52.0",
89 | ]
90 |
91 | [[package]]
92 | name = "anstyle-wincon"
93 | version = "3.0.3"
94 | source = "registry+https://github.com/rust-lang/crates.io-index"
95 | checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
96 | dependencies = [
97 | "anstyle",
98 | "windows-sys 0.52.0",
99 | ]
100 |
101 | [[package]]
102 | name = "anyhow"
103 | version = "1.0.86"
104 | source = "registry+https://github.com/rust-lang/crates.io-index"
105 | checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
106 |
107 | [[package]]
108 | name = "async-stream"
109 | version = "0.3.5"
110 | source = "registry+https://github.com/rust-lang/crates.io-index"
111 | checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51"
112 | dependencies = [
113 | "async-stream-impl",
114 | "futures-core",
115 | "pin-project-lite",
116 | ]
117 |
118 | [[package]]
119 | name = "async-stream-impl"
120 | version = "0.3.5"
121 | source = "registry+https://github.com/rust-lang/crates.io-index"
122 | checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
123 | dependencies = [
124 | "proc-macro2",
125 | "quote",
126 | "syn",
127 | ]
128 |
129 | [[package]]
130 | name = "async-trait"
131 | version = "0.1.80"
132 | source = "registry+https://github.com/rust-lang/crates.io-index"
133 | checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
134 | dependencies = [
135 | "proc-macro2",
136 | "quote",
137 | "syn",
138 | ]
139 |
140 | [[package]]
141 | name = "atomic-waker"
142 | version = "1.1.2"
143 | source = "registry+https://github.com/rust-lang/crates.io-index"
144 | checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
145 |
146 | [[package]]
147 | name = "autocfg"
148 | version = "1.3.0"
149 | source = "registry+https://github.com/rust-lang/crates.io-index"
150 | checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
151 |
152 | [[package]]
153 | name = "aws-lc-rs"
154 | version = "1.8.0"
155 | source = "registry+https://github.com/rust-lang/crates.io-index"
156 | checksum = "a8a47f2fb521b70c11ce7369a6c5fa4bd6af7e5d62ec06303875bafe7c6ba245"
157 | dependencies = [
158 | "aws-lc-sys",
159 | "mirai-annotations",
160 | "paste",
161 | "zeroize",
162 | ]
163 |
164 | [[package]]
165 | name = "aws-lc-sys"
166 | version = "0.19.0"
167 | source = "registry+https://github.com/rust-lang/crates.io-index"
168 | checksum = "2927c7af777b460b7ccd95f8b67acd7b4c04ec8896bf0c8e80ba30523cffc057"
169 | dependencies = [
170 | "bindgen",
171 | "cc",
172 | "cmake",
173 | "dunce",
174 | "fs_extra",
175 | "libc",
176 | "paste",
177 | ]
178 |
179 | [[package]]
180 | name = "axum"
181 | version = "0.7.5"
182 | source = "registry+https://github.com/rust-lang/crates.io-index"
183 | checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf"
184 | dependencies = [
185 | "async-trait",
186 | "axum-core",
187 | "bytes",
188 | "futures-util",
189 | "http",
190 | "http-body",
191 | "http-body-util",
192 | "itoa",
193 | "matchit",
194 | "memchr",
195 | "mime",
196 | "percent-encoding",
197 | "pin-project-lite",
198 | "rustversion",
199 | "serde",
200 | "sync_wrapper 1.0.1",
201 | "tower",
202 | "tower-layer",
203 | "tower-service",
204 | ]
205 |
206 | [[package]]
207 | name = "axum-core"
208 | version = "0.4.3"
209 | source = "registry+https://github.com/rust-lang/crates.io-index"
210 | checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3"
211 | dependencies = [
212 | "async-trait",
213 | "bytes",
214 | "futures-util",
215 | "http",
216 | "http-body",
217 | "http-body-util",
218 | "mime",
219 | "pin-project-lite",
220 | "rustversion",
221 | "sync_wrapper 0.1.2",
222 | "tower-layer",
223 | "tower-service",
224 | ]
225 |
226 | [[package]]
227 | name = "backtrace"
228 | version = "0.3.73"
229 | source = "registry+https://github.com/rust-lang/crates.io-index"
230 | checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a"
231 | dependencies = [
232 | "addr2line",
233 | "cc",
234 | "cfg-if",
235 | "libc",
236 | "miniz_oxide",
237 | "object",
238 | "rustc-demangle",
239 | ]
240 |
241 | [[package]]
242 | name = "base64"
243 | version = "0.22.1"
244 | source = "registry+https://github.com/rust-lang/crates.io-index"
245 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
246 |
247 | [[package]]
248 | name = "bindgen"
249 | version = "0.69.4"
250 | source = "registry+https://github.com/rust-lang/crates.io-index"
251 | checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0"
252 | dependencies = [
253 | "bitflags",
254 | "cexpr",
255 | "clang-sys",
256 | "itertools",
257 | "lazy_static",
258 | "lazycell",
259 | "log",
260 | "prettyplease",
261 | "proc-macro2",
262 | "quote",
263 | "regex",
264 | "rustc-hash",
265 | "shlex",
266 | "syn",
267 | "which",
268 | ]
269 |
270 | [[package]]
271 | name = "bitflags"
272 | version = "2.6.0"
273 | source = "registry+https://github.com/rust-lang/crates.io-index"
274 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
275 |
276 | [[package]]
277 | name = "bumpalo"
278 | version = "3.16.0"
279 | source = "registry+https://github.com/rust-lang/crates.io-index"
280 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
281 |
282 | [[package]]
283 | name = "bytes"
284 | version = "1.6.0"
285 | source = "registry+https://github.com/rust-lang/crates.io-index"
286 | checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
287 |
288 | [[package]]
289 | name = "cc"
290 | version = "1.0.104"
291 | source = "registry+https://github.com/rust-lang/crates.io-index"
292 | checksum = "74b6a57f98764a267ff415d50a25e6e166f3831a5071af4995296ea97d210490"
293 | dependencies = [
294 | "jobserver",
295 | "libc",
296 | "once_cell",
297 | ]
298 |
299 | [[package]]
300 | name = "cexpr"
301 | version = "0.6.0"
302 | source = "registry+https://github.com/rust-lang/crates.io-index"
303 | checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
304 | dependencies = [
305 | "nom",
306 | ]
307 |
308 | [[package]]
309 | name = "cfg-if"
310 | version = "1.0.0"
311 | source = "registry+https://github.com/rust-lang/crates.io-index"
312 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
313 |
314 | [[package]]
315 | name = "clang-sys"
316 | version = "1.8.1"
317 | source = "registry+https://github.com/rust-lang/crates.io-index"
318 | checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
319 | dependencies = [
320 | "glob",
321 | "libc",
322 | "libloading",
323 | ]
324 |
325 | [[package]]
326 | name = "clap"
327 | version = "4.5.9"
328 | source = "registry+https://github.com/rust-lang/crates.io-index"
329 | checksum = "64acc1846d54c1fe936a78dc189c34e28d3f5afc348403f28ecf53660b9b8462"
330 | dependencies = [
331 | "clap_builder",
332 | "clap_derive",
333 | ]
334 |
335 | [[package]]
336 | name = "clap_builder"
337 | version = "4.5.9"
338 | source = "registry+https://github.com/rust-lang/crates.io-index"
339 | checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942"
340 | dependencies = [
341 | "anstream",
342 | "anstyle",
343 | "clap_lex",
344 | "strsim",
345 | ]
346 |
347 | [[package]]
348 | name = "clap_derive"
349 | version = "4.5.8"
350 | source = "registry+https://github.com/rust-lang/crates.io-index"
351 | checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085"
352 | dependencies = [
353 | "heck",
354 | "proc-macro2",
355 | "quote",
356 | "syn",
357 | ]
358 |
359 | [[package]]
360 | name = "clap_lex"
361 | version = "0.7.1"
362 | source = "registry+https://github.com/rust-lang/crates.io-index"
363 | checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70"
364 |
365 | [[package]]
366 | name = "cmake"
367 | version = "0.1.50"
368 | source = "registry+https://github.com/rust-lang/crates.io-index"
369 | checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130"
370 | dependencies = [
371 | "cc",
372 | ]
373 |
374 | [[package]]
375 | name = "colorchoice"
376 | version = "1.0.1"
377 | source = "registry+https://github.com/rust-lang/crates.io-index"
378 | checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
379 |
380 | [[package]]
381 | name = "colored"
382 | version = "2.1.0"
383 | source = "registry+https://github.com/rust-lang/crates.io-index"
384 | checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8"
385 | dependencies = [
386 | "lazy_static",
387 | "windows-sys 0.48.0",
388 | ]
389 |
390 | [[package]]
391 | name = "deranged"
392 | version = "0.3.11"
393 | source = "registry+https://github.com/rust-lang/crates.io-index"
394 | checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
395 | dependencies = [
396 | "powerfmt",
397 | ]
398 |
399 | [[package]]
400 | name = "dunce"
401 | version = "1.0.4"
402 | source = "registry+https://github.com/rust-lang/crates.io-index"
403 | checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b"
404 |
405 | [[package]]
406 | name = "either"
407 | version = "1.13.0"
408 | source = "registry+https://github.com/rust-lang/crates.io-index"
409 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
410 |
411 | [[package]]
412 | name = "equivalent"
413 | version = "1.0.1"
414 | source = "registry+https://github.com/rust-lang/crates.io-index"
415 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
416 |
417 | [[package]]
418 | name = "errno"
419 | version = "0.3.9"
420 | source = "registry+https://github.com/rust-lang/crates.io-index"
421 | checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
422 | dependencies = [
423 | "libc",
424 | "windows-sys 0.52.0",
425 | ]
426 |
427 | [[package]]
428 | name = "fastrand"
429 | version = "2.1.0"
430 | source = "registry+https://github.com/rust-lang/crates.io-index"
431 | checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
432 |
433 | [[package]]
434 | name = "fixedbitset"
435 | version = "0.4.2"
436 | source = "registry+https://github.com/rust-lang/crates.io-index"
437 | checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
438 |
439 | [[package]]
440 | name = "fnv"
441 | version = "1.0.7"
442 | source = "registry+https://github.com/rust-lang/crates.io-index"
443 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
444 |
445 | [[package]]
446 | name = "form_urlencoded"
447 | version = "1.2.1"
448 | source = "registry+https://github.com/rust-lang/crates.io-index"
449 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
450 | dependencies = [
451 | "percent-encoding",
452 | ]
453 |
454 | [[package]]
455 | name = "fs_extra"
456 | version = "1.3.0"
457 | source = "registry+https://github.com/rust-lang/crates.io-index"
458 | checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
459 |
460 | [[package]]
461 | name = "futures"
462 | version = "0.3.30"
463 | source = "registry+https://github.com/rust-lang/crates.io-index"
464 | checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
465 | dependencies = [
466 | "futures-channel",
467 | "futures-core",
468 | "futures-executor",
469 | "futures-io",
470 | "futures-sink",
471 | "futures-task",
472 | "futures-util",
473 | ]
474 |
475 | [[package]]
476 | name = "futures-channel"
477 | version = "0.3.30"
478 | source = "registry+https://github.com/rust-lang/crates.io-index"
479 | checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
480 | dependencies = [
481 | "futures-core",
482 | "futures-sink",
483 | ]
484 |
485 | [[package]]
486 | name = "futures-core"
487 | version = "0.3.30"
488 | source = "registry+https://github.com/rust-lang/crates.io-index"
489 | checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
490 |
491 | [[package]]
492 | name = "futures-executor"
493 | version = "0.3.30"
494 | source = "registry+https://github.com/rust-lang/crates.io-index"
495 | checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
496 | dependencies = [
497 | "futures-core",
498 | "futures-task",
499 | "futures-util",
500 | ]
501 |
502 | [[package]]
503 | name = "futures-io"
504 | version = "0.3.30"
505 | source = "registry+https://github.com/rust-lang/crates.io-index"
506 | checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
507 |
508 | [[package]]
509 | name = "futures-macro"
510 | version = "0.3.30"
511 | source = "registry+https://github.com/rust-lang/crates.io-index"
512 | checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
513 | dependencies = [
514 | "proc-macro2",
515 | "quote",
516 | "syn",
517 | ]
518 |
519 | [[package]]
520 | name = "futures-sink"
521 | version = "0.3.30"
522 | source = "registry+https://github.com/rust-lang/crates.io-index"
523 | checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
524 |
525 | [[package]]
526 | name = "futures-task"
527 | version = "0.3.30"
528 | source = "registry+https://github.com/rust-lang/crates.io-index"
529 | checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
530 |
531 | [[package]]
532 | name = "futures-util"
533 | version = "0.3.30"
534 | source = "registry+https://github.com/rust-lang/crates.io-index"
535 | checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
536 | dependencies = [
537 | "futures-channel",
538 | "futures-core",
539 | "futures-io",
540 | "futures-macro",
541 | "futures-sink",
542 | "futures-task",
543 | "memchr",
544 | "pin-project-lite",
545 | "pin-utils",
546 | "slab",
547 | ]
548 |
549 | [[package]]
550 | name = "getrandom"
551 | version = "0.2.15"
552 | source = "registry+https://github.com/rust-lang/crates.io-index"
553 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
554 | dependencies = [
555 | "cfg-if",
556 | "libc",
557 | "wasi",
558 | ]
559 |
560 | [[package]]
561 | name = "gimli"
562 | version = "0.29.0"
563 | source = "registry+https://github.com/rust-lang/crates.io-index"
564 | checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
565 |
566 | [[package]]
567 | name = "glob"
568 | version = "0.3.1"
569 | source = "registry+https://github.com/rust-lang/crates.io-index"
570 | checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
571 |
572 | [[package]]
573 | name = "h2"
574 | version = "0.4.5"
575 | source = "registry+https://github.com/rust-lang/crates.io-index"
576 | checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab"
577 | dependencies = [
578 | "atomic-waker",
579 | "bytes",
580 | "fnv",
581 | "futures-core",
582 | "futures-sink",
583 | "http",
584 | "indexmap 2.2.6",
585 | "slab",
586 | "tokio",
587 | "tokio-util",
588 | "tracing",
589 | ]
590 |
591 | [[package]]
592 | name = "hashbrown"
593 | version = "0.12.3"
594 | source = "registry+https://github.com/rust-lang/crates.io-index"
595 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
596 |
597 | [[package]]
598 | name = "hashbrown"
599 | version = "0.14.5"
600 | source = "registry+https://github.com/rust-lang/crates.io-index"
601 | checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
602 |
603 | [[package]]
604 | name = "heck"
605 | version = "0.5.0"
606 | source = "registry+https://github.com/rust-lang/crates.io-index"
607 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
608 |
609 | [[package]]
610 | name = "hermit-abi"
611 | version = "0.3.9"
612 | source = "registry+https://github.com/rust-lang/crates.io-index"
613 | checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
614 |
615 | [[package]]
616 | name = "home"
617 | version = "0.5.9"
618 | source = "registry+https://github.com/rust-lang/crates.io-index"
619 | checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
620 | dependencies = [
621 | "windows-sys 0.52.0",
622 | ]
623 |
624 | [[package]]
625 | name = "http"
626 | version = "1.1.0"
627 | source = "registry+https://github.com/rust-lang/crates.io-index"
628 | checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
629 | dependencies = [
630 | "bytes",
631 | "fnv",
632 | "itoa",
633 | ]
634 |
635 | [[package]]
636 | name = "http-body"
637 | version = "1.0.0"
638 | source = "registry+https://github.com/rust-lang/crates.io-index"
639 | checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643"
640 | dependencies = [
641 | "bytes",
642 | "http",
643 | ]
644 |
645 | [[package]]
646 | name = "http-body-util"
647 | version = "0.1.2"
648 | source = "registry+https://github.com/rust-lang/crates.io-index"
649 | checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
650 | dependencies = [
651 | "bytes",
652 | "futures-util",
653 | "http",
654 | "http-body",
655 | "pin-project-lite",
656 | ]
657 |
658 | [[package]]
659 | name = "httparse"
660 | version = "1.9.4"
661 | source = "registry+https://github.com/rust-lang/crates.io-index"
662 | checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9"
663 |
664 | [[package]]
665 | name = "httpdate"
666 | version = "1.0.3"
667 | source = "registry+https://github.com/rust-lang/crates.io-index"
668 | checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
669 |
670 | [[package]]
671 | name = "hyper"
672 | version = "1.4.0"
673 | source = "registry+https://github.com/rust-lang/crates.io-index"
674 | checksum = "c4fe55fb7a772d59a5ff1dfbff4fe0258d19b89fec4b233e75d35d5d2316badc"
675 | dependencies = [
676 | "bytes",
677 | "futures-channel",
678 | "futures-util",
679 | "h2",
680 | "http",
681 | "http-body",
682 | "httparse",
683 | "httpdate",
684 | "itoa",
685 | "pin-project-lite",
686 | "smallvec",
687 | "tokio",
688 | "want",
689 | ]
690 |
691 | [[package]]
692 | name = "hyper-rustls"
693 | version = "0.27.2"
694 | source = "registry+https://github.com/rust-lang/crates.io-index"
695 | checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155"
696 | dependencies = [
697 | "futures-util",
698 | "http",
699 | "hyper",
700 | "hyper-util",
701 | "rustls",
702 | "rustls-pki-types",
703 | "tokio",
704 | "tokio-rustls",
705 | "tower-service",
706 | "webpki-roots",
707 | ]
708 |
709 | [[package]]
710 | name = "hyper-timeout"
711 | version = "0.5.1"
712 | source = "registry+https://github.com/rust-lang/crates.io-index"
713 | checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793"
714 | dependencies = [
715 | "hyper",
716 | "hyper-util",
717 | "pin-project-lite",
718 | "tokio",
719 | "tower-service",
720 | ]
721 |
722 | [[package]]
723 | name = "hyper-util"
724 | version = "0.1.6"
725 | source = "registry+https://github.com/rust-lang/crates.io-index"
726 | checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956"
727 | dependencies = [
728 | "bytes",
729 | "futures-channel",
730 | "futures-util",
731 | "http",
732 | "http-body",
733 | "hyper",
734 | "pin-project-lite",
735 | "socket2",
736 | "tokio",
737 | "tower",
738 | "tower-service",
739 | "tracing",
740 | ]
741 |
742 | [[package]]
743 | name = "idna"
744 | version = "0.5.0"
745 | source = "registry+https://github.com/rust-lang/crates.io-index"
746 | checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
747 | dependencies = [
748 | "unicode-bidi",
749 | "unicode-normalization",
750 | ]
751 |
752 | [[package]]
753 | name = "indexmap"
754 | version = "1.9.3"
755 | source = "registry+https://github.com/rust-lang/crates.io-index"
756 | checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
757 | dependencies = [
758 | "autocfg",
759 | "hashbrown 0.12.3",
760 | ]
761 |
762 | [[package]]
763 | name = "indexmap"
764 | version = "2.2.6"
765 | source = "registry+https://github.com/rust-lang/crates.io-index"
766 | checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
767 | dependencies = [
768 | "equivalent",
769 | "hashbrown 0.14.5",
770 | ]
771 |
772 | [[package]]
773 | name = "ipnet"
774 | version = "2.9.0"
775 | source = "registry+https://github.com/rust-lang/crates.io-index"
776 | checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
777 |
778 | [[package]]
779 | name = "ipnetwork"
780 | version = "0.20.0"
781 | source = "registry+https://github.com/rust-lang/crates.io-index"
782 | checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e"
783 | dependencies = [
784 | "serde",
785 | ]
786 |
787 | [[package]]
788 | name = "is_terminal_polyfill"
789 | version = "1.70.0"
790 | source = "registry+https://github.com/rust-lang/crates.io-index"
791 | checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
792 |
793 | [[package]]
794 | name = "itertools"
795 | version = "0.12.1"
796 | source = "registry+https://github.com/rust-lang/crates.io-index"
797 | checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
798 | dependencies = [
799 | "either",
800 | ]
801 |
802 | [[package]]
803 | name = "itoa"
804 | version = "1.0.11"
805 | source = "registry+https://github.com/rust-lang/crates.io-index"
806 | checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
807 |
808 | [[package]]
809 | name = "jobserver"
810 | version = "0.1.31"
811 | source = "registry+https://github.com/rust-lang/crates.io-index"
812 | checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e"
813 | dependencies = [
814 | "libc",
815 | ]
816 |
817 | [[package]]
818 | name = "js-sys"
819 | version = "0.3.69"
820 | source = "registry+https://github.com/rust-lang/crates.io-index"
821 | checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
822 | dependencies = [
823 | "wasm-bindgen",
824 | ]
825 |
826 | [[package]]
827 | name = "lazy_static"
828 | version = "1.5.0"
829 | source = "registry+https://github.com/rust-lang/crates.io-index"
830 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
831 |
832 | [[package]]
833 | name = "lazycell"
834 | version = "1.3.0"
835 | source = "registry+https://github.com/rust-lang/crates.io-index"
836 | checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
837 |
838 | [[package]]
839 | name = "libc"
840 | version = "0.2.155"
841 | source = "registry+https://github.com/rust-lang/crates.io-index"
842 | checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
843 |
844 | [[package]]
845 | name = "libloading"
846 | version = "0.8.4"
847 | source = "registry+https://github.com/rust-lang/crates.io-index"
848 | checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d"
849 | dependencies = [
850 | "cfg-if",
851 | "windows-targets 0.52.6",
852 | ]
853 |
854 | [[package]]
855 | name = "linux-raw-sys"
856 | version = "0.4.14"
857 | source = "registry+https://github.com/rust-lang/crates.io-index"
858 | checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
859 |
860 | [[package]]
861 | name = "lock_api"
862 | version = "0.4.12"
863 | source = "registry+https://github.com/rust-lang/crates.io-index"
864 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
865 | dependencies = [
866 | "autocfg",
867 | "scopeguard",
868 | ]
869 |
870 | [[package]]
871 | name = "log"
872 | version = "0.4.22"
873 | source = "registry+https://github.com/rust-lang/crates.io-index"
874 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
875 |
876 | [[package]]
877 | name = "matchit"
878 | version = "0.7.3"
879 | source = "registry+https://github.com/rust-lang/crates.io-index"
880 | checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
881 |
882 | [[package]]
883 | name = "memchr"
884 | version = "2.7.4"
885 | source = "registry+https://github.com/rust-lang/crates.io-index"
886 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
887 |
888 | [[package]]
889 | name = "mime"
890 | version = "0.3.17"
891 | source = "registry+https://github.com/rust-lang/crates.io-index"
892 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
893 |
894 | [[package]]
895 | name = "minimal-lexical"
896 | version = "0.2.1"
897 | source = "registry+https://github.com/rust-lang/crates.io-index"
898 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
899 |
900 | [[package]]
901 | name = "miniz_oxide"
902 | version = "0.7.4"
903 | source = "registry+https://github.com/rust-lang/crates.io-index"
904 | checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
905 | dependencies = [
906 | "adler",
907 | ]
908 |
909 | [[package]]
910 | name = "mio"
911 | version = "0.8.11"
912 | source = "registry+https://github.com/rust-lang/crates.io-index"
913 | checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
914 | dependencies = [
915 | "libc",
916 | "wasi",
917 | "windows-sys 0.48.0",
918 | ]
919 |
920 | [[package]]
921 | name = "mirai-annotations"
922 | version = "1.12.0"
923 | source = "registry+https://github.com/rust-lang/crates.io-index"
924 | checksum = "c9be0862c1b3f26a88803c4a49de6889c10e608b3ee9344e6ef5b45fb37ad3d1"
925 |
926 | [[package]]
927 | name = "multimap"
928 | version = "0.10.0"
929 | source = "registry+https://github.com/rust-lang/crates.io-index"
930 | checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03"
931 |
932 | [[package]]
933 | name = "nom"
934 | version = "7.1.3"
935 | source = "registry+https://github.com/rust-lang/crates.io-index"
936 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
937 | dependencies = [
938 | "memchr",
939 | "minimal-lexical",
940 | ]
941 |
942 | [[package]]
943 | name = "num-conv"
944 | version = "0.1.0"
945 | source = "registry+https://github.com/rust-lang/crates.io-index"
946 | checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
947 |
948 | [[package]]
949 | name = "num_cpus"
950 | version = "1.16.0"
951 | source = "registry+https://github.com/rust-lang/crates.io-index"
952 | checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
953 | dependencies = [
954 | "hermit-abi",
955 | "libc",
956 | ]
957 |
958 | [[package]]
959 | name = "num_threads"
960 | version = "0.1.7"
961 | source = "registry+https://github.com/rust-lang/crates.io-index"
962 | checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
963 | dependencies = [
964 | "libc",
965 | ]
966 |
967 | [[package]]
968 | name = "object"
969 | version = "0.36.1"
970 | source = "registry+https://github.com/rust-lang/crates.io-index"
971 | checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce"
972 | dependencies = [
973 | "memchr",
974 | ]
975 |
976 | [[package]]
977 | name = "once_cell"
978 | version = "1.19.0"
979 | source = "registry+https://github.com/rust-lang/crates.io-index"
980 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
981 |
982 | [[package]]
983 | name = "parking_lot"
984 | version = "0.12.3"
985 | source = "registry+https://github.com/rust-lang/crates.io-index"
986 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
987 | dependencies = [
988 | "lock_api",
989 | "parking_lot_core",
990 | ]
991 |
992 | [[package]]
993 | name = "parking_lot_core"
994 | version = "0.9.10"
995 | source = "registry+https://github.com/rust-lang/crates.io-index"
996 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
997 | dependencies = [
998 | "cfg-if",
999 | "libc",
1000 | "redox_syscall",
1001 | "smallvec",
1002 | "windows-targets 0.52.6",
1003 | ]
1004 |
1005 | [[package]]
1006 | name = "paste"
1007 | version = "1.0.15"
1008 | source = "registry+https://github.com/rust-lang/crates.io-index"
1009 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
1010 |
1011 | [[package]]
1012 | name = "percent-encoding"
1013 | version = "2.3.1"
1014 | source = "registry+https://github.com/rust-lang/crates.io-index"
1015 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
1016 |
1017 | [[package]]
1018 | name = "petgraph"
1019 | version = "0.6.5"
1020 | source = "registry+https://github.com/rust-lang/crates.io-index"
1021 | checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
1022 | dependencies = [
1023 | "fixedbitset",
1024 | "indexmap 2.2.6",
1025 | ]
1026 |
1027 | [[package]]
1028 | name = "pin-project"
1029 | version = "1.1.5"
1030 | source = "registry+https://github.com/rust-lang/crates.io-index"
1031 | checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3"
1032 | dependencies = [
1033 | "pin-project-internal",
1034 | ]
1035 |
1036 | [[package]]
1037 | name = "pin-project-internal"
1038 | version = "1.1.5"
1039 | source = "registry+https://github.com/rust-lang/crates.io-index"
1040 | checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
1041 | dependencies = [
1042 | "proc-macro2",
1043 | "quote",
1044 | "syn",
1045 | ]
1046 |
1047 | [[package]]
1048 | name = "pin-project-lite"
1049 | version = "0.2.14"
1050 | source = "registry+https://github.com/rust-lang/crates.io-index"
1051 | checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
1052 |
1053 | [[package]]
1054 | name = "pin-utils"
1055 | version = "0.1.0"
1056 | source = "registry+https://github.com/rust-lang/crates.io-index"
1057 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
1058 |
1059 | [[package]]
1060 | name = "powerfmt"
1061 | version = "0.2.0"
1062 | source = "registry+https://github.com/rust-lang/crates.io-index"
1063 | checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
1064 |
1065 | [[package]]
1066 | name = "ppv-lite86"
1067 | version = "0.2.17"
1068 | source = "registry+https://github.com/rust-lang/crates.io-index"
1069 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
1070 |
1071 | [[package]]
1072 | name = "prettyplease"
1073 | version = "0.2.20"
1074 | source = "registry+https://github.com/rust-lang/crates.io-index"
1075 | checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e"
1076 | dependencies = [
1077 | "proc-macro2",
1078 | "syn",
1079 | ]
1080 |
1081 | [[package]]
1082 | name = "proc-macro2"
1083 | version = "1.0.86"
1084 | source = "registry+https://github.com/rust-lang/crates.io-index"
1085 | checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
1086 | dependencies = [
1087 | "unicode-ident",
1088 | ]
1089 |
1090 | [[package]]
1091 | name = "prost"
1092 | version = "0.13.1"
1093 | source = "registry+https://github.com/rust-lang/crates.io-index"
1094 | checksum = "e13db3d3fde688c61e2446b4d843bc27a7e8af269a69440c0308021dc92333cc"
1095 | dependencies = [
1096 | "bytes",
1097 | "prost-derive",
1098 | ]
1099 |
1100 | [[package]]
1101 | name = "prost-build"
1102 | version = "0.13.0"
1103 | source = "registry+https://github.com/rust-lang/crates.io-index"
1104 | checksum = "04952a6dc0bf60a696e83fc8c58e912d4f6c1d06c6637db44c1cce9c6735c920"
1105 | dependencies = [
1106 | "bytes",
1107 | "heck",
1108 | "itertools",
1109 | "log",
1110 | "multimap",
1111 | "once_cell",
1112 | "petgraph",
1113 | "prettyplease",
1114 | "prost",
1115 | "prost-types",
1116 | "regex",
1117 | "syn",
1118 | "tempfile",
1119 | ]
1120 |
1121 | [[package]]
1122 | name = "prost-derive"
1123 | version = "0.13.1"
1124 | source = "registry+https://github.com/rust-lang/crates.io-index"
1125 | checksum = "18bec9b0adc4eba778b33684b7ba3e7137789434769ee3ce3930463ef904cfca"
1126 | dependencies = [
1127 | "anyhow",
1128 | "itertools",
1129 | "proc-macro2",
1130 | "quote",
1131 | "syn",
1132 | ]
1133 |
1134 | [[package]]
1135 | name = "prost-types"
1136 | version = "0.13.0"
1137 | source = "registry+https://github.com/rust-lang/crates.io-index"
1138 | checksum = "36c1964ef64b94480df8c92ae14e5764d470014ad951d2f99e5a6c0c7712710c"
1139 | dependencies = [
1140 | "prost",
1141 | ]
1142 |
1143 | [[package]]
1144 | name = "quinn"
1145 | version = "0.11.2"
1146 | source = "registry+https://github.com/rust-lang/crates.io-index"
1147 | checksum = "e4ceeeeabace7857413798eb1ffa1e9c905a9946a57d81fb69b4b71c4d8eb3ad"
1148 | dependencies = [
1149 | "bytes",
1150 | "pin-project-lite",
1151 | "quinn-proto",
1152 | "quinn-udp",
1153 | "rustc-hash",
1154 | "rustls",
1155 | "thiserror",
1156 | "tokio",
1157 | "tracing",
1158 | ]
1159 |
1160 | [[package]]
1161 | name = "quinn-proto"
1162 | version = "0.11.3"
1163 | source = "registry+https://github.com/rust-lang/crates.io-index"
1164 | checksum = "ddf517c03a109db8100448a4be38d498df8a210a99fe0e1b9eaf39e78c640efe"
1165 | dependencies = [
1166 | "bytes",
1167 | "rand 0.8.5",
1168 | "ring",
1169 | "rustc-hash",
1170 | "rustls",
1171 | "slab",
1172 | "thiserror",
1173 | "tinyvec",
1174 | "tracing",
1175 | ]
1176 |
1177 | [[package]]
1178 | name = "quinn-udp"
1179 | version = "0.5.2"
1180 | source = "registry+https://github.com/rust-lang/crates.io-index"
1181 | checksum = "9096629c45860fc7fb143e125eb826b5e721e10be3263160c7d60ca832cf8c46"
1182 | dependencies = [
1183 | "libc",
1184 | "once_cell",
1185 | "socket2",
1186 | "tracing",
1187 | "windows-sys 0.52.0",
1188 | ]
1189 |
1190 | [[package]]
1191 | name = "quote"
1192 | version = "1.0.36"
1193 | source = "registry+https://github.com/rust-lang/crates.io-index"
1194 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
1195 | dependencies = [
1196 | "proc-macro2",
1197 | ]
1198 |
1199 | [[package]]
1200 | name = "rand"
1201 | version = "0.8.5"
1202 | source = "registry+https://github.com/rust-lang/crates.io-index"
1203 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
1204 | dependencies = [
1205 | "libc",
1206 | "rand_chacha 0.3.1",
1207 | "rand_core 0.6.4",
1208 | ]
1209 |
1210 | [[package]]
1211 | name = "rand"
1212 | version = "0.9.0-alpha.1"
1213 | source = "registry+https://github.com/rust-lang/crates.io-index"
1214 | checksum = "8d31e63ea85be51c423e52ba8f2e68a3efd53eed30203ee029dd09947333693e"
1215 | dependencies = [
1216 | "rand_chacha 0.9.0-alpha.1",
1217 | "rand_core 0.9.0-alpha.1",
1218 | "zerocopy",
1219 | ]
1220 |
1221 | [[package]]
1222 | name = "rand_chacha"
1223 | version = "0.3.1"
1224 | source = "registry+https://github.com/rust-lang/crates.io-index"
1225 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
1226 | dependencies = [
1227 | "ppv-lite86",
1228 | "rand_core 0.6.4",
1229 | ]
1230 |
1231 | [[package]]
1232 | name = "rand_chacha"
1233 | version = "0.9.0-alpha.1"
1234 | source = "registry+https://github.com/rust-lang/crates.io-index"
1235 | checksum = "78674ef918c19451dbd250f8201f8619b494f64c9aa6f3adb28fd8a0f1f6da46"
1236 | dependencies = [
1237 | "ppv-lite86",
1238 | "rand_core 0.9.0-alpha.1",
1239 | ]
1240 |
1241 | [[package]]
1242 | name = "rand_core"
1243 | version = "0.6.4"
1244 | source = "registry+https://github.com/rust-lang/crates.io-index"
1245 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
1246 | dependencies = [
1247 | "getrandom",
1248 | ]
1249 |
1250 | [[package]]
1251 | name = "rand_core"
1252 | version = "0.9.0-alpha.1"
1253 | source = "registry+https://github.com/rust-lang/crates.io-index"
1254 | checksum = "cc89dffba8377c5ec847d12bb41492bda235dba31a25e8b695cd0fe6589eb8c9"
1255 | dependencies = [
1256 | "getrandom",
1257 | "zerocopy",
1258 | ]
1259 |
1260 | [[package]]
1261 | name = "redox_syscall"
1262 | version = "0.5.2"
1263 | source = "registry+https://github.com/rust-lang/crates.io-index"
1264 | checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd"
1265 | dependencies = [
1266 | "bitflags",
1267 | ]
1268 |
1269 | [[package]]
1270 | name = "regex"
1271 | version = "1.10.5"
1272 | source = "registry+https://github.com/rust-lang/crates.io-index"
1273 | checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
1274 | dependencies = [
1275 | "aho-corasick",
1276 | "memchr",
1277 | "regex-automata",
1278 | "regex-syntax",
1279 | ]
1280 |
1281 | [[package]]
1282 | name = "regex-automata"
1283 | version = "0.4.7"
1284 | source = "registry+https://github.com/rust-lang/crates.io-index"
1285 | checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
1286 | dependencies = [
1287 | "aho-corasick",
1288 | "memchr",
1289 | "regex-syntax",
1290 | ]
1291 |
1292 | [[package]]
1293 | name = "regex-syntax"
1294 | version = "0.8.4"
1295 | source = "registry+https://github.com/rust-lang/crates.io-index"
1296 | checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
1297 |
1298 | [[package]]
1299 | name = "reqwest"
1300 | version = "0.12.5"
1301 | source = "registry+https://github.com/rust-lang/crates.io-index"
1302 | checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37"
1303 | dependencies = [
1304 | "base64",
1305 | "bytes",
1306 | "futures-channel",
1307 | "futures-core",
1308 | "futures-util",
1309 | "http",
1310 | "http-body",
1311 | "http-body-util",
1312 | "hyper",
1313 | "hyper-rustls",
1314 | "hyper-util",
1315 | "ipnet",
1316 | "js-sys",
1317 | "log",
1318 | "mime",
1319 | "once_cell",
1320 | "percent-encoding",
1321 | "pin-project-lite",
1322 | "quinn",
1323 | "rustls",
1324 | "rustls-pemfile",
1325 | "rustls-pki-types",
1326 | "serde",
1327 | "serde_json",
1328 | "serde_urlencoded",
1329 | "sync_wrapper 1.0.1",
1330 | "tokio",
1331 | "tokio-rustls",
1332 | "tower-service",
1333 | "url",
1334 | "wasm-bindgen",
1335 | "wasm-bindgen-futures",
1336 | "web-sys",
1337 | "webpki-roots",
1338 | "winreg",
1339 | ]
1340 |
1341 | [[package]]
1342 | name = "ring"
1343 | version = "0.17.8"
1344 | source = "registry+https://github.com/rust-lang/crates.io-index"
1345 | checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
1346 | dependencies = [
1347 | "cc",
1348 | "cfg-if",
1349 | "getrandom",
1350 | "libc",
1351 | "spin",
1352 | "untrusted",
1353 | "windows-sys 0.52.0",
1354 | ]
1355 |
1356 | [[package]]
1357 | name = "rustc-demangle"
1358 | version = "0.1.24"
1359 | source = "registry+https://github.com/rust-lang/crates.io-index"
1360 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
1361 |
1362 | [[package]]
1363 | name = "rustc-hash"
1364 | version = "1.1.0"
1365 | source = "registry+https://github.com/rust-lang/crates.io-index"
1366 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
1367 |
1368 | [[package]]
1369 | name = "rustix"
1370 | version = "0.38.34"
1371 | source = "registry+https://github.com/rust-lang/crates.io-index"
1372 | checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
1373 | dependencies = [
1374 | "bitflags",
1375 | "errno",
1376 | "libc",
1377 | "linux-raw-sys",
1378 | "windows-sys 0.52.0",
1379 | ]
1380 |
1381 | [[package]]
1382 | name = "rustls"
1383 | version = "0.23.11"
1384 | source = "registry+https://github.com/rust-lang/crates.io-index"
1385 | checksum = "4828ea528154ae444e5a642dbb7d5623354030dc9822b83fd9bb79683c7399d0"
1386 | dependencies = [
1387 | "aws-lc-rs",
1388 | "log",
1389 | "once_cell",
1390 | "ring",
1391 | "rustls-pki-types",
1392 | "rustls-webpki",
1393 | "subtle",
1394 | "zeroize",
1395 | ]
1396 |
1397 | [[package]]
1398 | name = "rustls-pemfile"
1399 | version = "2.1.2"
1400 | source = "registry+https://github.com/rust-lang/crates.io-index"
1401 | checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d"
1402 | dependencies = [
1403 | "base64",
1404 | "rustls-pki-types",
1405 | ]
1406 |
1407 | [[package]]
1408 | name = "rustls-pki-types"
1409 | version = "1.7.0"
1410 | source = "registry+https://github.com/rust-lang/crates.io-index"
1411 | checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d"
1412 |
1413 | [[package]]
1414 | name = "rustls-webpki"
1415 | version = "0.102.5"
1416 | source = "registry+https://github.com/rust-lang/crates.io-index"
1417 | checksum = "f9a6fccd794a42c2c105b513a2f62bc3fd8f3ba57a4593677ceb0bd035164d78"
1418 | dependencies = [
1419 | "aws-lc-rs",
1420 | "ring",
1421 | "rustls-pki-types",
1422 | "untrusted",
1423 | ]
1424 |
1425 | [[package]]
1426 | name = "rustversion"
1427 | version = "1.0.17"
1428 | source = "registry+https://github.com/rust-lang/crates.io-index"
1429 | checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
1430 |
1431 | [[package]]
1432 | name = "ryu"
1433 | version = "1.0.18"
1434 | source = "registry+https://github.com/rust-lang/crates.io-index"
1435 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
1436 |
1437 | [[package]]
1438 | name = "scopeguard"
1439 | version = "1.2.0"
1440 | source = "registry+https://github.com/rust-lang/crates.io-index"
1441 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
1442 |
1443 | [[package]]
1444 | name = "serde"
1445 | version = "1.0.203"
1446 | source = "registry+https://github.com/rust-lang/crates.io-index"
1447 | checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
1448 | dependencies = [
1449 | "serde_derive",
1450 | ]
1451 |
1452 | [[package]]
1453 | name = "serde_derive"
1454 | version = "1.0.203"
1455 | source = "registry+https://github.com/rust-lang/crates.io-index"
1456 | checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
1457 | dependencies = [
1458 | "proc-macro2",
1459 | "quote",
1460 | "syn",
1461 | ]
1462 |
1463 | [[package]]
1464 | name = "serde_json"
1465 | version = "1.0.120"
1466 | source = "registry+https://github.com/rust-lang/crates.io-index"
1467 | checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5"
1468 | dependencies = [
1469 | "itoa",
1470 | "ryu",
1471 | "serde",
1472 | ]
1473 |
1474 | [[package]]
1475 | name = "serde_urlencoded"
1476 | version = "0.7.1"
1477 | source = "registry+https://github.com/rust-lang/crates.io-index"
1478 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
1479 | dependencies = [
1480 | "form_urlencoded",
1481 | "itoa",
1482 | "ryu",
1483 | "serde",
1484 | ]
1485 |
1486 | [[package]]
1487 | name = "shlex"
1488 | version = "1.3.0"
1489 | source = "registry+https://github.com/rust-lang/crates.io-index"
1490 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
1491 |
1492 | [[package]]
1493 | name = "signal-hook-registry"
1494 | version = "1.4.2"
1495 | source = "registry+https://github.com/rust-lang/crates.io-index"
1496 | checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
1497 | dependencies = [
1498 | "libc",
1499 | ]
1500 |
1501 | [[package]]
1502 | name = "simple_logger"
1503 | version = "5.0.0"
1504 | source = "registry+https://github.com/rust-lang/crates.io-index"
1505 | checksum = "e8c5dfa5e08767553704aa0ffd9d9794d527103c736aba9854773851fd7497eb"
1506 | dependencies = [
1507 | "colored",
1508 | "log",
1509 | "time",
1510 | "windows-sys 0.48.0",
1511 | ]
1512 |
1513 | [[package]]
1514 | name = "slab"
1515 | version = "0.4.9"
1516 | source = "registry+https://github.com/rust-lang/crates.io-index"
1517 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
1518 | dependencies = [
1519 | "autocfg",
1520 | ]
1521 |
1522 | [[package]]
1523 | name = "smallvec"
1524 | version = "1.13.2"
1525 | source = "registry+https://github.com/rust-lang/crates.io-index"
1526 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
1527 |
1528 | [[package]]
1529 | name = "socket2"
1530 | version = "0.5.7"
1531 | source = "registry+https://github.com/rust-lang/crates.io-index"
1532 | checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
1533 | dependencies = [
1534 | "libc",
1535 | "windows-sys 0.52.0",
1536 | ]
1537 |
1538 | [[package]]
1539 | name = "spin"
1540 | version = "0.9.8"
1541 | source = "registry+https://github.com/rust-lang/crates.io-index"
1542 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
1543 |
1544 | [[package]]
1545 | name = "strsim"
1546 | version = "0.11.1"
1547 | source = "registry+https://github.com/rust-lang/crates.io-index"
1548 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
1549 |
1550 | [[package]]
1551 | name = "subtle"
1552 | version = "2.6.1"
1553 | source = "registry+https://github.com/rust-lang/crates.io-index"
1554 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
1555 |
1556 | [[package]]
1557 | name = "syn"
1558 | version = "2.0.68"
1559 | source = "registry+https://github.com/rust-lang/crates.io-index"
1560 | checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9"
1561 | dependencies = [
1562 | "proc-macro2",
1563 | "quote",
1564 | "unicode-ident",
1565 | ]
1566 |
1567 | [[package]]
1568 | name = "sync_wrapper"
1569 | version = "0.1.2"
1570 | source = "registry+https://github.com/rust-lang/crates.io-index"
1571 | checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
1572 |
1573 | [[package]]
1574 | name = "sync_wrapper"
1575 | version = "1.0.1"
1576 | source = "registry+https://github.com/rust-lang/crates.io-index"
1577 | checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
1578 |
1579 | [[package]]
1580 | name = "tempfile"
1581 | version = "3.10.1"
1582 | source = "registry+https://github.com/rust-lang/crates.io-index"
1583 | checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
1584 | dependencies = [
1585 | "cfg-if",
1586 | "fastrand",
1587 | "rustix",
1588 | "windows-sys 0.52.0",
1589 | ]
1590 |
1591 | [[package]]
1592 | name = "thiserror"
1593 | version = "1.0.61"
1594 | source = "registry+https://github.com/rust-lang/crates.io-index"
1595 | checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
1596 | dependencies = [
1597 | "thiserror-impl",
1598 | ]
1599 |
1600 | [[package]]
1601 | name = "thiserror-impl"
1602 | version = "1.0.61"
1603 | source = "registry+https://github.com/rust-lang/crates.io-index"
1604 | checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
1605 | dependencies = [
1606 | "proc-macro2",
1607 | "quote",
1608 | "syn",
1609 | ]
1610 |
1611 | [[package]]
1612 | name = "time"
1613 | version = "0.3.36"
1614 | source = "registry+https://github.com/rust-lang/crates.io-index"
1615 | checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
1616 | dependencies = [
1617 | "deranged",
1618 | "itoa",
1619 | "libc",
1620 | "num-conv",
1621 | "num_threads",
1622 | "powerfmt",
1623 | "serde",
1624 | "time-core",
1625 | "time-macros",
1626 | ]
1627 |
1628 | [[package]]
1629 | name = "time-core"
1630 | version = "0.1.2"
1631 | source = "registry+https://github.com/rust-lang/crates.io-index"
1632 | checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
1633 |
1634 | [[package]]
1635 | name = "time-macros"
1636 | version = "0.2.18"
1637 | source = "registry+https://github.com/rust-lang/crates.io-index"
1638 | checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
1639 | dependencies = [
1640 | "num-conv",
1641 | "time-core",
1642 | ]
1643 |
1644 | [[package]]
1645 | name = "tinyvec"
1646 | version = "1.7.0"
1647 | source = "registry+https://github.com/rust-lang/crates.io-index"
1648 | checksum = "ce6b6a2fb3a985e99cebfaefa9faa3024743da73304ca1c683a36429613d3d22"
1649 | dependencies = [
1650 | "tinyvec_macros",
1651 | ]
1652 |
1653 | [[package]]
1654 | name = "tinyvec_macros"
1655 | version = "0.1.1"
1656 | source = "registry+https://github.com/rust-lang/crates.io-index"
1657 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
1658 |
1659 | [[package]]
1660 | name = "tokio"
1661 | version = "1.38.0"
1662 | source = "registry+https://github.com/rust-lang/crates.io-index"
1663 | checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a"
1664 | dependencies = [
1665 | "backtrace",
1666 | "bytes",
1667 | "libc",
1668 | "mio",
1669 | "num_cpus",
1670 | "parking_lot",
1671 | "pin-project-lite",
1672 | "signal-hook-registry",
1673 | "socket2",
1674 | "tokio-macros",
1675 | "windows-sys 0.48.0",
1676 | ]
1677 |
1678 | [[package]]
1679 | name = "tokio-macros"
1680 | version = "2.3.0"
1681 | source = "registry+https://github.com/rust-lang/crates.io-index"
1682 | checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a"
1683 | dependencies = [
1684 | "proc-macro2",
1685 | "quote",
1686 | "syn",
1687 | ]
1688 |
1689 | [[package]]
1690 | name = "tokio-rustls"
1691 | version = "0.26.0"
1692 | source = "registry+https://github.com/rust-lang/crates.io-index"
1693 | checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
1694 | dependencies = [
1695 | "rustls",
1696 | "rustls-pki-types",
1697 | "tokio",
1698 | ]
1699 |
1700 | [[package]]
1701 | name = "tokio-stream"
1702 | version = "0.1.15"
1703 | source = "registry+https://github.com/rust-lang/crates.io-index"
1704 | checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af"
1705 | dependencies = [
1706 | "futures-core",
1707 | "pin-project-lite",
1708 | "tokio",
1709 | ]
1710 |
1711 | [[package]]
1712 | name = "tokio-util"
1713 | version = "0.7.11"
1714 | source = "registry+https://github.com/rust-lang/crates.io-index"
1715 | checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1"
1716 | dependencies = [
1717 | "bytes",
1718 | "futures-core",
1719 | "futures-sink",
1720 | "pin-project-lite",
1721 | "tokio",
1722 | ]
1723 |
1724 | [[package]]
1725 | name = "tonic"
1726 | version = "0.12.0"
1727 | source = "registry+https://github.com/rust-lang/crates.io-index"
1728 | checksum = "f738b6a169a29bca4e39656db89c44a08e09c5b700b896ee9e7459f0652e81dd"
1729 | dependencies = [
1730 | "async-stream",
1731 | "async-trait",
1732 | "axum",
1733 | "base64",
1734 | "bytes",
1735 | "h2",
1736 | "http",
1737 | "http-body",
1738 | "http-body-util",
1739 | "hyper",
1740 | "hyper-timeout",
1741 | "hyper-util",
1742 | "percent-encoding",
1743 | "pin-project",
1744 | "prost",
1745 | "socket2",
1746 | "tokio",
1747 | "tokio-stream",
1748 | "tower",
1749 | "tower-layer",
1750 | "tower-service",
1751 | "tracing",
1752 | ]
1753 |
1754 | [[package]]
1755 | name = "tonic-build"
1756 | version = "0.12.0"
1757 | source = "registry+https://github.com/rust-lang/crates.io-index"
1758 | checksum = "690943cc223adcdd67bb597a2e573ead1b88e999ba37528fe8e6356bf44b29b6"
1759 | dependencies = [
1760 | "prettyplease",
1761 | "proc-macro2",
1762 | "prost-build",
1763 | "quote",
1764 | "syn",
1765 | ]
1766 |
1767 | [[package]]
1768 | name = "tower"
1769 | version = "0.4.13"
1770 | source = "registry+https://github.com/rust-lang/crates.io-index"
1771 | checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
1772 | dependencies = [
1773 | "futures-core",
1774 | "futures-util",
1775 | "indexmap 1.9.3",
1776 | "pin-project",
1777 | "pin-project-lite",
1778 | "rand 0.8.5",
1779 | "slab",
1780 | "tokio",
1781 | "tokio-util",
1782 | "tower-layer",
1783 | "tower-service",
1784 | "tracing",
1785 | ]
1786 |
1787 | [[package]]
1788 | name = "tower-layer"
1789 | version = "0.3.2"
1790 | source = "registry+https://github.com/rust-lang/crates.io-index"
1791 | checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0"
1792 |
1793 | [[package]]
1794 | name = "tower-service"
1795 | version = "0.3.2"
1796 | source = "registry+https://github.com/rust-lang/crates.io-index"
1797 | checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
1798 |
1799 | [[package]]
1800 | name = "tracing"
1801 | version = "0.1.40"
1802 | source = "registry+https://github.com/rust-lang/crates.io-index"
1803 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
1804 | dependencies = [
1805 | "pin-project-lite",
1806 | "tracing-attributes",
1807 | "tracing-core",
1808 | ]
1809 |
1810 | [[package]]
1811 | name = "tracing-attributes"
1812 | version = "0.1.27"
1813 | source = "registry+https://github.com/rust-lang/crates.io-index"
1814 | checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
1815 | dependencies = [
1816 | "proc-macro2",
1817 | "quote",
1818 | "syn",
1819 | ]
1820 |
1821 | [[package]]
1822 | name = "tracing-core"
1823 | version = "0.1.32"
1824 | source = "registry+https://github.com/rust-lang/crates.io-index"
1825 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
1826 | dependencies = [
1827 | "once_cell",
1828 | ]
1829 |
1830 | [[package]]
1831 | name = "try-lock"
1832 | version = "0.2.5"
1833 | source = "registry+https://github.com/rust-lang/crates.io-index"
1834 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
1835 |
1836 | [[package]]
1837 | name = "unicode-bidi"
1838 | version = "0.3.15"
1839 | source = "registry+https://github.com/rust-lang/crates.io-index"
1840 | checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
1841 |
1842 | [[package]]
1843 | name = "unicode-ident"
1844 | version = "1.0.12"
1845 | source = "registry+https://github.com/rust-lang/crates.io-index"
1846 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
1847 |
1848 | [[package]]
1849 | name = "unicode-normalization"
1850 | version = "0.1.23"
1851 | source = "registry+https://github.com/rust-lang/crates.io-index"
1852 | checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5"
1853 | dependencies = [
1854 | "tinyvec",
1855 | ]
1856 |
1857 | [[package]]
1858 | name = "untrusted"
1859 | version = "0.9.0"
1860 | source = "registry+https://github.com/rust-lang/crates.io-index"
1861 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
1862 |
1863 | [[package]]
1864 | name = "url"
1865 | version = "2.5.2"
1866 | source = "registry+https://github.com/rust-lang/crates.io-index"
1867 | checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
1868 | dependencies = [
1869 | "form_urlencoded",
1870 | "idna",
1871 | "percent-encoding",
1872 | ]
1873 |
1874 | [[package]]
1875 | name = "utf8parse"
1876 | version = "0.2.2"
1877 | source = "registry+https://github.com/rust-lang/crates.io-index"
1878 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
1879 |
1880 | [[package]]
1881 | name = "uuid"
1882 | version = "1.10.0"
1883 | source = "registry+https://github.com/rust-lang/crates.io-index"
1884 | checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
1885 | dependencies = [
1886 | "getrandom",
1887 | ]
1888 |
1889 | [[package]]
1890 | name = "want"
1891 | version = "0.3.1"
1892 | source = "registry+https://github.com/rust-lang/crates.io-index"
1893 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
1894 | dependencies = [
1895 | "try-lock",
1896 | ]
1897 |
1898 | [[package]]
1899 | name = "wasi"
1900 | version = "0.11.0+wasi-snapshot-preview1"
1901 | source = "registry+https://github.com/rust-lang/crates.io-index"
1902 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
1903 |
1904 | [[package]]
1905 | name = "wasm-bindgen"
1906 | version = "0.2.92"
1907 | source = "registry+https://github.com/rust-lang/crates.io-index"
1908 | checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
1909 | dependencies = [
1910 | "cfg-if",
1911 | "wasm-bindgen-macro",
1912 | ]
1913 |
1914 | [[package]]
1915 | name = "wasm-bindgen-backend"
1916 | version = "0.2.92"
1917 | source = "registry+https://github.com/rust-lang/crates.io-index"
1918 | checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
1919 | dependencies = [
1920 | "bumpalo",
1921 | "log",
1922 | "once_cell",
1923 | "proc-macro2",
1924 | "quote",
1925 | "syn",
1926 | "wasm-bindgen-shared",
1927 | ]
1928 |
1929 | [[package]]
1930 | name = "wasm-bindgen-futures"
1931 | version = "0.4.42"
1932 | source = "registry+https://github.com/rust-lang/crates.io-index"
1933 | checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0"
1934 | dependencies = [
1935 | "cfg-if",
1936 | "js-sys",
1937 | "wasm-bindgen",
1938 | "web-sys",
1939 | ]
1940 |
1941 | [[package]]
1942 | name = "wasm-bindgen-macro"
1943 | version = "0.2.92"
1944 | source = "registry+https://github.com/rust-lang/crates.io-index"
1945 | checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
1946 | dependencies = [
1947 | "quote",
1948 | "wasm-bindgen-macro-support",
1949 | ]
1950 |
1951 | [[package]]
1952 | name = "wasm-bindgen-macro-support"
1953 | version = "0.2.92"
1954 | source = "registry+https://github.com/rust-lang/crates.io-index"
1955 | checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
1956 | dependencies = [
1957 | "proc-macro2",
1958 | "quote",
1959 | "syn",
1960 | "wasm-bindgen-backend",
1961 | "wasm-bindgen-shared",
1962 | ]
1963 |
1964 | [[package]]
1965 | name = "wasm-bindgen-shared"
1966 | version = "0.2.92"
1967 | source = "registry+https://github.com/rust-lang/crates.io-index"
1968 | checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
1969 |
1970 | [[package]]
1971 | name = "web-sys"
1972 | version = "0.3.69"
1973 | source = "registry+https://github.com/rust-lang/crates.io-index"
1974 | checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
1975 | dependencies = [
1976 | "js-sys",
1977 | "wasm-bindgen",
1978 | ]
1979 |
1980 | [[package]]
1981 | name = "webpki-roots"
1982 | version = "0.26.3"
1983 | source = "registry+https://github.com/rust-lang/crates.io-index"
1984 | checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd"
1985 | dependencies = [
1986 | "rustls-pki-types",
1987 | ]
1988 |
1989 | [[package]]
1990 | name = "which"
1991 | version = "4.4.2"
1992 | source = "registry+https://github.com/rust-lang/crates.io-index"
1993 | checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
1994 | dependencies = [
1995 | "either",
1996 | "home",
1997 | "once_cell",
1998 | "rustix",
1999 | ]
2000 |
2001 | [[package]]
2002 | name = "windows-sys"
2003 | version = "0.48.0"
2004 | source = "registry+https://github.com/rust-lang/crates.io-index"
2005 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
2006 | dependencies = [
2007 | "windows-targets 0.48.5",
2008 | ]
2009 |
2010 | [[package]]
2011 | name = "windows-sys"
2012 | version = "0.52.0"
2013 | source = "registry+https://github.com/rust-lang/crates.io-index"
2014 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
2015 | dependencies = [
2016 | "windows-targets 0.52.6",
2017 | ]
2018 |
2019 | [[package]]
2020 | name = "windows-targets"
2021 | version = "0.48.5"
2022 | source = "registry+https://github.com/rust-lang/crates.io-index"
2023 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
2024 | dependencies = [
2025 | "windows_aarch64_gnullvm 0.48.5",
2026 | "windows_aarch64_msvc 0.48.5",
2027 | "windows_i686_gnu 0.48.5",
2028 | "windows_i686_msvc 0.48.5",
2029 | "windows_x86_64_gnu 0.48.5",
2030 | "windows_x86_64_gnullvm 0.48.5",
2031 | "windows_x86_64_msvc 0.48.5",
2032 | ]
2033 |
2034 | [[package]]
2035 | name = "windows-targets"
2036 | version = "0.52.6"
2037 | source = "registry+https://github.com/rust-lang/crates.io-index"
2038 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
2039 | dependencies = [
2040 | "windows_aarch64_gnullvm 0.52.6",
2041 | "windows_aarch64_msvc 0.52.6",
2042 | "windows_i686_gnu 0.52.6",
2043 | "windows_i686_gnullvm",
2044 | "windows_i686_msvc 0.52.6",
2045 | "windows_x86_64_gnu 0.52.6",
2046 | "windows_x86_64_gnullvm 0.52.6",
2047 | "windows_x86_64_msvc 0.52.6",
2048 | ]
2049 |
2050 | [[package]]
2051 | name = "windows_aarch64_gnullvm"
2052 | version = "0.48.5"
2053 | source = "registry+https://github.com/rust-lang/crates.io-index"
2054 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
2055 |
2056 | [[package]]
2057 | name = "windows_aarch64_gnullvm"
2058 | version = "0.52.6"
2059 | source = "registry+https://github.com/rust-lang/crates.io-index"
2060 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
2061 |
2062 | [[package]]
2063 | name = "windows_aarch64_msvc"
2064 | version = "0.48.5"
2065 | source = "registry+https://github.com/rust-lang/crates.io-index"
2066 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
2067 |
2068 | [[package]]
2069 | name = "windows_aarch64_msvc"
2070 | version = "0.52.6"
2071 | source = "registry+https://github.com/rust-lang/crates.io-index"
2072 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
2073 |
2074 | [[package]]
2075 | name = "windows_i686_gnu"
2076 | version = "0.48.5"
2077 | source = "registry+https://github.com/rust-lang/crates.io-index"
2078 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
2079 |
2080 | [[package]]
2081 | name = "windows_i686_gnu"
2082 | version = "0.52.6"
2083 | source = "registry+https://github.com/rust-lang/crates.io-index"
2084 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
2085 |
2086 | [[package]]
2087 | name = "windows_i686_gnullvm"
2088 | version = "0.52.6"
2089 | source = "registry+https://github.com/rust-lang/crates.io-index"
2090 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
2091 |
2092 | [[package]]
2093 | name = "windows_i686_msvc"
2094 | version = "0.48.5"
2095 | source = "registry+https://github.com/rust-lang/crates.io-index"
2096 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
2097 |
2098 | [[package]]
2099 | name = "windows_i686_msvc"
2100 | version = "0.52.6"
2101 | source = "registry+https://github.com/rust-lang/crates.io-index"
2102 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
2103 |
2104 | [[package]]
2105 | name = "windows_x86_64_gnu"
2106 | version = "0.48.5"
2107 | source = "registry+https://github.com/rust-lang/crates.io-index"
2108 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
2109 |
2110 | [[package]]
2111 | name = "windows_x86_64_gnu"
2112 | version = "0.52.6"
2113 | source = "registry+https://github.com/rust-lang/crates.io-index"
2114 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
2115 |
2116 | [[package]]
2117 | name = "windows_x86_64_gnullvm"
2118 | version = "0.48.5"
2119 | source = "registry+https://github.com/rust-lang/crates.io-index"
2120 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
2121 |
2122 | [[package]]
2123 | name = "windows_x86_64_gnullvm"
2124 | version = "0.52.6"
2125 | source = "registry+https://github.com/rust-lang/crates.io-index"
2126 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
2127 |
2128 | [[package]]
2129 | name = "windows_x86_64_msvc"
2130 | version = "0.48.5"
2131 | source = "registry+https://github.com/rust-lang/crates.io-index"
2132 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
2133 |
2134 | [[package]]
2135 | name = "windows_x86_64_msvc"
2136 | version = "0.52.6"
2137 | source = "registry+https://github.com/rust-lang/crates.io-index"
2138 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
2139 |
2140 | [[package]]
2141 | name = "winreg"
2142 | version = "0.52.0"
2143 | source = "registry+https://github.com/rust-lang/crates.io-index"
2144 | checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5"
2145 | dependencies = [
2146 | "cfg-if",
2147 | "windows-sys 0.48.0",
2148 | ]
2149 |
2150 | [[package]]
2151 | name = "zerocopy"
2152 | version = "0.8.0-alpha.6"
2153 | source = "registry+https://github.com/rust-lang/crates.io-index"
2154 | checksum = "db678a6ee512bd06adf35c35be471cae2f9c82a5aed2b5d15e03628c98bddd57"
2155 | dependencies = [
2156 | "zerocopy-derive",
2157 | ]
2158 |
2159 | [[package]]
2160 | name = "zerocopy-derive"
2161 | version = "0.8.0-alpha.6"
2162 | source = "registry+https://github.com/rust-lang/crates.io-index"
2163 | checksum = "201585ea96d37ee69f2ac769925ca57160cef31acb137c16f38b02b76f4c1e62"
2164 | dependencies = [
2165 | "proc-macro2",
2166 | "quote",
2167 | "syn",
2168 | ]
2169 |
2170 | [[package]]
2171 | name = "zeroize"
2172 | version = "1.8.1"
2173 | source = "registry+https://github.com/rust-lang/crates.io-index"
2174 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
2175 | dependencies = [
2176 | "zeroize_derive",
2177 | ]
2178 |
2179 | [[package]]
2180 | name = "zeroize_derive"
2181 | version = "1.4.2"
2182 | source = "registry+https://github.com/rust-lang/crates.io-index"
2183 | checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
2184 | dependencies = [
2185 | "proc-macro2",
2186 | "quote",
2187 | "syn",
2188 | ]
2189 |
--------------------------------------------------------------------------------