From 5071997ffcf9048429d35094b06b05fbd7bd6cae Mon Sep 17 00:00:00 2001 From: wisdgod Date: Sat, 5 Apr 2025 17:21:49 +0800 Subject: [PATCH] 0.1.3-rc.5.2.4 --- .cargo/config.toml | 3 + .github/workflows/docker.yml | 12 +- .gitignore | 2 +- Cargo.lock | 3030 --------------------------- Cargo.toml | 16 +- Cursor API.md | 4 +- Dockerfile | 4 +- Dockerfile.cross | 2 +- README.md | 104 +- build.rs | 37 +- src/app/config.rs | 16 +- src/app/constant.rs | 15 +- src/app/lazy.rs | 22 +- src/app/model.rs | 110 +- src/app/model/build_key.rs | 2 +- src/app/model/config.rs | 12 +- src/app/model/proxy_pool.rs | 21 +- src/app/model/state.rs | 23 +- src/common/client.rs | 139 +- src/common/model.rs | 13 +- src/common/model/error.rs | 6 +- src/common/model/health.rs | 2 +- src/common/utils.rs | 95 +- src/common/utils/checksum.rs | 61 +- src/common/utils/token.rs | 26 +- src/core/adapter.rs | 20 +- src/core/aiserver/v1/aiserver.v1.rs | 455 +--- src/core/aiserver/v1/lite.proto | 2 + src/core/config.rs | 3 +- src/core/config/key.proto | 12 +- src/core/config/key.rs | 102 + src/core/constant.rs | 24 +- src/core/constant/display_name.rs | 171 ++ src/core/error.rs | 8 +- src/core/middleware/auth.rs | 16 - src/core/model.rs | 23 +- src/core/route.rs | 8 +- src/core/route/health.rs | 85 +- src/core/route/profile.rs | 50 +- src/core/route/proxies.rs | 32 +- src/core/route/token.rs | 28 +- src/core/route/tokens.rs | 191 +- src/core/service.rs | 38 +- src/core/stream/decoder.rs | 8 + src/main.rs | 36 +- static/api.html | 4 +- static/logs.html | 6 +- static/proxies.html | 4 +- static/tokens.html | 355 +++- tools/get-token/src/main.rs | 2 +- 50 files changed, 1591 insertions(+), 3869 deletions(-) create mode 100644 .cargo/config.toml delete mode 100644 Cargo.lock create mode 100644 src/core/config/key.rs create mode 100644 src/core/constant/display_name.rs diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..0eba3eb --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,3 @@ +[unstable] +profile-rustflags = true +trim-paths = true diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index ff4bb18..1a1db2b 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -36,14 +36,14 @@ jobs: echo "version=v${VERSION}" >> $GITHUB_OUTPUT - name: Log in to Docker Hub - uses: docker/login-action@v3.3.0 + uses: docker/login-action@v3.4.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Extract metadata for Docker id: meta - uses: docker/metadata-action@v5.6.1 + uses: docker/metadata-action@v5.7.0 with: images: ${{ env.IMAGE_NAME }} tags: | @@ -53,20 +53,20 @@ jobs: type=raw,value=${{ github.ref_name }},enable=${{ github.event_name == 'push' }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.8.0 + uses: docker/setup-buildx-action@v3.10.0 with: driver-opts: | image=moby/buildkit:latest network=host - name: Build and push Docker image - uses: docker/build-push-action@v6.11.0 + uses: docker/build-push-action@v6.15.0 env: DOCKER_BUILD_RECORD_UPLOAD: false with: context: . push: true - platforms: linux/amd64,linux/arm64v8 + platforms: linux/amd64,linux/arm64 tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha @@ -93,4 +93,4 @@ jobs: with: name: cursor-api-binaries path: artifacts/ - retention-days: 7 \ No newline at end of file + retention-days: 7 diff --git a/.gitignore b/.gitignore index 5769e4a..8b0d141 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,6 @@ node_modules .DS_Store /.vscode -/.cargo /.token /.token-list /.tokens @@ -25,3 +24,4 @@ node_modules /result.txt tools/tokenizer/ /diff +/Cargo.lock diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index c4d1ea8..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,3030 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - -[[package]] -name = "ahash" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" -dependencies = [ - "getrandom 0.2.15", - "once_cell", - "version_check", -] - -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy 0.7.35", -] - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "alloc-no-stdlib" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" - -[[package]] -name = "alloc-stdlib" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" -dependencies = [ - "alloc-no-stdlib", -] - -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anyhow" -version = "1.0.97" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" - -[[package]] -name = "async-compression" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a194f9d963d8099596278594b3107448656ba73831c9d8c783e613ce86da64" -dependencies = [ - "brotli", - "flate2", - "futures-core", - "memchr", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - -[[package]] -name = "axum" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de45108900e1f9b9242f7f2e254aa3e2c029c921c258fe9e6b4217eeebd54288" -dependencies = [ - "axum-core", - "bytes", - "form_urlencoded", - "futures-util", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-util", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "serde_json", - "serde_path_to_error", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6" -dependencies = [ - "bytes", - "futures-core", - "http", - "http-body", - "http-body-util", - "mime", - "pin-project-lite", - "rustversion", - "sync_wrapper", - "tower-layer", - "tower-service", -] - -[[package]] -name = "backtrace" -version = "0.3.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" - -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "brotli" -version = "7.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", -] - -[[package]] -name = "brotli-decompressor" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - -[[package]] -name = "bumpalo" -version = "3.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" - -[[package]] -name = "bytecheck" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" -dependencies = [ - "bytecheck_derive", - "ptr_meta 0.1.4", - "simdutf8", -] - -[[package]] -name = "bytecheck_derive" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "bytemuck" -version = "1.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" - -[[package]] -name = "byteorder-lite" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" - -[[package]] -name = "bytes" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" - -[[package]] -name = "cc" -version = "1.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" -dependencies = [ - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - -[[package]] -name = "chrono" -version = "0.4.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "num-traits", - "rkyv 0.7.45", - "serde", - "windows-link", -] - -[[package]] -name = "chrono-tz" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efdce149c370f133a071ca8ef6ea340b7b88748ab0810097a9e2976eaa34b4f3" -dependencies = [ - "chrono", - "chrono-tz-build", - "phf", - "serde", -] - -[[package]] -name = "chrono-tz-build" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f10f8c9340e31fc120ff885fcdb54a0b48e474bbd77cab557f0c30a3e569402" -dependencies = [ - "parse-zoneinfo", - "phf_codegen", -] - -[[package]] -name = "color_quant" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "cursor-api" -version = "0.1.3-rc.5.2.3" -dependencies = [ - "axum", - "base64", - "bytes", - "chrono", - "chrono-tz", - "dotenvy", - "flate2", - "futures", - "gif", - "hex", - "image", - "lasso", - "memmap2", - "parking_lot", - "paste", - "prost", - "prost-build", - "prost-types", - "rand 0.9.0", - "regex", - "reqwest", - "rkyv 0.7.45", - "serde", - "serde_json", - "sha2", - "sonic-rs", - "sysinfo", - "tokio", - "tower-http", - "url", - "uuid", -] - -[[package]] -name = "dashmap" -version = "6.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" -dependencies = [ - "cfg-if", - "crossbeam-utils", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "dotenvy" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "errno" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "faststr" -version = "0.2.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6503af7917fea18ffef8f7e8553fb8dff89e2e6837e94e09dd7fb069c82d62c" -dependencies = [ - "bytes", - "rkyv 0.8.10", - "serde", - "simdutf8", -] - -[[package]] -name = "fdeflate" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" -dependencies = [ - "simd-adler32", -] - -[[package]] -name = "fixedbitset" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" - -[[package]] -name = "flate2" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "futures" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-io" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-macro" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "wasm-bindgen", -] - -[[package]] -name = "getrandom" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "r-efi", - "wasi 0.14.2+wasi-0.2.4", - "wasm-bindgen", -] - -[[package]] -name = "gif" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" -dependencies = [ - "color_quant", - "weezl", -] - -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - -[[package]] -name = "h2" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash 0.7.8", -] - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash 0.8.11", - "allocator-api2", -] - -[[package]] -name = "hashbrown" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "http" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" -dependencies = [ - "bytes", - "http", -] - -[[package]] -name = "http-body-util" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" -dependencies = [ - "bytes", - "futures-core", - "http", - "http-body", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.27.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" -dependencies = [ - "futures-util", - "http", - "hyper", - "hyper-util", - "rustls", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tower-service", - "webpki-roots", -] - -[[package]] -name = "hyper-util" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "http", - "http-body", - "hyper", - "libc", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core 0.61.0", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "icu_collections" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locid" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" - -[[package]] -name = "icu_normalizer" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "utf16_iter", - "utf8_iter", - "write16", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" - -[[package]] -name = "icu_properties" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locid_transform", - "icu_properties_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" - -[[package]] -name = "icu_provider" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "idna" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "image" -version = "0.25.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" -dependencies = [ - "bytemuck", - "byteorder-lite", - "color_quant", - "gif", - "image-webp", - "num-traits", - "png", - "zune-core", - "zune-jpeg", -] - -[[package]] -name = "image-webp" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b77d01e822461baa8409e156015a1d91735549f0f2c17691bd2d996bef238f7f" -dependencies = [ - "byteorder-lite", - "quick-error", -] - -[[package]] -name = "indexmap" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" -dependencies = [ - "equivalent", - "hashbrown 0.15.2", -] - -[[package]] -name = "ipnet" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" - -[[package]] -name = "itertools" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "js-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "lasso" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e14eda50a3494b3bf7b9ce51c52434a761e383d7238ce1dd5dcec2fbc13e9fb" -dependencies = [ - "dashmap", - "hashbrown 0.14.5", -] - -[[package]] -name = "libc" -version = "0.2.171" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" - -[[package]] -name = "linux-raw-sys" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" - -[[package]] -name = "litemap" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" - -[[package]] -name = "matchit" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "memmap2" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" -dependencies = [ - "libc", -] - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "miniz_oxide" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" -dependencies = [ - "adler2", - "simd-adler32", -] - -[[package]] -name = "mio" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" -dependencies = [ - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", -] - -[[package]] -name = "multimap" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" - -[[package]] -name = "munge" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0091202c98cf06da46c279fdf50cccb6b1c43b4521abdf6a27b4c7e71d5d9d7" -dependencies = [ - "munge_macro", -] - -[[package]] -name = "munge_macro" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "734799cf91479720b2f970c61a22850940dd91e27d4f02b1c6fc792778df2459" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "ntapi" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" -dependencies = [ - "winapi", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "parse-zoneinfo" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24" -dependencies = [ - "regex", -] - -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "petgraph" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" -dependencies = [ - "fixedbitset", - "indexmap", -] - -[[package]] -name = "phf" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" -dependencies = [ - "phf_shared", -] - -[[package]] -name = "phf_codegen" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" -dependencies = [ - "phf_generator", - "phf_shared", -] - -[[package]] -name = "phf_generator" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" -dependencies = [ - "phf_shared", - "rand 0.8.5", -] - -[[package]] -name = "phf_shared" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "png" -version = "0.17.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" -dependencies = [ - "bitflags 1.3.2", - "crc32fast", - "fdeflate", - "flate2", - "miniz_oxide", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy 0.8.24", -] - -[[package]] -name = "prettyplease" -version = "0.2.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5316f57387668042f561aae71480de936257848f9c43ce528e311d89a07cadeb" -dependencies = [ - "proc-macro2", - "syn 2.0.100", -] - -[[package]] -name = "proc-macro2" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "prost" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-build" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" -dependencies = [ - "heck", - "itertools", - "log", - "multimap", - "once_cell", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn 2.0.100", - "tempfile", -] - -[[package]] -name = "prost-derive" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "prost-types" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" -dependencies = [ - "prost", -] - -[[package]] -name = "ptr_meta" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" -dependencies = [ - "ptr_meta_derive 0.1.4", -] - -[[package]] -name = "ptr_meta" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9e76f66d3f9606f44e45598d155cb13ecf09f4a28199e48daf8c8fc937ea90" -dependencies = [ - "ptr_meta_derive 0.3.0", -] - -[[package]] -name = "ptr_meta_derive" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ptr_meta_derive" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca414edb151b4c8d125c12566ab0d74dc9cdba36fb80eb7b848c15f495fd32d1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "quick-error" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" - -[[package]] -name = "quinn" -version = "0.11.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3bd15a6f2967aef83887dcb9fec0014580467e33720d073560cf015a5683012" -dependencies = [ - "bytes", - "cfg_aliases", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash", - "rustls", - "socket2", - "thiserror 2.0.12", - "tokio", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-proto" -version = "0.11.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b820744eb4dc9b57a3398183639c511b5a26d2ed702cedd3febaa1393caa22cc" -dependencies = [ - "bytes", - "getrandom 0.3.2", - "rand 0.9.0", - "ring", - "rustc-hash", - "rustls", - "rustls-pki-types", - "slab", - "thiserror 2.0.12", - "tinyvec", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-udp" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "541d0f57c6ec747a90738a52741d3221f7960e8ac2f0ff4b1a63680e033b4ab5" -dependencies = [ - "cfg_aliases", - "libc", - "once_cell", - "socket2", - "tracing", - "windows-sys 0.59.0", -] - -[[package]] -name = "quote" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" - -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[package]] -name = "rancor" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf5f7161924b9d1cea0e4cabc97c372cea92b5f927fc13c6bca67157a0ad947" -dependencies = [ - "ptr_meta 0.3.0", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "rand_core 0.6.4", -] - -[[package]] -name = "rand" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" -dependencies = [ - "rand_chacha", - "rand_core 0.9.3", - "zerocopy 0.8.24", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core 0.9.3", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" - -[[package]] -name = "rand_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" -dependencies = [ - "getrandom 0.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" -dependencies = [ - "bitflags 2.9.0", -] - -[[package]] -name = "ref-cast" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" -dependencies = [ - "ref-cast-impl", -] - -[[package]] -name = "ref-cast-impl" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "regex" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - -[[package]] -name = "rend" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" -dependencies = [ - "bytecheck", -] - -[[package]] -name = "rend" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a35e8a6bf28cd121053a66aa2e6a2e3eaffad4a60012179f0e864aa5ffeff215" - -[[package]] -name = "reqwest" -version = "0.12.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" -dependencies = [ - "async-compression", - "base64", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-util", - "ipnet", - "js-sys", - "log", - "mime", - "once_cell", - "percent-encoding", - "pin-project-lite", - "quinn", - "rustls", - "rustls-pemfile", - "rustls-pki-types", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "system-configuration", - "tokio", - "tokio-rustls", - "tokio-socks", - "tokio-util", - "tower", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams", - "web-sys", - "webpki-roots", - "windows-registry", -] - -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.15", - "libc", - "untrusted", - "windows-sys 0.52.0", -] - -[[package]] -name = "rkyv" -version = "0.7.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" -dependencies = [ - "bitvec", - "bytecheck", - "bytes", - "hashbrown 0.12.3", - "ptr_meta 0.1.4", - "rend 0.4.2", - "rkyv_derive 0.7.45", - "seahash", - "tinyvec", - "uuid", -] - -[[package]] -name = "rkyv" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e147371c75553e1e2fcdb483944a8540b8438c31426279553b9a8182a9b7b65" -dependencies = [ - "bytes", - "hashbrown 0.15.2", - "indexmap", - "munge", - "ptr_meta 0.3.0", - "rancor", - "rend 0.5.2", - "rkyv_derive 0.8.10", - "tinyvec", - "uuid", -] - -[[package]] -name = "rkyv_derive" -version = "0.7.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "rkyv_derive" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "246b40ac189af6c675d124b802e8ef6d5246c53e17367ce9501f8f66a81abb7a" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - -[[package]] -name = "rustix" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e56a18552996ac8d29ecc3b190b4fdbb2d91ca4ec396de7bbffaf43f3d637e96" -dependencies = [ - "bitflags 2.9.0", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.59.0", -] - -[[package]] -name = "rustls" -version = "0.23.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c" -dependencies = [ - "once_cell", - "ring", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "rustls-pki-types" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" -dependencies = [ - "web-time", -] - -[[package]] -name = "rustls-webpki" -version = "0.103.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" - -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "seahash" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" - -[[package]] -name = "serde" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "serde_json" -version = "1.0.140" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "serde_path_to_error" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" -dependencies = [ - "itoa", - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "signal-hook-registry" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" -dependencies = [ - "libc", -] - -[[package]] -name = "simd-adler32" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" - -[[package]] -name = "simdutf8" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" - -[[package]] -name = "siphasher" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" - -[[package]] -name = "socket2" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "sonic-number" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a74044c092f4f43ca7a6cfd62854cf9fb5ac8502b131347c990bf22bef1dfe" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "sonic-rs" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0275f9f2f07d47556fe60c2759da8bc4be6083b047b491b2d476aa0bfa558eb1" -dependencies = [ - "bumpalo", - "bytes", - "cfg-if", - "faststr", - "itoa", - "ref-cast", - "ryu", - "serde", - "simdutf8", - "sonic-number", - "sonic-simd", - "thiserror 2.0.12", -] - -[[package]] -name = "sonic-simd" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b421f7b6aa4a5de8f685aaf398dfaa828346ee639d2b1c1061ab43d40baa6223" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" -dependencies = [ - "futures-core", -] - -[[package]] -name = "synstructure" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "sysinfo" -version = "0.33.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fc858248ea01b66f19d8e8a6d55f41deaf91e9d495246fd01368d99935c6c01" -dependencies = [ - "core-foundation-sys", - "libc", - "memchr", - "ntapi", - "windows", -] - -[[package]] -name = "system-configuration" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" -dependencies = [ - "bitflags 2.9.0", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "tempfile" -version = "3.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" -dependencies = [ - "fastrand", - "getrandom 0.3.2", - "once_cell", - "rustix", - "windows-sys 0.59.0", -] - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - -[[package]] -name = "thiserror" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" -dependencies = [ - "thiserror-impl 2.0.12", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "tinystr" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "tinyvec" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.44.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys 0.52.0", -] - -[[package]] -name = "tokio-macros" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "tokio-rustls" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tokio-socks" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4770b8024672c1101b3f6733eab95b18007dbe0847a8afe341fcf79e06043f" -dependencies = [ - "either", - "futures-util", - "thiserror 1.0.69", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tower" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" -dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper", - "tokio", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-http" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403fa3b783d4b626a8ad51d766ab03cb6d2dbfc46b1c5d4448395e6628dc9697" -dependencies = [ - "bitflags 2.9.0", - "bytes", - "http", - "http-body", - "http-body-util", - "pin-project-lite", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] -name = "tracing" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -dependencies = [ - "pin-project-lite", - "tracing-core", -] - -[[package]] -name = "tracing-core" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" -dependencies = [ - "once_cell", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "typenum" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" - -[[package]] -name = "unicode-ident" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "uuid" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" -dependencies = [ - "getrandom 0.3.2", -] - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" -dependencies = [ - "wit-bindgen-rt", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.100", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" -dependencies = [ - "cfg-if", - "js-sys", - "once_cell", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "wasm-streams" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" -dependencies = [ - "futures-util", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "web-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "web-time" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webpki-roots" -version = "0.26.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "weezl" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" -dependencies = [ - "windows-core 0.57.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-core" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" -dependencies = [ - "windows-implement 0.57.0", - "windows-interface 0.57.0", - "windows-result 0.1.2", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-core" -version = "0.61.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" -dependencies = [ - "windows-implement 0.60.0", - "windows-interface 0.59.1", - "windows-link", - "windows-result 0.3.2", - "windows-strings 0.4.0", -] - -[[package]] -name = "windows-implement" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "windows-implement" -version = "0.60.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "windows-interface" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "windows-interface" -version = "0.59.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "windows-link" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" - -[[package]] -name = "windows-registry" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" -dependencies = [ - "windows-result 0.3.2", - "windows-strings 0.3.1", - "windows-targets 0.53.0", -] - -[[package]] -name = "windows-result" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-result" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" -dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - -[[package]] -name = "wit-bindgen-rt" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags 2.9.0", -] - -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - -[[package]] -name = "writeable" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - -[[package]] -name = "yoke" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", - "synstructure", -] - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "zerocopy-derive 0.7.35", -] - -[[package]] -name = "zerocopy" -version = "0.8.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" -dependencies = [ - "zerocopy-derive 0.8.24", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", - "synstructure", -] - -[[package]] -name = "zeroize" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" - -[[package]] -name = "zerovec" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "zune-core" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" - -[[package]] -name = "zune-jpeg" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028" -dependencies = [ - "zune-core", -] diff --git a/Cargo.toml b/Cargo.toml index bcf2b9a..ee68214 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,8 @@ +cargo-features = ["profile-rustflags", "trim-paths"] + [package] name = "cursor-api" -version = "0.1.3-rc.5.2.3" +version = "0.1.3-rc.5.2.4" edition = "2024" authors = ["wisdgod "] description = "OpenAI format compatibility layer for the Cursor API" @@ -19,7 +21,7 @@ bytes = "^1.10" chrono = { version = "^0.4", default-features = false, features = ["std", "clock", "now", "serde", "rkyv-64"] } chrono-tz = { version = "^0.10", features = ["serde"] } dotenvy = "^0.15" -flate2 = { version = "^1.0", default-features = false, features = ["rust_backend"] } +flate2 = { version = "1", default-features = false, features = ["rust_backend"] } futures = { version = "^0.3", default-features = false, features = ["std"] } gif = { version = "^0.13", default-features = false, features = ["std"] } hex = { version = "^0.4", default-features = false, features = ["std"] } @@ -33,13 +35,13 @@ prost = "^0.13" prost-types = "^0.13" rand = { version = "^0.9", default-features = false, features = ["thread_rng"] } regex = { version = "^1.11", default-features = false, features = ["std", "perf"] } -reqwest = { version = "^0.12", default-features = false, features = ["gzip", "brotli", "json", "stream", "socks", "__tls", "charset", "rustls-tls-webpki-roots", "macos-system-configuration"] } +reqwest = { version = "^0.12", default-features = false, features = ["gzip", "brotli", "json", "stream", "socks", "__tls", "charset", "rustls-tls-native-roots", "macos-system-configuration"] } rkyv = { version = "^0.7", default-features = false, features = ["alloc", "std", "bytecheck", "size_64", "validation", "std"] } -serde = { version = "^1.0", default-features = false, features = ["std", "derive"] } -serde_json = { package = "sonic-rs", version = "^0.3" } +serde = { version = "^1.0", default-features = false, features = ["std", "derive", "rc"] } +serde_json = { package = "sonic-rs", version = "^0.4" } # serde_json = "^1.0" sha2 = { version = "^0.10", default-features = false } -sysinfo = { version = "^0.33", default-features = false, features = ["system"] } +sysinfo = { version = "^0.34", default-features = false, features = ["system"] } tokio = { version = "^1.43", features = ["rt-multi-thread", "macros", "net", "sync", "time", "fs", "signal"] } # tokio-stream = { version = "^0.1", features = ["time"] } tower-http = { version = "^0.6", features = ["cors", "limit"] } @@ -52,6 +54,8 @@ codegen-units = 1 panic = 'abort' strip = true opt-level = 3 +trim-paths = "all" +rustflags = ["-Cdebuginfo=0", "-Zthreads=8"] [features] default = [] diff --git a/Cursor API.md b/Cursor API.md index 5015110..69f0bac 100644 --- a/Cursor API.md +++ b/Cursor API.md @@ -112,9 +112,9 @@ token2,checksum2 | 端点 | 方法 | 功能 | |------|------|-----| | `/tokens` | GET | Token 信息管理界面 | -| `/tokens/update` | POST | 批量更新 Token 列表 | +| `/tokens/set` | POST | 批量更新 Token 列表 | | `/tokens/add` | POST | 增量添加 Token | -| `/tokens/delete` | POST | 删除指定 Token | +| `/tokens/del` | POST | 删除指定 Token | ```mermaid sequenceDiagram diff --git a/Dockerfile b/Dockerfile index 4b9673c..a1ad25a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ ARG TARGETARCH -FROM --platform=linux/${TARGETARCH} rust:1-slim-bookworm as builder +FROM --platform=linux/${TARGETARCH} rustlang/rust:nightly-bookworm-slim as builder ARG TARGETARCH @@ -10,7 +10,7 @@ RUN apt-get update && \ && rm -rf /var/lib/apt/lists/* COPY . . -RUN case "$TARGETARCH" in amd64) TARGET_CPU="x86-64-v2" ;; arm64) TARGET_CPU="neoverse-n1" ;; *) echo "Unsupported architecture: $TARGETARCH" && exit 1 ;; esac && RUSTFLAGS="-C link-arg=-s -C target-cpu=$TARGET_CPU" cargo build --release && cp target/release/cursor-api /app/cursor-api +RUN case "$TARGETARCH" in amd64) TARGET_CPU="x86-64-v2" ;; arm64) TARGET_CPU="neoverse-n1" ;; *) echo "Unsupported architecture: $TARGETARCH" && exit 1 ;; esac && RUSTFLAGS="-C link-arg=-s -C target-cpu=$TARGET_CPU" cargo +nightly build --release && cp target/release/cursor-api /app/cursor-api # 运行阶段 ARG TARGETARCH diff --git a/Dockerfile.cross b/Dockerfile.cross index ee34eb7..9ca5971 100644 --- a/Dockerfile.cross +++ b/Dockerfile.cross @@ -1,6 +1,6 @@ # Dockerfile.cross -FROM --platform=linux/amd64 rust:1-slim-bookworm +FROM --platform=linux/amd64 rustlang/rust:nightly-bookworm-slim WORKDIR /app diff --git a/README.md b/README.md index 998982f..837680c 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,7 @@ o1 claude-3.5-haiku gemini-2.0-pro-exp gemini-2.5-pro-exp-03-25 +gemini-2.5-pro-max gemini-2.0-flash-thinking-exp gemini-2.0-flash deepseek-v3 @@ -209,6 +210,7 @@ data: [DONE] { "token": "string", "checksum": "string", + "status": "enabled" | "disabled", "profile": { // 可能存在 "usage": { "premium": { @@ -246,16 +248,18 @@ data: [DONE] "days_remaining_on_trial": number } }, - "tags": ["string"] + "tags": { + "string": null | "string" + } } ], "tokens_count": number } ``` -#### 更新Token信息 +#### 设置Token信息 -* 接口地址: `/tokens/update` +* 接口地址: `/tokens/set` * 请求方法: POST * 认证方式: Bearer Token * 请求格式: @@ -265,6 +269,7 @@ data: [DONE] { "token": "string", "checksum": "string", + "status": "enabled" | "disabled", "profile": { "usage": { "premium": { @@ -302,7 +307,9 @@ data: [DONE] "days_remaining_on_trial": number } }, - "tags": ["string"] + "tags": { + "string": null | "string" + } } ] ``` @@ -332,7 +339,10 @@ data: [DONE] "checksum": "string" // 可选,如果不提供将自动生成 } ], - "tags": ["string"] + "tags": { + "string": null | "string" + }, + "status": "enabled" | "disabled" } ``` @@ -348,7 +358,7 @@ data: [DONE] #### 删除Token -* 接口地址: `/tokens/delete` +* 接口地址: `/tokens/del` * 请求方法: POST * 认证方式: Bearer Token * 请求格式: @@ -376,9 +386,9 @@ data: [DONE] - failed_tokens: 返回未找到的token列表 - detailed: 返回完整信息(包括updated_tokens和failed_tokens) -#### 更新Tokens标签 +#### 设置Tokens标签 -* 接口地址: `/tokens/tags/update` +* 接口地址: `/tokens/tags/set` * 请求方法: POST * 认证方式: Bearer Token * 请求格式: @@ -386,7 +396,9 @@ data: [DONE] ```json { "tokens": ["string"], - "tags": ["string"] // index 0: 时区标识符(独有); index 1: 代理名称 + "tags": { + "string": null | "string" // 键可以为 timezone: 时区标识符 或 proxy: 代理名称 + } } ``` @@ -421,6 +433,51 @@ data: [DONE] } ``` +#### 升级Tokens + +* 接口地址: `/tokens/upgrade` +* 请求方法: POST +* 认证方式: Bearer Token +* 请求格式: + +```json +[ + "string" // tokens +] +``` + +* 响应格式: + +```json +{ + "status": "success", + "message": "string" // "已升级?个令牌, ?个令牌升级失败" +} +``` + +#### 设置Tokens Status + +* 接口地址: `/tokens/status/set` +* 请求方法: POST +* 认证方式: Bearer Token +* 请求格式: + +```json +{ + "tokens": ["string"], + "status": "enabled" | "disabled" +} +``` + +* 响应格式: + +```json +{ + "status": "success", + "message": "string" // "已设置?个令牌状态, ?个令牌设置失败" +} +``` + #### 构建API Key * 接口地址: `/build-key` @@ -512,9 +569,9 @@ data: [DONE] } ``` -#### 更新代理配置 +#### 设置代理配置 -* 接口地址: `/proxies/update` +* 接口地址: `/proxies/set` * 请求方法: POST * 请求格式: @@ -565,7 +622,7 @@ data: [DONE] #### 删除代理 -* 接口地址: `/proxies/delete` +* 接口地址: `/proxies/del` * 请求方法: POST * 请求格式: @@ -997,6 +1054,29 @@ string } ``` +#### 获取更新令牌 + +* 接口地址: `/token-upgrade` +* 请求方法: POST +* 认证方式: 请求体中包含token +* 请求格式: + +```json +{ + "token": "string" +} +``` + +* 响应格式: + +```json +{ + "status": "success" | "failure" | "error", + "message": "string", + "result": "string" // optional +} +``` + #### 基础校准 * 接口地址: `/basic-calibration` diff --git a/build.rs b/build.rs index 98cd79e..04c7a39 100644 --- a/build.rs +++ b/build.rs @@ -13,6 +13,7 @@ use std::io::Result; use std::io::{Read, Write}; #[cfg(not(any(feature = "use-minified")))] use std::path::Path; +#[cfg(not(any(feature = "use-minified")))] use std::path::PathBuf; #[cfg(not(any(feature = "use-minified")))] use std::process::Command; @@ -153,7 +154,7 @@ fn minify_assets() -> Result<()> { } println!("cargo:warning=Minifying {} files...", files_to_update.len()); - println!("cargo:warning={}", files_to_update.join("\n")); + println!("cargo:warning={}", files_to_update.join(" ")); // 运行压缩脚本 let status = Command::new("node") @@ -231,21 +232,21 @@ fn main() -> Result<()> { // Proto 文件处理 // println!("cargo:rerun-if-changed=src/core/aiserver/v1/lite.proto"); - println!("cargo:rerun-if-changed=src/core/config/key.proto"); + // println!("cargo:rerun-if-changed=src/core/config/key.proto"); // 获取环境变量 PROTOC - let protoc_path = match std::env::var_os("PROTOC") { - Some(path) => PathBuf::from(path), - None => { - println!("cargo:warning=PROTOC environment variable not set, using default protoc."); - // 如果 PROTOC 未设置,则返回一个空的 PathBuf,prost-build 会尝试使用默认的 protoc - PathBuf::new() - } - }; - let mut config = prost_build::Config::new(); - // 如果 protoc_path 不为空,则配置使用指定的 protoc - if !protoc_path.as_os_str().is_empty() { - config.protoc_executable(protoc_path); - } + // let protoc_path = match std::env::var_os("PROTOC") { + // Some(path) => PathBuf::from(path), + // None => { + // println!("cargo:warning=PROTOC environment variable not set, using default protoc."); + // // 如果 PROTOC 未设置,则返回一个空的 PathBuf,prost-build 会尝试使用默认的 protoc + // PathBuf::new() + // } + // }; + // let mut config = prost_build::Config::new(); + // // 如果 protoc_path 不为空,则配置使用指定的 protoc + // if !protoc_path.as_os_str().is_empty() { + // config.protoc_executable(protoc_path); + // } // config.type_attribute(".", "#[derive(serde::Serialize, serde::Deserialize)]"); // config.enum_attribute(".aiserver.v1", "#[allow(clippy::enum_variant_names)]"); // config @@ -254,9 +255,9 @@ fn main() -> Result<()> { // &["src/core/aiserver/v1/"], // ) // .unwrap(); - config - .compile_protos(&["src/core/config/key.proto"], &["src/core/config/"]) - .unwrap(); + // config + // .compile_protos(&["src/core/config/key.proto"], &["src/core/config/"]) + // .unwrap(); // 静态资源文件处理 println!("cargo:rerun-if-changed=scripts/minify.js"); diff --git a/src/app/config.rs b/src/app/config.rs index 5343af4..d426879 100644 --- a/src/app/config.rs +++ b/src/app/config.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use super::{constant::AUTHORIZATION_BEARER_PREFIX, lazy::AUTH_TOKEN, model::AppConfig}; use crate::common::model::{ ApiStatus, ErrorResponse, NormalResponse, @@ -43,7 +45,7 @@ pub async fn handle_config_update( Json(ErrorResponse { status: ApiStatus::Failure, code: Some(401), - error: Some("未提供认证令牌".to_string()), + error: Some(Cow::Borrowed("未提供认证令牌")), message: None, }), ))?; @@ -54,7 +56,7 @@ pub async fn handle_config_update( Json(ErrorResponse { status: ApiStatus::Failure, code: Some(401), - error: Some("无效的认证令牌".to_string()), + error: Some(Cow::Borrowed("无效的认证令牌")), message: None, }), )); @@ -86,7 +88,7 @@ pub async fn handle_config_update( Json(ErrorResponse { status: ApiStatus::Failure, code: Some(500), - error: Some(format!("更新页面内容失败: {e}")), + error: Some(Cow::Owned(format!("更新页面内容失败: {e}"))), message: None, }), )); @@ -107,7 +109,7 @@ pub async fn handle_config_update( Ok(Json(NormalResponse { status: ApiStatus::Success, data: None, - message: Some("配置已更新".to_string()), + message: Some(Cow::Borrowed("配置已更新")), })) } @@ -120,7 +122,7 @@ pub async fn handle_config_update( Json(ErrorResponse { status: ApiStatus::Failure, code: Some(500), - error: Some(format!("重置页面内容失败: {e}")), + error: Some(Cow::Owned(format!("重置页面内容失败: {e}"))), message: None, }), )); @@ -140,7 +142,7 @@ pub async fn handle_config_update( Ok(Json(NormalResponse { status: ApiStatus::Success, data: None, - message: Some("配置已重置".to_string()), + message: Some(Cow::Borrowed("配置已重置")), })) } @@ -149,7 +151,7 @@ pub async fn handle_config_update( Json(ErrorResponse { status: ApiStatus::Failure, code: Some(400), - error: Some("无效的操作类型".to_string()), + error: Some(Cow::Borrowed("无效的操作类型")), message: None, }), )), diff --git a/src/app/constant.rs b/src/app/constant.rs index 0156794..f3d87d1 100644 --- a/src/app/constant.rs +++ b/src/app/constant.rs @@ -43,18 +43,20 @@ def_pub_const!( ROUTE_CONFIG_PATH => "/config", ROUTE_TOKENS_PATH => "/tokens", ROUTE_TOKENS_GET_PATH => "/tokens/get", - ROUTE_TOKENS_UPDATE_PATH => "/tokens/update", + ROUTE_TOKENS_SET_PATH => "/tokens/set", ROUTE_TOKENS_ADD_PATH => "/tokens/add", - ROUTE_TOKENS_DELETE_PATH => "/tokens/delete", + ROUTE_TOKENS_DELETE_PATH => "/tokens/del", ROUTE_TOKENS_TAGS_GET_PATH => "/tokens/tags/get", - ROUTE_TOKENS_TAGS_UPDATE_PATH => "/tokens/tags/update", + ROUTE_TOKENS_TAGS_SET_PATH => "/tokens/tags/set", ROUTE_TOKENS_BY_TAG_GET_PATH => "/tokens/by-tag/get", ROUTE_TOKENS_PROFILE_UPDATE_PATH => "/tokens/profile/update", + ROUTE_TOKENS_UPGRADE_PATH => "/tokens/upgrade", + ROUTE_TOKENS_STATUS_SET_PATH => "/tokens/status/set", ROUTE_PROXIES_PATH => "/proxies", ROUTE_PROXIES_GET_PATH => "/proxies/get", - ROUTE_PROXIES_UPDATE_PATH => "/proxies/update", + ROUTE_PROXIES_SET_PATH => "/proxies/set", ROUTE_PROXIES_ADD_PATH => "/proxies/add", - ROUTE_PROXIES_DELETE_PATH => "/proxies/delete", + ROUTE_PROXIES_DELETE_PATH => "/proxies/del", ROUTE_PROXIES_SET_GENERAL_PATH => "/proxies/set-general", ROUTE_ENV_EXAMPLE_PATH => "/env-example", ROUTE_STATIC_PATH => "/static/{path}", @@ -63,7 +65,8 @@ def_pub_const!( ROUTE_ABOUT_PATH => "/about", ROUTE_README_PATH => "/readme", ROUTE_BASIC_CALIBRATION_PATH => "/basic-calibration", - ROUTE_BUILD_KEY_PATH => "/build-key" + ROUTE_BUILD_KEY_PATH => "/build-key", + ROUTE_TOKEN_UPGRADE_PATH => "/token-upgrade" ); // def_pub_const!(DEFAULT_TOKEN_LIST_FILE_NAME => ".tokens"); diff --git a/src/app/lazy.rs b/src/app/lazy.rs index 5110690..ed7720b 100644 --- a/src/app/lazy.rs +++ b/src/app/lazy.rs @@ -48,6 +48,7 @@ def_pub_static!( format!("{}/v1/chat/completions", *ROUTE_PREFIX), _ ); +def_pub_static!(ROUTE_MESSAGES_PATH, format!("{}/v1/messages", *ROUTE_PREFIX), _); static START_TIME: OnceLock> = OnceLock::new(); @@ -84,7 +85,11 @@ def_pub_static!(DEFAULT_INSTRUCTIONS, env: "DEFAULT_INSTRUCTIONS", default: "Res const USE_OFFICIAL_CLAUDE_PROMPTS: LazyLock = LazyLock::new(|| parse_bool_from_env("USE_OFFICIAL_CLAUDE_PROMPTS", false)); -pub fn get_default_instructions(model: &str, image_support: bool) -> String { +pub fn get_default_instructions( + now_with_tz: Option>, + model: &str, + image_support: bool, +) -> String { let mut instructions = ""; if *USE_OFFICIAL_CLAUDE_PROMPTS { if let Some(rest) = model.strip_prefix("claude-3") { @@ -111,7 +116,12 @@ pub fn get_default_instructions(model: &str, image_support: bool) -> String { } instructions.replace( "{{currentDateTime}}", - &now_in_general_timezone().to_rfc3339_opts(chrono::SecondsFormat::Millis, true), + &if let Some(now) = now_with_tz { + now + } else { + now_in_general_timezone() + } + .to_rfc3339_opts(chrono::SecondsFormat::Millis, true), ) } @@ -226,6 +236,14 @@ def_cursor_api_url!(cursor_usage_api_url, CURSOR_HOST, "/api/usage"); def_cursor_api_url!(cursor_user_api_url, CURSOR_HOST, "/api/auth/me"); +def_cursor_api_url!( + cursor_token_upgrade_url, + CURSOR_HOST, + "/api/auth/loginDeepCallbackControl" +); + +def_cursor_api_url!(cursor_token_poll_url, CURSOR_API2_HOST, "/auth/poll"); + static DATA_DIR: LazyLock = LazyLock::new(|| { let data_dir = parse_string_from_env("DATA_DIR", "data"); let path = std::env::current_exe() diff --git a/src/app/model.rs b/src/app/model.rs index 6858fc9..3eef694 100644 --- a/src/app/model.rs +++ b/src/app/model.rs @@ -1,4 +1,4 @@ -use std::sync::LazyLock; +use std::{collections::HashMap, sync::LazyLock}; use crate::{ common::{ @@ -277,12 +277,30 @@ impl ErrorInfo { pub struct TokenInfo { pub token: String, pub checksum: String, + #[serde(default)] + pub status: TokenStatus, #[serde(skip_serializing, default = "generate_client_key")] pub client_key: Option, #[serde(skip_serializing_if = "Option::is_none")] pub profile: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub tags: Option>, + pub tags: Option>>, +} + +#[derive(Default, Clone, Copy, Serialize, Deserialize, Archive, RkyvSerialize, RkyvDeserialize)] +#[serde(rename_all = "lowercase")] +#[repr(u8)] +pub enum TokenStatus { + #[default] + Enabled, + Disabled, +} + +impl TokenInfo { + #[inline(always)] + pub fn is_enabled(&self) -> bool { + matches!(self.status, TokenStatus::Enabled) + } } #[inline(always)] @@ -293,56 +311,50 @@ fn generate_client_key() -> Option { impl TokenInfo { /// 获取适用于此 token 的 HTTP 客户端 /// - /// 如果 tags 中包含 "proxy" 标签,会尝试使用其后一个标签作为代理 URL - /// 例如: tags = ["proxy", "http://localhost:8080"] 将使用 http://localhost:8080 作为代理 + /// 如果 tags 中包含 "proxy" 键值对对象,会使用其值作为代理 URL + /// 例如: tags = ["a", {"proxy": "http://localhost:8080"}, "d"] 将使用 http://localhost:8080 作为代理 /// /// 如果没有找到有效的代理配置,将返回默认客户端 pub fn get_client(&self) -> Client { - // if let Some(tags) = &self.tags { - // // 查找 "proxy" 标签的位置 - // if let Some(proxy_index) = tags.iter().position(|tag| tag == "proxy") { - // // 检查是否存在下一个标签作为代理 URL - // if proxy_index + 1 < tags.len() { - // // 获取代理 URL 并尝试创建对应的客户端 - // return ProxyPool::get_client(&tags[proxy_index + 1]); - // } - // } - // } - // // 如果没有找到有效的代理配置,返回默认客户端 - // ProxyPool::get_general_client() if let Some(tags) = &self.tags { - ProxyPool::get_client_or_general(tags.get(1).map(|s| s.as_str())) + ProxyPool::get_client_or_general( + tags.get("proxy") + .and_then(|v| v.as_ref().map(String::as_str)), + ) } else { ProxyPool::get_general_client() } } - pub fn timezone_name(&self) -> &'static str { + /// 获取此 token 关联的时区 + /// + /// 如果 tags 中包含 "timezone" 键值对对象,会尝试使用其值作为时区标识 + /// 例如: tags = ["a", {"timezone": "Asia/Shanghai"}, "d"] 将使用上海时区 + /// 如果无法解析时区或未设置,将返回系统默认时区 + #[inline] + fn get_timezone(&self) -> chrono_tz::Tz { use std::str::FromStr as _; - if let Some(Some(Ok(tz))) = self.tags.as_ref().map(|tags| { - tags.first() - .filter(|s| !s.is_empty()) - .map(|s| chrono_tz::Tz::from_str(s.as_str())) - }) { - tz.name() - } else { - super::lazy::GENERAL_TIMEZONE.name() + if let Some(tags) = self.tags.as_ref() { + if let Some(Some(tz_str)) = tags.get("timezone") { + if let Ok(tz) = chrono_tz::Tz::from_str(tz_str) { + return tz; + } + } } + *super::lazy::GENERAL_TIMEZONE } - // pub fn now(&self) -> chrono::DateTime { - // use std::str::FromStr as _; - // if let Some(Some(Ok(tz))) = self.tags.as_ref().map(|tags| { - // tags.get(0) - // .filter(|s| !s.is_empty()) - // .map(|s| chrono_tz::Tz::from_str(s.as_str())) - // }) { - // use chrono::TimeZone as _; - // tz.from_utc_datetime(&chrono::Utc::now().naive_utc()) - // } else { - // super::lazy::now_in_general_timezone() - // } - // } + /// 返回关联的时区名称 + pub fn timezone_name(&self) -> &'static str { + self.get_timezone().name() + } + + /// 获取当前时区的当前时间 + pub fn now(&self) -> chrono::DateTime { + use chrono::TimeZone as _; + self.get_timezone() + .from_utc_datetime(&chrono::Utc::now().naive_utc()) + } } // TokenUpdateRequest 结构体 @@ -352,7 +364,9 @@ pub type TokenUpdateRequest = Vec; pub struct TokenAddRequest { pub tokens: Vec, #[serde(default)] - pub tags: Option>, + pub tags: Option>>, + #[serde(default)] + pub status: TokenStatus, } #[derive(Deserialize)] @@ -421,7 +435,7 @@ pub struct TokenInfoResponse { #[derive(Deserialize)] pub struct TokenTagsUpdateRequest { pub tokens: Vec, - pub tags: Vec, + pub tags: Option>>, } #[derive(Serialize)] @@ -430,12 +444,8 @@ pub struct CommonResponse { pub message: Option, } -// impl CommonResponse { -// pub fn into_normal_response(self) -> NormalResponse<()> { -// NormalResponse { -// status: self.status, -// data: None, -// message: self.message, -// } -// } -// } +#[derive(Deserialize)] +pub struct TokenStatusSetRequest { + pub tokens: Vec, + pub status: TokenStatus, +} diff --git a/src/app/model/build_key.rs b/src/app/model/build_key.rs index 883b9bf..07f22b0 100644 --- a/src/app/model/build_key.rs +++ b/src/app/model/build_key.rs @@ -70,5 +70,5 @@ pub enum UsageCheckModelType { #[serde(rename_all = "lowercase")] pub enum BuildKeyResponse { Key(String), - Error(String), + Error(&'static str), } diff --git a/src/app/model/config.rs b/src/app/model/config.rs index 11cf928..09c49d9 100644 --- a/src/app/model/config.rs +++ b/src/app/model/config.rs @@ -127,10 +127,10 @@ impl AppConfig { long_context: bool, false; dynamic_key: bool, false; web_refs: bool, false; + vision_ability: VisionAbility, VisionAbility::default(); } config_methods_clone! { - vision_ability: VisionAbility, VisionAbility::default(); usage_check: UsageCheck, UsageCheck::default(); } @@ -138,9 +138,12 @@ impl AppConfig { APP_CONFIG.read().share_token.clone() } + pub fn share_token_eq(s: &str) -> bool { + APP_CONFIG.read().share_token == s + } + pub fn update_share_token(value: String) { - let current = Self::get_share_token(); - if current != value { + if Self::share_token_eq(&value) { let mut config = APP_CONFIG.write(); config.share_token = value; config.is_share = !config.share_token.is_empty(); @@ -148,8 +151,7 @@ impl AppConfig { } pub fn reset_share_token() { - let current = Self::get_share_token(); - if !current.is_empty() { + if !APP_CONFIG.read().share_token.is_empty() { let mut config = APP_CONFIG.write(); config.share_token = String::new(); config.is_share = false; diff --git a/src/app/model/proxy_pool.rs b/src/app/model/proxy_pool.rs index 4ec4efe..aefcc01 100644 --- a/src/app/model/proxy_pool.rs +++ b/src/app/model/proxy_pool.rs @@ -164,17 +164,16 @@ impl Proxies { } // 5. 设置通用客户端 - if let Some(proxy) = self.proxies.get(&self.general) { - if let Some(client) = pool.clients.get(proxy) { - pool.general = Some(client.clone()); - } else { - // 这不应该发生 - unreachable!() - } - } else { - // 这不应该发生 - unreachable!() - } + pool.general = Some( + pool.clients + .get( + self.proxies + .get(&self.general) + .expect("General proxy not found in proxy list"), + ) + .expect("Client for general proxy not found in client pool") + .clone(), + ); Ok(()) } diff --git a/src/app/model/state.rs b/src/app/model/state.rs index 4b9259d..ad759d2 100644 --- a/src/app/model/state.rs +++ b/src/app/model/state.rs @@ -2,7 +2,10 @@ use crate::common::utils::{generate_checksum_with_repair, generate_hash}; use memmap2::{MmapMut, MmapOptions}; use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize}; use serde::{Deserialize, Serialize}; -use std::{collections::HashSet, fs::OpenOptions}; +use std::{ + collections::{HashMap, HashSet}, + fs::OpenOptions, +}; use super::{ super::lazy::{LOGS_FILE_PATH, TOKENS_FILE_PATH}, @@ -70,7 +73,7 @@ impl TokenManager { let mut tags = HashSet::new(); for token in &tokens { if let Some(token_tags) = &token.tags { - tags.extend(token_tags.iter().cloned()); + tags.extend(token_tags.keys().cloned()); } } @@ -78,16 +81,16 @@ impl TokenManager { } #[inline(always)] - pub fn update_global_tags(&mut self, new_tags: &[String]) { + pub fn update_global_tags(&mut self, new_tags: &HashMap>) { // 将新标签添加到全局标签集合中 - self.tags.extend(new_tags.iter().cloned()); + self.tags.extend(new_tags.keys().cloned()); } #[inline(always)] pub fn update_tokens_tags( &mut self, - tokens: Vec, - new_tags: Vec, + tokens: &[String], + new_tags: Option>>, ) -> Result<(), &'static str> { // 创建tokens的HashSet用于快速查找 let tokens_set: HashSet<_> = tokens.iter().collect(); @@ -95,7 +98,7 @@ impl TokenManager { // 更新指定tokens的标签 for token_info in &mut self.tokens { if tokens_set.contains(&token_info.token) { - token_info.tags = Some(new_tags.clone()); + token_info.tags = new_tags.clone(); } } @@ -103,8 +106,8 @@ impl TokenManager { self.tags = self .tokens .iter() - .filter_map(|t| t.tags.clone()) - .flatten() + .filter_map(|t| t.tags.as_ref()) + .flat_map(|tags| tags.keys().cloned()) .collect(); Ok(()) @@ -122,7 +125,7 @@ impl TokenManager { .filter(|t| { t.tags .as_ref() - .is_some_and(|tags| tags.iter().any(|t| t == tag)) + .is_some_and(|tags| tags.keys().any(|t| t == tag)) }) .collect()) } diff --git a/src/common/client.rs b/src/common/client.rs index d8d099a..ad4dc97 100644 --- a/src/common/client.rs +++ b/src/common/client.rs @@ -5,14 +5,16 @@ use crate::app::{ }, lazy::{ PRI_REVERSE_PROXY_HOST, PUB_REVERSE_PROXY_HOST, USE_PRI_REVERSE_PROXY, - USE_PUB_REVERSE_PROXY, cursor_api2_stripe_url, cursor_usage_api_url, cursor_user_api_url, + USE_PUB_REVERSE_PROXY, cursor_api2_stripe_url, cursor_token_poll_url, + cursor_token_upgrade_url, cursor_usage_api_url, cursor_user_api_url, }, }; use reqwest::{ Client, RequestBuilder, header::{ - ACCEPT, ACCEPT_ENCODING, ACCEPT_LANGUAGE, CACHE_CONTROL, CONNECTION, CONTENT_TYPE, COOKIE, - DNT, HOST, ORIGIN, PRAGMA, REFERER, TE, USER_AGENT, + ACCEPT, ACCEPT_ENCODING, ACCEPT_LANGUAGE, CACHE_CONTROL, CONNECTION, CONTENT_LENGTH, + CONTENT_TYPE, COOKIE, DNT, HOST, ORIGIN, PRAGMA, REFERER, TE, TRANSFER_ENCODING, + USER_AGENT, }, }; @@ -43,9 +45,32 @@ def_const!(SAME_ORIGIN, "same-origin"); def_const!(KEEP_ALIVE, "keep-alive"); def_const!(TRAILERS, "trailers"); def_const!(U_EQ_4, "u=4"); +def_const!(U_EQ_0, "u=0"); def_const!(PROXY_HOST, "x-co"); +#[inline] +fn get_client_and_host_post<'a>( + client: &Client, + url: &'a str, + is_pri: bool, + real_host: &'a str, +) -> (RequestBuilder, &'a str) { + if is_pri && *USE_PRI_REVERSE_PROXY { + ( + client.post(url).header(PROXY_HOST, real_host), + PRI_REVERSE_PROXY_HOST.as_str(), + ) + } else if !is_pri && *USE_PUB_REVERSE_PROXY { + ( + client.post(url).header(PROXY_HOST, real_host), + PUB_REVERSE_PROXY_HOST.as_str(), + ) + } else { + (client.post(url), real_host) + } +} + pub(crate) struct AiServiceRequest<'a> { pub(crate) client: Client, pub(crate) auth_token: &'a str, @@ -70,28 +95,8 @@ pub(crate) struct AiServiceRequest<'a> { /// /// * `reqwest::RequestBuilder` - 配置好的请求构建器 pub fn build_request(req: AiServiceRequest) -> RequestBuilder { - #[inline] - fn get_client_and_host<'a>( - client: &Client, - url: &'a str, - is_pri: bool, - real_host: &'a str, - ) -> (RequestBuilder, &'a str) { - if is_pri && *USE_PRI_REVERSE_PROXY { - ( - client.post(url).header(PROXY_HOST, real_host), - PRI_REVERSE_PROXY_HOST.as_str(), - ) - } else if !is_pri && *USE_PUB_REVERSE_PROXY { - ( - client.post(url).header(PROXY_HOST, real_host), - PUB_REVERSE_PROXY_HOST.as_str(), - ) - } else { - (client.post(url), real_host) - } - } - let (client, host) = get_client_and_host(&req.client, req.url, req.is_pri, CURSOR_API2_HOST); + let (client, host) = + get_client_and_host_post(&req.client, req.url, req.is_pri, CURSOR_API2_HOST); client .header( @@ -114,8 +119,8 @@ pub fn build_request(req: AiServiceRequest) -> RequestBuilder { .header(HEADER_NAME_GHOST_MODE, TRUE) .header("x-request-id", req.trace_id) .header(HOST, host) - .header("Connection", KEEP_ALIVE) - .header("Transfer-Encoding", "chunked") + .header(CONNECTION, KEEP_ALIVE) + .header(TRANSFER_ENCODING, "chunked") } #[inline] @@ -194,8 +199,6 @@ pub fn build_usage_request( auth_token: &str, is_pri: bool, ) -> RequestBuilder { - let session_token = format!("{}%3A%3A{}", user_id, auth_token); - let (client, host) = get_client_and_host(client, cursor_usage_api_url(is_pri), is_pri, CURSOR_HOST); @@ -218,7 +221,7 @@ pub fn build_usage_request( .header(PRIORITY, U_EQ_4) .header( COOKIE, - &format!("WorkosCursorSessionToken={}", session_token), + format!("WorkosCursorSessionToken={user_id}%3A%3A{auth_token}"), ) .query(&[("user", user_id)]) } @@ -239,8 +242,6 @@ pub fn build_userinfo_request( auth_token: &str, is_pri: bool, ) -> RequestBuilder { - let session_token = format!("{}%3A%3A{}", user_id, auth_token); - let (client, host) = get_client_and_host(client, cursor_user_api_url(is_pri), is_pri, CURSOR_HOST); @@ -263,7 +264,77 @@ pub fn build_userinfo_request( .header(PRIORITY, U_EQ_4) .header( COOKIE, - &format!("WorkosCursorSessionToken={}", session_token), + format!("WorkosCursorSessionToken={user_id}%3A%3A{auth_token}"), ) - .query(&[("user", user_id)]) +} + +pub fn build_token_upgrade_request( + client: &Client, + uuid: &str, + challenge: &str, + user_id: &str, + auth_token: &str, + is_pri: bool, +) -> RequestBuilder { + let (client, host) = get_client_and_host_post( + client, + cursor_token_upgrade_url(is_pri), + is_pri, + CURSOR_HOST, + ); + + let body = format!("{{\"uuid\":\"{uuid}\",\"challenge\":\"{challenge}\"}}"); + + client + .header(HOST, host) + .header(USER_AGENT, UA_WIN) + .header(ACCEPT, VALUE_ACCEPT) + .header(ACCEPT_LANGUAGE, VALUE_LANGUAGE) + .header(ACCEPT_ENCODING, ENCODINGS) + .header( + REFERER, + format!( + "https://cursor.com/loginDeepControl?challenge={challenge}&uuid={uuid}&mode=login" + ), + ) + .header(CONTENT_TYPE, "application/json") + .header(CONTENT_LENGTH, body.len()) + .header(DNT, ONE) + .header(SEC_GPC, ONE) + .header(SEC_FETCH_DEST, EMPTY) + .header(SEC_FETCH_MODE, CORS) + .header(SEC_FETCH_SITE, SAME_ORIGIN) + .header(CONNECTION, KEEP_ALIVE) + .header(PRAGMA, NO_CACHE) + .header(CACHE_CONTROL, NO_CACHE) + .header(TE, TRAILERS) + .header(PRIORITY, U_EQ_0) + .header( + COOKIE, + format!("WorkosCursorSessionToken={user_id}%3A%3A{auth_token}"), + ) + .body(body) +} + +pub fn build_token_poll_request( + client: &Client, + uuid: &str, + verifier: &str, + is_pri: bool, +) -> RequestBuilder { + let (client, host) = get_client_and_host( + client, + cursor_token_poll_url(is_pri), + is_pri, + CURSOR_API2_HOST, + ); + client + .header(HOST, host) + .header(ACCEPT_ENCODING, "gzip, deflate") + .header(ACCEPT_LANGUAGE, "en-US") + .header(USER_AGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Cursor/0.48.2 Chrome/132.0.6834.210 Electron/34.3.4 Safari/537.36") + .header(ORIGIN, "vscode-file://vscode-app") + .header(HEADER_NAME_GHOST_MODE, TRUE) + .header(ACCEPT, "*/*") + .query(&[("uuid", uuid), ("verifier", verifier)]) } diff --git a/src/common/model.rs b/src/common/model.rs index 039e21d..35420d3 100644 --- a/src/common/model.rs +++ b/src/common/model.rs @@ -5,19 +5,18 @@ pub mod token; pub mod tri; pub mod userinfo; +use std::borrow::Cow; + use config::ConfigData; use serde::Serialize; #[derive(Serialize)] +#[serde(rename_all = "lowercase")] pub enum ApiStatus { - #[serde(rename = "healthy")] Healthy, - #[serde(rename = "success")] Success, - #[serde(rename = "error")] Error, - #[serde(rename = "failure")] Failure, } @@ -41,7 +40,7 @@ pub struct NormalResponse { #[serde(skip_serializing_if = "Option::is_none")] pub data: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub message: Option, + pub message: Option>, } impl std::fmt::Display for NormalResponse { @@ -66,8 +65,8 @@ pub struct ErrorResponse { pub code: Option, // HTTP 请求的错误码 #[serde(skip_serializing_if = "Option::is_none")] - pub error: Option, + pub error: Option>, // 错误详情 #[serde(skip_serializing_if = "Option::is_none")] - pub message: Option, + pub message: Option>, } diff --git a/src/common/model/error.rs b/src/common/model/error.rs index c8b232b..56be747 100644 --- a/src/common/model/error.rs +++ b/src/common/model/error.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use super::ErrorResponse; pub enum ChatError { @@ -27,8 +29,8 @@ impl ChatError { ErrorResponse { status: super::ApiStatus::Error, code: None, - error: Some(error.to_string()), - message: Some(message), + error: Some(Cow::Borrowed(error)), + message: Some(Cow::Owned(message)), } } } diff --git a/src/common/model/health.rs b/src/common/model/health.rs index f74fe09..57dd8dd 100644 --- a/src/common/model/health.rs +++ b/src/common/model/health.rs @@ -10,7 +10,7 @@ pub struct HealthCheckResponse { #[serde(skip_serializing_if = "Option::is_none")] pub stats: Option, pub models: Vec<&'static str>, - pub endpoints: Vec<&'static str>, + pub endpoints: &'static [&'static str], } #[derive(Serialize)] diff --git a/src/common/utils.rs b/src/common/utils.rs index 42bab16..c74cc1d 100644 --- a/src/common/utils.rs +++ b/src/common/utils.rs @@ -31,6 +31,7 @@ use crate::{ config::key_config, constant::{ ANTHROPIC, CREATED, CURSOR, DEEPSEEK, GOOGLE, MODEL_OBJECT, OPENAI, UNKNOWN, XAI, + calculate_display_name_v3, }, model::{Model, Usage}, }, @@ -72,6 +73,13 @@ pub fn parse_usize_from_env(key: &str, default: usize) -> usize { .unwrap_or(default) } +pub fn now_secs() -> u64 { + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .expect("system time before Unix epoch") + .as_secs() +} + pub trait TrimNewlines { fn trim_leading_newlines(self) -> Self; } @@ -231,7 +239,7 @@ pub async fn get_available_models( Some('g') => match chars.next() { Some('p') => OPENAI, // g + p → "gp" (gpt) Some('e') => GOOGLE, // g + e → "ge" (gemini) - Some('r') => XAI, // g + r → "ge" (grok) + Some('r') => XAI, // g + r → "gr" (grok) _ => UNKNOWN, }, Some('o') => match chars.next() { @@ -252,9 +260,11 @@ pub async fn get_available_models( _ => UNKNOWN, } }; + let display_name = calculate_display_name_v3(&model.name); Model { id: crate::leak::intern_string(model.name), + display_name: crate::leak::intern_string(display_name), created: CREATED, object: MODEL_OBJECT, owned_by, @@ -425,7 +435,11 @@ pub fn token_to_tokeninfo( // 构建 TokenInfo Some(key_config::TokenInfo { sub: payload.sub, - exp: payload.exp, + start: match payload.time.parse::() { + Ok(n) => n, + Err(_) => return None, + }, + end: payload.exp, randomness: payload.randomness, signature: parts[2].to_string(), machine_id: machine_id_hash, @@ -439,9 +453,9 @@ pub fn tokeninfo_to_token(mut info: key_config::TokenInfo) -> Option<(String, St // 构建 payload let payload = TokenPayload { sub: std::mem::take(&mut info.sub), - exp: info.exp, + exp: info.end, randomness: std::mem::take(&mut info.randomness), - time: (info.exp - 2592000000).to_string(), // exp - 30000天 + time: info.start.to_string(), // exp - 30000天 iss: ISSUER.to_string(), scope: SCOPE.to_string(), aud: AUDIENCE.to_string(), @@ -466,7 +480,7 @@ pub fn tokeninfo_to_token(mut info: key_config::TokenInfo) -> Option<(String, St // 组合 token Some(( - format!("{}.{}.{}", HEADER_B64, payload_b64, info.signature), + format!("{HEADER_B64}.{payload_b64}.{}", info.signature), generate_checksum(&device_id, mac_addr.as_deref()), client, )) @@ -497,3 +511,74 @@ pub fn encode_message( Ok(result) } + +/// 生成 PKCE code_verifier 和对应的 code_challenge (S256 method). +/// 返回一个包含 (verifier, challenge) 的元组。 +fn generate_pkce_pair() -> (String, String) { + use rand::TryRngCore as _; + use sha2::Digest as _; + + // 1. 生成 code_verifier 的原始随机字节 (32 bytes is recommended) + let mut verifier_bytes = [0u8; 32]; + + // 使用 OsRng 填充字节。如果失败(极其罕见),则直接 panic + rand::rngs::OsRng + .try_fill_bytes(&mut verifier_bytes) + .expect("获取系统安全随机数失败,这是一个严重错误!"); + + // 2. 将随机字节编码为 URL 安全 Base64 字符串,这就是 code_verifier + let code_verifier = URL_SAFE_NO_PAD.encode(verifier_bytes); + + // 3. 计算 code_verifier 字符串的 SHA-256 哈希值 + let hash_result = sha2::Sha256::digest(code_verifier.as_bytes()); + + // 4. 将哈希结果编码为 URL 安全 Base64 字符串,这就是 code_challenge + let code_challenge = URL_SAFE_NO_PAD.encode(hash_result); + + // 5. 同时返回 verifier 和 challenge + (code_verifier, code_challenge) +} + +pub async fn get_new_token(client: Client, auth_token: &str, is_pri: bool) -> Option { + #[derive(serde::Deserialize)] + #[serde(rename_all = "camelCase")] + pub struct PollResponse { + pub access_token: String, + // pub refresh_token: String, + // pub challenge: String, + // pub auth_id: String, + // pub uuid: String, + } + + let (verifier, challenge) = generate_pkce_pair(); + let user_id = extract_user_id(auth_token)?; + let uuid = uuid::Uuid::new_v4().to_string(); + + let request = super::client::build_token_upgrade_request( + &client, &uuid, &challenge, &user_id, auth_token, is_pri, + ); + + let response = request.send().await.ok()?; + if response.status() != reqwest::StatusCode::OK { + return None; + } + + for _ in 0..5 { + let request = super::client::build_token_poll_request(&client, &uuid, &verifier, is_pri); + let response = request.send().await.ok()?; + + match response.status() { + reqwest::StatusCode::OK => { + let poll_response = response.json::().await.ok()?; + return Some(poll_response.access_token); + } + reqwest::StatusCode::NOT_FOUND => { + tokio::time::sleep(std::time::Duration::from_secs(1)).await; + continue; + } + _ => return None, + } + } + + None +} diff --git a/src/common/utils/checksum.rs b/src/common/utils/checksum.rs index 0e90b0d..2a885d5 100644 --- a/src/common/utils/checksum.rs +++ b/src/common/utils/checksum.rs @@ -32,11 +32,7 @@ fn deobfuscate_bytes(bytes: &mut [u8]) { } pub fn generate_timestamp_header() -> String { - let timestamp = std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .as_secs() - / 1_000; + let timestamp = super::now_secs() / 1_000; let mut timestamp_bytes = vec![ ((timestamp >> 8) & 0xFF) as u8, @@ -55,8 +51,8 @@ pub fn generate_timestamp_header() -> String { pub fn generate_checksum(device_id: &str, mac_addr: Option<&str>) -> String { let encoded = generate_timestamp_header(); match mac_addr { - Some(mac) => format!("{}{}/{}", encoded, device_id, mac), - None => format!("{}{}", encoded, device_id), + Some(mac) => format!("{encoded}{device_id}/{mac}"), + None => format!("{encoded}{device_id}"), } } @@ -109,20 +105,20 @@ pub fn generate_checksum_with_repair(checksum: &str) -> String { 72 => format!( "{}{}/{}", generate_timestamp_header(), - unsafe { std::str::from_utf8_unchecked(&bytes[8..]) }, + unsafe { std::str::from_utf8_unchecked(bytes.get_unchecked(8..)) }, generate_hash() ), 129 => format!( "{}{}/{}", generate_timestamp_header(), - unsafe { std::str::from_utf8_unchecked(&bytes[..64]) }, - unsafe { std::str::from_utf8_unchecked(&bytes[65..]) } + unsafe { std::str::from_utf8_unchecked(bytes.get_unchecked(..64)) }, + unsafe { std::str::from_utf8_unchecked(bytes.get_unchecked(65..)) } ), 137 => format!( "{}{}/{}", generate_timestamp_header(), - unsafe { std::str::from_utf8_unchecked(&bytes[8..72]) }, - unsafe { std::str::from_utf8_unchecked(&bytes[73..]) } + unsafe { std::str::from_utf8_unchecked(bytes.get_unchecked(8..72)) }, + unsafe { std::str::from_utf8_unchecked(bytes.get_unchecked(73..)) } ), _ => unreachable!(), } @@ -137,17 +133,21 @@ pub fn extract_time_ks(timestamp_base64: &str) -> Option { deobfuscate_bytes(&mut timestamp_bytes); - if timestamp_bytes[0] != timestamp_bytes[4] || timestamp_bytes[1] != timestamp_bytes[5] { - return None; - } + unsafe { + if timestamp_bytes.get_unchecked(0) != timestamp_bytes.get_unchecked(4) + || timestamp_bytes.get_unchecked(1) != timestamp_bytes.get_unchecked(5) + { + return None; + } - // 使用后四位还原 timestamp - Some( - ((timestamp_bytes[2] as u64) << 24) - | ((timestamp_bytes[3] as u64) << 16) - | ((timestamp_bytes[4] as u64) << 8) - | (timestamp_bytes[5] as u64), - ) + // 使用后四位还原 timestamp + Some( + ((*timestamp_bytes.get_unchecked(2) as u64) << 24) + | ((*timestamp_bytes.get_unchecked(3) as u64) << 16) + | ((*timestamp_bytes.get_unchecked(4) as u64) << 8) + | (*timestamp_bytes.get_unchecked(5) as u64), + ) + } } pub fn validate_checksum(checksum: &str) -> bool { @@ -183,16 +183,9 @@ pub fn validate_checksum(checksum: &str) -> bool { } // 统一时间戳验证(无需分层) - let time_valid = extract_time_ks(&checksum[..8]).is_some(); + let time_valid = extract_time_ks(unsafe { checksum.get_unchecked(..8) }).is_some(); - // 附加MAC哈希长度校验(仅137字符需要) - let mac_hash_valid = if len == 137 { - checksum[73..].len() == 64 // 确保MAC哈希长度为64 - } else { - true // 72字符无需此检查 - }; - - time_valid && mac_hash_valid + time_valid } /// 从校验通过的checksum中提取哈希值(需先通过validate_checksum验证) @@ -207,14 +200,14 @@ pub fn extract_hashes(checksum: &str) -> Option<(Vec, Vec)> { match checksum.len() { 72 => { // 格式:8字节时间戳 + 64字节设备哈希 - let device_hash = hex::decode(&checksum[8..]).ok()?; // 8..72 + let device_hash = hex::decode(unsafe { checksum.get_unchecked(8..) }).ok()?; // 8..72 Some((device_hash, Vec::new())) } 137 => { // 格式:8时间戳 + 64设备哈希 + '/' + 64MAC哈希 // 直接按固定位置切割(validate_checksum已确保索引72是'/') - let device_hash = hex::decode(&checksum[8..72]).ok()?; - let mac_hash = hex::decode(&checksum[73..]).ok()?; // 73..137 + let device_hash = hex::decode(unsafe { checksum.get_unchecked(8..72) }).ok()?; + let mac_hash = hex::decode(unsafe { checksum.get_unchecked(73..) }).ok()?; // 73..137 Some((device_hash, mac_hash)) } // validate_checksum已过滤其他长度,此处应为不可达代码 diff --git a/src/common/utils/token.rs b/src/common/utils/token.rs index 6b4ab65..2f8d74c 100644 --- a/src/common/utils/token.rs +++ b/src/common/utils/token.rs @@ -123,10 +123,10 @@ pub fn validate_token(token: &str) -> bool { } // 验证过期时间 - let current_time = chrono::Utc::now().timestamp(); - if current_time > payload.exp { - return false; - } + // let current_time = chrono::Utc::now().timestamp(); + // if current_time > payload.exp { + // return false; + // } // 验证发行者 if payload.iss != ISSUER { @@ -183,8 +183,14 @@ pub fn extract_user_id(token: &str) -> Option { ) } +#[derive(serde::Serialize)] +pub struct JwtTime { + pub iat: DateTime, + pub exp: DateTime, +} + // 从 JWT token 中提取 time 字段 -pub fn extract_time(token: &str) -> Option> { +pub fn extract_time(token: &str) -> Option { // JWT token 由3部分组成,用 . 分隔 let parts: Vec<&str> = token.split('.').collect(); if parts.len() != 3 { @@ -197,6 +203,8 @@ pub fn extract_time(token: &str) -> Option> { Err(_) => return None, }; + drop(parts); + // 将 payload 转换为字符串 let payload_str = match String::from_utf8(payload) { Ok(s) => s, @@ -209,10 +217,12 @@ pub fn extract_time(token: &str) -> Option> { Err(_) => return None, }; - // 提取时间戳并转换为本地时间 - payload + let iat = payload .time .parse::() .ok() - .and_then(|timestamp| Local.timestamp_opt(timestamp, 0).single()) + .and_then(|ts| Local.timestamp_opt(ts, 0).single())?; + let exp = Local.timestamp_opt(payload.exp, 0).single()?; + + Some(JwtTime { iat, exp }) } diff --git a/src/core/adapter.rs b/src/core/adapter.rs index 06f1ba2..4d9eaf3 100644 --- a/src/core/adapter.rs +++ b/src/core/adapter.rs @@ -88,6 +88,7 @@ fn parse_web_references(text: &str) -> Vec { async fn process_chat_inputs( inputs: Vec, + now_with_tz: Option>, disable_vision: bool, model: &str, ) -> (String, Vec, Vec) { @@ -115,7 +116,7 @@ async fn process_chat_inputs( // 使用默认指令或收集到的指令 let image_support = !disable_vision && SUPPORTED_IMAGE_MODELS.contains(&model); let instructions = if instructions.is_empty() { - get_default_instructions(model, image_support) + get_default_instructions(now_with_tz, model, image_support) } else { instructions }; @@ -491,15 +492,14 @@ async fn process_http_image( pub async fn encode_chat_message( inputs: Vec, + now_with_tz: Option>, model: &str, disable_vision: bool, enable_slow_pool: bool, is_search: bool, ) -> Result, Box> { - // 在进入异步操作前获取并释放锁 - let enable_slow_pool = { if enable_slow_pool { Some(true) } else { None } }; - - let (instructions, messages, urls) = process_chat_inputs(inputs, disable_vision, model).await; + let (instructions, messages, urls) = + process_chat_inputs(inputs, now_with_tz, disable_vision, model).await; let explicit_context = if !instructions.trim().is_empty() { Some(ExplicitContext { @@ -525,6 +525,8 @@ pub async fn encode_chat_message( }) .collect(); + let long_context = AppConfig::get_long_context() || LONG_CONTEXT_MODELS.contains(&model); + let chat = GetChatRequest { current_file: None, conversation: messages, @@ -542,7 +544,7 @@ pub async fn encode_chat_message( deployment: String::new(), use_azure: false, }), - enable_slow_pool, + enable_slow_pool: if enable_slow_pool { Some(true) } else { None }, openai_api_base_url: None, }), documentation_identifiers: vec![], @@ -564,11 +566,9 @@ pub async fn encode_chat_message( workspace_id: None, external_links, commit_notes: vec![], - long_context_mode: Some( - AppConfig::get_long_context() || LONG_CONTEXT_MODELS.contains(&model), - ), + long_context_mode: Some(long_context), is_eval: Some(false), - desired_max_tokens: None, + desired_max_tokens: if long_context { Some(200_000) } else { None }, context_ast: None, is_composer: None, runnable_code_blocks: Some(false), diff --git a/src/core/aiserver/v1/aiserver.v1.rs b/src/core/aiserver/v1/aiserver.v1.rs index e62600f..175fd2d 100644 --- a/src/core/aiserver/v1/aiserver.v1.rs +++ b/src/core/aiserver/v1/aiserver.v1.rs @@ -25,17 +25,7 @@ pub struct GitDiff { /// Nested message and enum types in `GitDiff`. pub mod git_diff { /// aiserver.v1.GitDiff.DiffType - #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration - )] + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum DiffType { Unspecified = 0, @@ -182,17 +172,7 @@ pub mod diagnostic { pub range: ::core::option::Option, } /// aiserver.v1.Diagnostic.DiagnosticSeverity - #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration - )] + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum DiagnosticSeverity { Unspecified = 0, @@ -410,17 +390,7 @@ pub struct ErrorDetails { /// Nested message and enum types in `ErrorDetails`. pub mod error_details { /// aiserver.v1.ErrorDetails.Error - #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration - )] + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum Error { Unspecified = 0, @@ -509,9 +479,7 @@ pub mod error_details { Self::GenericRateLimitExceeded => "ERROR_GENERIC_RATE_LIMIT_EXCEEDED", Self::SlashEditFileTooLong => "ERROR_SLASH_EDIT_FILE_TOO_LONG", Self::FileUnsupported => "ERROR_FILE_UNSUPPORTED", - Self::Gpt4VisionPreviewRateLimit => { - "ERROR_GPT_4_VISION_PREVIEW_RATE_LIMIT" - } + Self::Gpt4VisionPreviewRateLimit => "ERROR_GPT_4_VISION_PREVIEW_RATE_LIMIT", Self::CustomMessage => "ERROR_CUSTOM_MESSAGE", Self::OutdatedClient => "ERROR_OUTDATED_CLIENT", Self::ClaudeImageTooLarge => "ERROR_CLAUDE_IMAGE_TOO_LARGE", @@ -526,9 +494,7 @@ pub mod error_details { Self::Unauthorized => "ERROR_UNAUTHORIZED", Self::ConversationTooLong => "ERROR_CONVERSATION_TOO_LONG", Self::UsagePricingRequired => "ERROR_USAGE_PRICING_REQUIRED", - Self::UsagePricingRequiredChangeable => { - "ERROR_USAGE_PRICING_REQUIRED_CHANGEABLE" - } + Self::UsagePricingRequiredChangeable => "ERROR_USAGE_PRICING_REQUIRED_CHANGEABLE", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -539,20 +505,14 @@ pub mod error_details { "ERROR_BAD_USER_API_KEY" => Some(Self::BadUserApiKey), "ERROR_NOT_LOGGED_IN" => Some(Self::NotLoggedIn), "ERROR_INVALID_AUTH_ID" => Some(Self::InvalidAuthId), - "ERROR_NOT_HIGH_ENOUGH_PERMISSIONS" => { - Some(Self::NotHighEnoughPermissions) - } + "ERROR_NOT_HIGH_ENOUGH_PERMISSIONS" => Some(Self::NotHighEnoughPermissions), "ERROR_AGENT_REQUIRES_LOGIN" => Some(Self::AgentRequiresLogin), "ERROR_BAD_MODEL_NAME" => Some(Self::BadModelName), "ERROR_NOT_FOUND" => Some(Self::NotFound), "ERROR_DEPRECATED" => Some(Self::Deprecated), "ERROR_USER_NOT_FOUND" => Some(Self::UserNotFound), - "ERROR_FREE_USER_RATE_LIMIT_EXCEEDED" => { - Some(Self::FreeUserRateLimitExceeded) - } - "ERROR_PRO_USER_RATE_LIMIT_EXCEEDED" => { - Some(Self::ProUserRateLimitExceeded) - } + "ERROR_FREE_USER_RATE_LIMIT_EXCEEDED" => Some(Self::FreeUserRateLimitExceeded), + "ERROR_PRO_USER_RATE_LIMIT_EXCEEDED" => Some(Self::ProUserRateLimitExceeded), "ERROR_FREE_USER_USAGE_LIMIT" => Some(Self::FreeUserUsageLimit), "ERROR_PRO_USER_USAGE_LIMIT" => Some(Self::ProUserUsageLimit), "ERROR_RESOURCE_EXHAUSTED" => Some(Self::ResourceExhausted), @@ -560,9 +520,7 @@ pub mod error_details { "ERROR_AUTH_TOKEN_EXPIRED" => Some(Self::AuthTokenExpired), "ERROR_OPENAI" => Some(Self::Openai), "ERROR_OPENAI_RATE_LIMIT_EXCEEDED" => Some(Self::OpenaiRateLimitExceeded), - "ERROR_OPENAI_ACCOUNT_LIMIT_EXCEEDED" => { - Some(Self::OpenaiAccountLimitExceeded) - } + "ERROR_OPENAI_ACCOUNT_LIMIT_EXCEEDED" => Some(Self::OpenaiAccountLimitExceeded), "ERROR_TASK_UUID_NOT_FOUND" => Some(Self::TaskUuidNotFound), "ERROR_TASK_NO_PERMISSIONS" => Some(Self::TaskNoPermissions), "ERROR_AGENT_ENGINE_NOT_FOUND" => Some(Self::AgentEngineNotFound), @@ -571,14 +529,10 @@ pub mod error_details { "ERROR_API_KEY_NOT_SUPPORTED" => Some(Self::ApiKeyNotSupported), "ERROR_USER_ABORTED_REQUEST" => Some(Self::UserAbortedRequest), "ERROR_TIMEOUT" => Some(Self::Timeout), - "ERROR_GENERIC_RATE_LIMIT_EXCEEDED" => { - Some(Self::GenericRateLimitExceeded) - } + "ERROR_GENERIC_RATE_LIMIT_EXCEEDED" => Some(Self::GenericRateLimitExceeded), "ERROR_SLASH_EDIT_FILE_TOO_LONG" => Some(Self::SlashEditFileTooLong), "ERROR_FILE_UNSUPPORTED" => Some(Self::FileUnsupported), - "ERROR_GPT_4_VISION_PREVIEW_RATE_LIMIT" => { - Some(Self::Gpt4VisionPreviewRateLimit) - } + "ERROR_GPT_4_VISION_PREVIEW_RATE_LIMIT" => Some(Self::Gpt4VisionPreviewRateLimit), "ERROR_CUSTOM_MESSAGE" => Some(Self::CustomMessage), "ERROR_OUTDATED_CLIENT" => Some(Self::OutdatedClient), "ERROR_CLAUDE_IMAGE_TOO_LARGE" => Some(Self::ClaudeImageTooLarge), @@ -609,9 +563,8 @@ pub struct CustomErrorDetails { #[prost(string, tag = "2")] pub detail: ::prost::alloc::string::String, #[prost(bool, optional, tag = "3")] - pub allow_command_links_potentially_unsafe_please_only_use_for_handwritten_trusted_markdown: ::core::option::Option< - bool, - >, + pub allow_command_links_potentially_unsafe_please_only_use_for_handwritten_trusted_markdown: + ::core::option::Option, #[prost(bool, optional, tag = "4")] pub is_retryable: ::core::option::Option, #[prost(bool, optional, tag = "5")] @@ -687,17 +640,7 @@ pub struct CodeChunk { /// Nested message and enum types in `CodeChunk`. pub mod code_chunk { /// aiserver.v1.CodeChunk.Intent - #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration - )] + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum Intent { Unspecified = 0, @@ -727,17 +670,7 @@ pub mod code_chunk { } } /// aiserver.v1.CodeChunk.SummarizationStrategy - #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration - )] + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum SummarizationStrategy { NoneUnspecified = 0, @@ -852,9 +785,8 @@ pub struct ToolResultError { #[prost(string, tag = "2")] pub model_visible_error_message: ::prost::alloc::string::String, #[prost(string, optional, tag = "3")] - pub actual_error_message_only_send_from_client_to_server_never_the_other_way_around_because_that_may_be_a_security_risk: ::core::option::Option< - ::prost::alloc::string::String, - >, + pub actual_error_message_only_send_from_client_to_server_never_the_other_way_around_because_that_may_be_a_security_risk: + ::core::option::Option<::prost::alloc::string::String>, } /// aiserver.v1.ClientSideToolV2Result #[derive(Clone, PartialEq, ::prost::Message)] @@ -971,15 +903,7 @@ pub mod edit_file_result { } /// aiserver.v1.EditFileResult.FileDiff.Editor #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, )] #[repr(i32)] pub enum Editor { @@ -1101,9 +1025,8 @@ pub struct RipgrepSearchResultInternal { #[prost(bool, optional, tag = "3")] pub limit_hit: ::core::option::Option, #[prost(message, repeated, tag = "4")] - pub messages: ::prost::alloc::vec::Vec< - ripgrep_search_result_internal::ITextSearchCompleteMessage, - >, + pub messages: + ::prost::alloc::vec::Vec, #[prost(oneof = "ripgrep_search_result_internal::Stats", tags = "5, 6")] pub stats: ::core::option::Option, } @@ -1205,15 +1128,7 @@ pub mod ripgrep_search_result_internal { pub mod i_file_search_stats { /// aiserver.v1.RipgrepSearchResultInternal.IFileSearchStats.FileSearchProviderType #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, )] #[repr(i32)] pub enum FileSearchProviderType { @@ -1229,9 +1144,7 @@ pub mod ripgrep_search_result_internal { pub fn as_str_name(&self) -> &'static str { match self { Self::Unspecified => "FILE_SEARCH_PROVIDER_TYPE_UNSPECIFIED", - Self::FileSearchProvider => { - "FILE_SEARCH_PROVIDER_TYPE_FILE_SEARCH_PROVIDER" - } + Self::FileSearchProvider => "FILE_SEARCH_PROVIDER_TYPE_FILE_SEARCH_PROVIDER", Self::SearchProcess => "FILE_SEARCH_PROVIDER_TYPE_SEARCH_PROCESS", } } @@ -1242,9 +1155,7 @@ pub mod ripgrep_search_result_internal { "FILE_SEARCH_PROVIDER_TYPE_FILE_SEARCH_PROVIDER" => { Some(Self::FileSearchProvider) } - "FILE_SEARCH_PROVIDER_TYPE_SEARCH_PROCESS" => { - Some(Self::SearchProcess) - } + "FILE_SEARCH_PROVIDER_TYPE_SEARCH_PROCESS" => Some(Self::SearchProcess), _ => None, } } @@ -1269,15 +1180,7 @@ pub mod ripgrep_search_result_internal { pub mod i_text_search_stats { /// aiserver.v1.RipgrepSearchResultInternal.ITextSearchStats.TextSearchProviderType #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, )] #[repr(i32)] pub enum TextSearchProviderType { @@ -1294,9 +1197,7 @@ pub mod ripgrep_search_result_internal { pub fn as_str_name(&self) -> &'static str { match self { Self::Unspecified => "TEXT_SEARCH_PROVIDER_TYPE_UNSPECIFIED", - Self::TextSearchProvider => { - "TEXT_SEARCH_PROVIDER_TYPE_TEXT_SEARCH_PROVIDER" - } + Self::TextSearchProvider => "TEXT_SEARCH_PROVIDER_TYPE_TEXT_SEARCH_PROVIDER", Self::SearchProcess => "TEXT_SEARCH_PROVIDER_TYPE_SEARCH_PROCESS", Self::AiTextSearchProvider => { "TEXT_SEARCH_PROVIDER_TYPE_AI_TEXT_SEARCH_PROVIDER" @@ -1310,9 +1211,7 @@ pub mod ripgrep_search_result_internal { "TEXT_SEARCH_PROVIDER_TYPE_TEXT_SEARCH_PROVIDER" => { Some(Self::TextSearchProvider) } - "TEXT_SEARCH_PROVIDER_TYPE_SEARCH_PROCESS" => { - Some(Self::SearchProcess) - } + "TEXT_SEARCH_PROVIDER_TYPE_SEARCH_PROCESS" => Some(Self::SearchProcess), "TEXT_SEARCH_PROVIDER_TYPE_AI_TEXT_SEARCH_PROVIDER" => { Some(Self::AiTextSearchProvider) } @@ -1356,17 +1255,7 @@ pub mod ripgrep_search_result_internal { pub post_process_time: i32, } /// aiserver.v1.RipgrepSearchResultInternal.TextSearchCompleteMessageType - #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration - )] + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum TextSearchCompleteMessageType { Unspecified = 0, @@ -1388,29 +1277,15 @@ pub mod ripgrep_search_result_internal { /// Creates an enum from field names used in the ProtoBuf definition. pub fn from_str_name(value: &str) -> ::core::option::Option { match value { - "TEXT_SEARCH_COMPLETE_MESSAGE_TYPE_UNSPECIFIED" => { - Some(Self::Unspecified) - } - "TEXT_SEARCH_COMPLETE_MESSAGE_TYPE_INFORMATION" => { - Some(Self::Information) - } + "TEXT_SEARCH_COMPLETE_MESSAGE_TYPE_UNSPECIFIED" => Some(Self::Unspecified), + "TEXT_SEARCH_COMPLETE_MESSAGE_TYPE_INFORMATION" => Some(Self::Information), "TEXT_SEARCH_COMPLETE_MESSAGE_TYPE_WARNING" => Some(Self::Warning), _ => None, } } } /// aiserver.v1.RipgrepSearchResultInternal.SearchCompletionExitCode - #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration - )] + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum SearchCompletionExitCode { Unspecified = 0, @@ -1426,9 +1301,7 @@ pub mod ripgrep_search_result_internal { match self { Self::Unspecified => "SEARCH_COMPLETION_EXIT_CODE_UNSPECIFIED", Self::Normal => "SEARCH_COMPLETION_EXIT_CODE_NORMAL", - Self::NewSearchStarted => { - "SEARCH_COMPLETION_EXIT_CODE_NEW_SEARCH_STARTED" - } + Self::NewSearchStarted => "SEARCH_COMPLETION_EXIT_CODE_NEW_SEARCH_STARTED", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -1436,9 +1309,7 @@ pub mod ripgrep_search_result_internal { match value { "SEARCH_COMPLETION_EXIT_CODE_UNSPECIFIED" => Some(Self::Unspecified), "SEARCH_COMPLETION_EXIT_CODE_NORMAL" => Some(Self::Normal), - "SEARCH_COMPLETION_EXIT_CODE_NEW_SEARCH_STARTED" => { - Some(Self::NewSearchStarted) - } + "SEARCH_COMPLETION_EXIT_CODE_NEW_SEARCH_STARTED" => Some(Self::NewSearchStarted), _ => None, } } @@ -1464,17 +1335,7 @@ pub struct MissingFile { /// Nested message and enum types in `MissingFile`. pub mod missing_file { /// aiserver.v1.MissingFile.MissingReason - #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration - )] + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum MissingReason { Unspecified = 0, @@ -1705,17 +1566,13 @@ pub mod diff_history_result { #[prost(int32, tag = "2")] pub end_line_number_exclusive: i32, #[prost(string, repeated, tag = "3")] - pub before_context_lines: ::prost::alloc::vec::Vec< - ::prost::alloc::string::String, - >, + pub before_context_lines: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, #[prost(string, repeated, tag = "4")] pub removed_lines: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, #[prost(string, repeated, tag = "5")] pub added_lines: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, #[prost(string, repeated, tag = "6")] - pub after_context_lines: ::prost::alloc::vec::Vec< - ::prost::alloc::string::String, - >, + pub after_context_lines: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, } /// aiserver.v1.DiffHistoryResult.HumanChange #[derive(Clone, PartialEq, ::prost::Message)] @@ -1772,15 +1629,7 @@ pub mod implementer_result { } /// aiserver.v1.ImplementerResult.FileDiff.Editor #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, )] #[repr(i32)] pub enum Editor { @@ -1950,10 +1799,7 @@ pub mod composer_capability_request { #[prost(string, tag = "2")] pub name: ::prost::alloc::string::String, #[prost(map = "string, message", tag = "3")] - pub properties: ::std::collections::HashMap< - ::prost::alloc::string::String, - SchemaProperty, - >, + pub properties: ::std::collections::HashMap<::prost::alloc::string::String, SchemaProperty>, #[prost(string, repeated, tag = "4")] pub required: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, } @@ -2011,9 +1857,7 @@ pub mod composer_capability_request { #[prost(string, repeated, tag = "4")] pub files_in_context: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, #[prost(string, repeated, tag = "5")] - pub semantic_search_files: ::prost::alloc::vec::Vec< - ::prost::alloc::string::String, - >, + pub semantic_search_files: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, } /// aiserver.v1.ComposerCapabilityRequest.DiffReviewCapability #[derive(Clone, PartialEq, ::prost::Message)] @@ -2061,9 +1905,7 @@ pub mod composer_capability_request { #[prost(string, optional, tag = "1")] pub custom_instructions: ::core::option::Option<::prost::alloc::string::String>, #[prost(string, repeated, tag = "2")] - pub potential_context_files: ::prost::alloc::vec::Vec< - ::prost::alloc::string::String, - >, + pub potential_context_files: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, #[prost(message, repeated, tag = "3")] pub potential_context_code_chunks: ::prost::alloc::vec::Vec, #[prost(string, repeated, tag = "4")] @@ -2106,17 +1948,7 @@ pub mod composer_capability_request { pub custom_instructions: ::core::option::Option<::prost::alloc::string::String>, } /// aiserver.v1.ComposerCapabilityRequest.ComposerCapabilityType - #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration - )] + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum ComposerCapabilityType { Unspecified = 0, @@ -2171,9 +2003,7 @@ pub mod composer_capability_request { Self::UsageData => "COMPOSER_CAPABILITY_TYPE_USAGE_DATA", Self::Chimes => "COMPOSER_CAPABILITY_TYPE_CHIMES", Self::CodeDecayTracker => "COMPOSER_CAPABILITY_TYPE_CODE_DECAY_TRACKER", - Self::BackgroundComposer => { - "COMPOSER_CAPABILITY_TYPE_BACKGROUND_COMPOSER" - } + Self::BackgroundComposer => "COMPOSER_CAPABILITY_TYPE_BACKGROUND_COMPOSER", Self::Summarization => "COMPOSER_CAPABILITY_TYPE_SUMMARIZATION", } } @@ -2200,29 +2030,15 @@ pub mod composer_capability_request { "COMPOSER_CAPABILITY_TYPE_TOKEN_COUNTER" => Some(Self::TokenCounter), "COMPOSER_CAPABILITY_TYPE_USAGE_DATA" => Some(Self::UsageData), "COMPOSER_CAPABILITY_TYPE_CHIMES" => Some(Self::Chimes), - "COMPOSER_CAPABILITY_TYPE_CODE_DECAY_TRACKER" => { - Some(Self::CodeDecayTracker) - } - "COMPOSER_CAPABILITY_TYPE_BACKGROUND_COMPOSER" => { - Some(Self::BackgroundComposer) - } + "COMPOSER_CAPABILITY_TYPE_CODE_DECAY_TRACKER" => Some(Self::CodeDecayTracker), + "COMPOSER_CAPABILITY_TYPE_BACKGROUND_COMPOSER" => Some(Self::BackgroundComposer), "COMPOSER_CAPABILITY_TYPE_SUMMARIZATION" => Some(Self::Summarization), _ => None, } } } /// aiserver.v1.ComposerCapabilityRequest.ToolType - #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration - )] + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum ToolType { Unspecified = 0, @@ -2255,9 +2071,7 @@ pub mod composer_capability_request { "TOOL_TYPE_RUN_TERMINAL_COMMAND" => Some(Self::RunTerminalCommand), "TOOL_TYPE_ITERATE" => Some(Self::Iterate), "TOOL_TYPE_REMOVE_FILE_FROM_CONTEXT" => Some(Self::RemoveFileFromContext), - "TOOL_TYPE_SEMANTIC_SEARCH_CODEBASE" => { - Some(Self::SemanticSearchCodebase) - } + "TOOL_TYPE_SEMANTIC_SEARCH_CODEBASE" => Some(Self::SemanticSearchCodebase), _ => None, } } @@ -2370,17 +2184,7 @@ pub struct StreamUnifiedChatRequest {} /// Nested message and enum types in `StreamUnifiedChatRequest`. pub mod stream_unified_chat_request { /// aiserver.v1.StreamUnifiedChatRequest.UnifiedMode - #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration - )] + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum UnifiedMode { Unspecified = 0, @@ -2434,13 +2238,10 @@ pub struct ServiceStatusUpdate { #[prost(string, tag = "2")] pub codicon: ::prost::alloc::string::String, #[prost(bool, optional, tag = "3")] - pub allow_command_links_potentially_unsafe_please_only_use_for_handwritten_trusted_markdown: ::core::option::Option< - bool, - >, + pub allow_command_links_potentially_unsafe_please_only_use_for_handwritten_trusted_markdown: + ::core::option::Option, #[prost(string, optional, tag = "4")] - pub action_to_run_on_status_update: ::core::option::Option< - ::prost::alloc::string::String, - >, + pub action_to_run_on_status_update: ::core::option::Option<::prost::alloc::string::String>, } /// aiserver.v1.SymbolLink #[derive(Clone, PartialEq, ::prost::Message)] @@ -2548,9 +2349,8 @@ pub struct ConversationMessage { #[prost(string, repeated, tag = "11")] pub attached_folders: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, #[prost(message, repeated, tag = "12")] - pub approximate_lint_errors: ::prost::alloc::vec::Vec< - conversation_message::ApproximateLintError, - >, + pub approximate_lint_errors: + ::prost::alloc::vec::Vec, #[prost(string, tag = "13")] pub bubble_id: ::prost::alloc::string::String, #[prost(string, optional, tag = "32")] @@ -2560,9 +2360,8 @@ pub struct ConversationMessage { #[prost(message, repeated, tag = "15")] pub lints: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag = "16")] - pub user_responses_to_suggested_code_blocks: ::prost::alloc::vec::Vec< - UserResponseToSuggestedCodeBlock, - >, + pub user_responses_to_suggested_code_blocks: + ::prost::alloc::vec::Vec, #[prost(string, repeated, tag = "17")] pub relevant_files: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, #[prost(message, repeated, tag = "18")] @@ -2574,25 +2373,19 @@ pub struct ConversationMessage { #[prost(message, repeated, tag = "21")] pub capabilities: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag = "22")] - pub edit_trail_contexts: ::prost::alloc::vec::Vec< - conversation_message::EditTrailContext, - >, + pub edit_trail_contexts: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag = "23")] pub suggested_code_blocks: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag = "24")] pub diffs_for_compressing_files: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag = "25")] - pub multi_file_linter_errors: ::prost::alloc::vec::Vec< - LinterErrorsWithoutFileContents, - >, + pub multi_file_linter_errors: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag = "26")] pub diff_histories: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag = "27")] pub recently_viewed_files: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag = "28")] - pub recent_locations_history: ::prost::alloc::vec::Vec< - conversation_message::RecentLocation, - >, + pub recent_locations_history: ::prost::alloc::vec::Vec, #[prost(bool, tag = "29")] pub is_agentic: bool, #[prost(message, repeated, tag = "30")] @@ -2618,9 +2411,7 @@ pub struct ConversationMessage { #[prost(bool, tag = "41")] pub attached_human_changes: bool, #[prost(message, repeated, tag = "42")] - pub summarized_composers: ::prost::alloc::vec::Vec< - conversation_message::ComposerContext, - >, + pub summarized_composers: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag = "43")] pub cursor_rules: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag = "44")] @@ -2636,9 +2427,7 @@ pub struct ConversationMessage { )] pub unified_mode: ::core::option::Option, #[prost(message, repeated, tag = "48")] - pub diffs_since_last_apply: ::prost::alloc::vec::Vec< - conversation_message::DiffSinceLastApply, - >, + pub diffs_since_last_apply: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag = "49")] pub deleted_files: ::prost::alloc::vec::Vec, #[prost(string, optional, tag = "50")] @@ -2676,15 +2465,7 @@ pub mod conversation_message { pub mod code_chunk { /// aiserver.v1.ConversationMessage.CodeChunk.Intent #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, )] #[repr(i32)] pub enum Intent { @@ -2717,9 +2498,7 @@ pub mod conversation_message { match value { "INTENT_UNSPECIFIED" => Some(Self::Unspecified), "INTENT_COMPOSER_FILE" => Some(Self::ComposerFile), - "INTENT_COMPRESSED_COMPOSER_FILE" => { - Some(Self::CompressedComposerFile) - } + "INTENT_COMPRESSED_COMPOSER_FILE" => Some(Self::CompressedComposerFile), "INTENT_RECENTLY_VIEWED_FILE" => Some(Self::RecentlyViewedFile), "INTENT_OUTLINE" => Some(Self::Outline), "INTENT_MENTIONED_FILE" => Some(Self::MentionedFile), @@ -2730,15 +2509,7 @@ pub mod conversation_message { } /// aiserver.v1.ConversationMessage.CodeChunk.SummarizationStrategy #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, )] #[repr(i32)] pub enum SummarizationStrategy { @@ -2761,9 +2532,7 @@ pub mod conversation_message { /// Creates an enum from field names used in the ProtoBuf definition. pub fn from_str_name(value: &str) -> ::core::option::Option { match value { - "SUMMARIZATION_STRATEGY_NONE_UNSPECIFIED" => { - Some(Self::NoneUnspecified) - } + "SUMMARIZATION_STRATEGY_NONE_UNSPECIFIED" => Some(Self::NoneUnspecified), "SUMMARIZATION_STRATEGY_SUMMARIZED" => Some(Self::Summarized), "SUMMARIZATION_STRATEGY_EMBEDDED" => Some(Self::Embedded), _ => None, @@ -2908,17 +2677,13 @@ pub mod conversation_message { #[prost(int32, tag = "2")] pub end_line_number_exclusive: i32, #[prost(string, repeated, tag = "3")] - pub before_context_lines: ::prost::alloc::vec::Vec< - ::prost::alloc::string::String, - >, + pub before_context_lines: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, #[prost(string, repeated, tag = "4")] pub removed_lines: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, #[prost(string, repeated, tag = "5")] pub added_lines: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, #[prost(string, repeated, tag = "6")] - pub after_context_lines: ::prost::alloc::vec::Vec< - ::prost::alloc::string::String, - >, + pub after_context_lines: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, } /// aiserver.v1.ConversationMessage.HumanChange #[derive(Clone, PartialEq, ::prost::Message)] @@ -2959,17 +2724,7 @@ pub mod conversation_message { pub relative_workspace_path: ::prost::alloc::string::String, } /// aiserver.v1.ConversationMessage.MessageType - #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration - )] + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum MessageType { Unspecified = 0, @@ -3108,17 +2863,7 @@ pub struct UserResponseToSuggestedCodeBlock { /// Nested message and enum types in `UserResponseToSuggestedCodeBlock`. pub mod user_response_to_suggested_code_block { /// aiserver.v1.UserResponseToSuggestedCodeBlock.UserResponseType - #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration - )] + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum UserResponseType { Unspecified = 0, @@ -3182,17 +2927,7 @@ pub mod composer_file_diff { pub lines_added: i32, } /// aiserver.v1.ComposerFileDiff.Editor - #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration - )] + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum Editor { Unspecified = 0, @@ -3359,19 +3094,13 @@ pub mod available_models_response { pub price: ::core::option::Option, #[prost(message, optional, tag = "8")] pub tooltip_data: ::core::option::Option, + #[prost(bool, optional, tag = "9")] + pub supports_thinking: ::core::option::Option, + #[prost(bool, optional, tag = "10")] + pub supports_images: ::core::option::Option, } /// aiserver.v1.AvailableModelsResponse.DegradationStatus - #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration - )] + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum DegradationStatus { Unspecified = 0, @@ -3451,13 +3180,9 @@ pub mod debug_info { #[prost(int32, tag = "2")] pub line_number: i32, #[prost(string, repeated, tag = "3")] - pub lines_before_breakpoint: ::prost::alloc::vec::Vec< - ::prost::alloc::string::String, - >, + pub lines_before_breakpoint: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, #[prost(string, repeated, tag = "4")] - pub lines_after_breakpoint: ::prost::alloc::vec::Vec< - ::prost::alloc::string::String, - >, + pub lines_after_breakpoint: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, #[prost(string, optional, tag = "5")] pub exception_info: ::core::option::Option<::prost::alloc::string::String>, } @@ -3480,9 +3205,7 @@ pub struct GetChatRequest { #[prost(message, optional, tag = "7")] pub model_details: ::core::option::Option, #[prost(string, repeated, tag = "8")] - pub documentation_identifiers: ::prost::alloc::vec::Vec< - ::prost::alloc::string::String, - >, + pub documentation_identifiers: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, #[prost(string, tag = "9")] pub request_id: ::prost::alloc::string::String, #[prost(message, optional, tag = "10")] @@ -3550,9 +3273,7 @@ pub struct StreamChatResponse { #[prost(string, optional, tag = "22")] pub server_bubble_id: ::core::option::Option<::prost::alloc::string::String>, #[prost(string, optional, tag = "2")] - pub debugging_only_chat_prompt: ::core::option::Option< - ::prost::alloc::string::String, - >, + pub debugging_only_chat_prompt: ::core::option::Option<::prost::alloc::string::String>, #[prost(int32, optional, tag = "3")] pub debugging_only_token_count: ::core::option::Option, #[prost(message, optional, tag = "4")] @@ -3721,9 +3442,7 @@ impl ClientSideToolV2 { Self::DiffHistory => "CLIENT_SIDE_TOOL_V2_DIFF_HISTORY", Self::Implementer => "CLIENT_SIDE_TOOL_V2_IMPLEMENTER", Self::SearchSymbols => "CLIENT_SIDE_TOOL_V2_SEARCH_SYMBOLS", - Self::BackgroundComposerFollowup => { - "CLIENT_SIDE_TOOL_V2_BACKGROUND_COMPOSER_FOLLOWUP" - } + Self::BackgroundComposerFollowup => "CLIENT_SIDE_TOOL_V2_BACKGROUND_COMPOSER_FOLLOWUP", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -3744,9 +3463,7 @@ impl ClientSideToolV2 { "CLIENT_SIDE_TOOL_V2_REAPPLY" => Some(Self::Reapply), "CLIENT_SIDE_TOOL_V2_GET_RELATED_FILES" => Some(Self::GetRelatedFiles), "CLIENT_SIDE_TOOL_V2_PARALLEL_APPLY" => Some(Self::ParallelApply), - "CLIENT_SIDE_TOOL_V2_RUN_TERMINAL_COMMAND_V2" => { - Some(Self::RunTerminalCommandV2) - } + "CLIENT_SIDE_TOOL_V2_RUN_TERMINAL_COMMAND_V2" => Some(Self::RunTerminalCommandV2), "CLIENT_SIDE_TOOL_V2_FETCH_RULES" => Some(Self::FetchRules), "CLIENT_SIDE_TOOL_V2_PLANNER" => Some(Self::Planner), "CLIENT_SIDE_TOOL_V2_WEB_SEARCH" => Some(Self::WebSearch), @@ -3780,12 +3497,8 @@ impl RunTerminalCommandEndedReason { pub fn as_str_name(&self) -> &'static str { match self { Self::Unspecified => "RUN_TERMINAL_COMMAND_ENDED_REASON_UNSPECIFIED", - Self::ExecutionCompleted => { - "RUN_TERMINAL_COMMAND_ENDED_REASON_EXECUTION_COMPLETED" - } - Self::ExecutionAborted => { - "RUN_TERMINAL_COMMAND_ENDED_REASON_EXECUTION_ABORTED" - } + Self::ExecutionCompleted => "RUN_TERMINAL_COMMAND_ENDED_REASON_EXECUTION_COMPLETED", + Self::ExecutionAborted => "RUN_TERMINAL_COMMAND_ENDED_REASON_EXECUTION_ABORTED", Self::ExecutionFailed => "RUN_TERMINAL_COMMAND_ENDED_REASON_EXECUTION_FAILED", Self::ErrorOccurredCheckingReason => { "RUN_TERMINAL_COMMAND_ENDED_REASON_ERROR_OCCURRED_CHECKING_REASON" @@ -3799,12 +3512,8 @@ impl RunTerminalCommandEndedReason { "RUN_TERMINAL_COMMAND_ENDED_REASON_EXECUTION_COMPLETED" => { Some(Self::ExecutionCompleted) } - "RUN_TERMINAL_COMMAND_ENDED_REASON_EXECUTION_ABORTED" => { - Some(Self::ExecutionAborted) - } - "RUN_TERMINAL_COMMAND_ENDED_REASON_EXECUTION_FAILED" => { - Some(Self::ExecutionFailed) - } + "RUN_TERMINAL_COMMAND_ENDED_REASON_EXECUTION_ABORTED" => Some(Self::ExecutionAborted), + "RUN_TERMINAL_COMMAND_ENDED_REASON_EXECUTION_FAILED" => Some(Self::ExecutionFailed), "RUN_TERMINAL_COMMAND_ENDED_REASON_ERROR_OCCURRED_CHECKING_REASON" => { Some(Self::ErrorOccurredCheckingReason) } diff --git a/src/core/aiserver/v1/lite.proto b/src/core/aiserver/v1/lite.proto index bbb3710..a78d6d9 100644 --- a/src/core/aiserver/v1/lite.proto +++ b/src/core/aiserver/v1/lite.proto @@ -1268,6 +1268,8 @@ message AvailableModelsResponse { // aiserver.v1.AvailableModelsResponse optional DegradationStatus degradation_status = 6; optional double price = 7; optional TooltipData tooltip_data = 8; + optional bool supports_thinking = 9; + optional bool supports_images = 10; } repeated AvailableModel models = 2; repeated string model_names = 1; diff --git a/src/core/config.rs b/src/core/config.rs index e649b7b..7335512 100644 --- a/src/core/config.rs +++ b/src/core/config.rs @@ -1,6 +1,7 @@ use crate::AppConfig; -include!(concat!(env!("OUT_DIR"), "/key.rs")); +// include!(concat!(env!("OUT_DIR"), "/key.rs")); +include!("config/key.rs"); impl KeyConfig { pub fn new_with_global() -> Self { diff --git a/src/core/config/key.proto b/src/core/config/key.proto index fb6a8d6..0b6e56e 100644 --- a/src/core/config/key.proto +++ b/src/core/config/key.proto @@ -7,12 +7,12 @@ message KeyConfig { // 认证令牌信息 message TokenInfo { string sub = 1; // 用户标识符 - int64 exp = 2; // 过期时间(Unix 时间戳) - string randomness = 3; // 随机字符串 - string signature = 4; // 签名 - bytes machine_id = 5; // 机器ID的SHA256哈希值 - bytes mac_id = 6; // MAC地址的SHA256哈希值 - // string timezone = 7; // 时区 + int64 start = 2; // 生成时间(Unix 时间戳) + int64 end = 3; // 过期时间(Unix 时间戳) + string randomness = 4; // 随机字符串 + string signature = 5; // 签名 + bytes machine_id = 6; // 机器ID的SHA256哈希值 + bytes mac_id = 7; // MAC地址的SHA256哈希值 optional string proxy_name = 8; // 代理名称 } diff --git a/src/core/config/key.rs b/src/core/config/key.rs new file mode 100644 index 0000000..8ccb0f9 --- /dev/null +++ b/src/core/config/key.rs @@ -0,0 +1,102 @@ +/// 动态配置的 API KEY +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct KeyConfig { + /// 认证令牌(必需) + #[prost(message, optional, tag = "1")] + pub auth_token: ::core::option::Option, + /// 是否禁用图片处理能力 + #[prost(bool, optional, tag = "4")] + pub disable_vision: ::core::option::Option, + /// 是否启用慢速池 + #[prost(bool, optional, tag = "5")] + pub enable_slow_pool: ::core::option::Option, + /// 使用量检查模型规则 + #[prost(message, optional, tag = "6")] + pub usage_check_models: ::core::option::Option, + /// 包含网络引用 + #[prost(bool, optional, tag = "7")] + pub include_web_references: ::core::option::Option, +} +/// Nested message and enum types in `KeyConfig`. +pub mod key_config { + /// 认证令牌信息 + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct TokenInfo { + /// 用户标识符 + #[prost(string, tag = "1")] + pub sub: ::prost::alloc::string::String, + /// 生成时间(Unix 时间戳) + #[prost(int64, tag = "2")] + pub start: i64, + /// 过期时间(Unix 时间戳) + #[prost(int64, tag = "3")] + pub end: i64, + /// 随机字符串 + #[prost(string, tag = "4")] + pub randomness: ::prost::alloc::string::String, + /// 签名 + #[prost(string, tag = "5")] + pub signature: ::prost::alloc::string::String, + /// 机器ID的SHA256哈希值 + #[prost(bytes = "vec", tag = "6")] + pub machine_id: ::prost::alloc::vec::Vec, + /// MAC地址的SHA256哈希值 + #[prost(bytes = "vec", tag = "7")] + pub mac_id: ::prost::alloc::vec::Vec, + /// 代理名称 + #[prost(string, optional, tag = "8")] + pub proxy_name: ::core::option::Option<::prost::alloc::string::String>, + } + /// 使用量检查模型规则 + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct UsageCheckModel { + /// 检查类型 + #[prost(enumeration = "usage_check_model::Type", tag = "1")] + pub r#type: i32, + /// 模型 ID 列表,当 type 为 TYPE_CUSTOM 时生效 + #[prost(string, repeated, tag = "2")] + pub model_ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + } + /// Nested message and enum types in `UsageCheckModel`. + pub mod usage_check_model { + /// 检查类型 + #[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, + )] + #[repr(i32)] + pub enum Type { + /// 未指定 + Default = 0, + /// 禁用 + Disabled = 1, + /// 全部 + All = 2, + /// 自定义列表 + Custom = 3, + } + impl Type { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Default => "TYPE_DEFAULT", + Self::Disabled => "TYPE_DISABLED", + Self::All => "TYPE_ALL", + Self::Custom => "TYPE_CUSTOM", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "TYPE_DEFAULT" => Some(Self::Default), + "TYPE_DISABLED" => Some(Self::Disabled), + "TYPE_ALL" => Some(Self::All), + "TYPE_CUSTOM" => Some(Self::Custom), + _ => None, + } + } + } + } +} diff --git a/src/core/constant.rs b/src/core/constant.rs index 164df57..1d81130 100644 --- a/src/core/constant.rs +++ b/src/core/constant.rs @@ -1,9 +1,14 @@ +mod display_name; +pub use display_name::calculate_display_name_v3; + use parking_lot::RwLock; use std::{ sync::Arc, time::{Duration, Instant}, }; +use crate::app::lazy::get_start_time; + use super::model::Model; macro_rules! def_pub_const { @@ -71,6 +76,7 @@ def_pub_const!( GEMINI_EXP_1206 => "gemini-exp-1206", GEMINI_2_0_PRO_EXP => "gemini-2.0-pro-exp", GEMINI_2_5_PRO_EXP_03_25 => "gemini-2.5-pro-exp-03-25", + GEMINI_2_5_PRO_MAX => "gemini-2.5-pro-max", GEMINI_2_0_FLASH_THINKING_EXP => "gemini-2.0-flash-thinking-exp", GEMINI_2_0_FLASH => "gemini-2.0-flash", @@ -93,13 +99,14 @@ macro_rules! create_models { $( Model { id: $model, + display_name: $crate::leak::intern_string(calculate_display_name_v3($model)), created: CREATED, object: MODEL_OBJECT, owned_by: $owner, }, )* ]), - last_update: Instant::now() - Duration::from_secs(30 * 60), + last_update: Instant::now(), }) }); }; @@ -154,7 +161,19 @@ impl Models { let mut data = INSTANCE.write(); // 检查时间间隔(30分钟) - if data.last_update.elapsed() < Duration::from_secs(30 * 60) { + if data.last_update.elapsed() < Duration::from_secs(30 * 60) && { + static ONCE: std::sync::OnceLock<()> = std::sync::OnceLock::new(); + if ONCE.get().is_some() { + true + } else { + let result = + chrono::Local::now() - get_start_time() >= chrono::TimeDelta::minutes(30); + if result { + let _ = ONCE.set(()); + } + result + } + } { return Ok(()); } @@ -202,6 +221,7 @@ create_models!( CLAUDE_3_5_HAIKU => ANTHROPIC, GEMINI_2_0_PRO_EXP => GOOGLE, GEMINI_2_5_PRO_EXP_03_25 => GOOGLE, + GEMINI_2_5_PRO_MAX => GOOGLE, GEMINI_2_0_FLASH_THINKING_EXP => GOOGLE, GEMINI_2_0_FLASH => GOOGLE, DEEPSEEK_V3 => DEEPSEEK, diff --git a/src/core/constant/display_name.rs b/src/core/constant/display_name.rs new file mode 100644 index 0000000..40b2ce8 --- /dev/null +++ b/src/core/constant/display_name.rs @@ -0,0 +1,171 @@ +/// 计算 AI 模型标识符的显示名称。 +/// +/// 规则: +/// 1. 单个数字通过 '-' 连接时 (前后都不是数字),'-' 变为 '.' (例如 "3-5" -> "3.5")。 +/// 2. 日期格式中的 '-' (如 YYYY-MM-DD, MM-DD) 保持不变。 +/// 3. 其他所有的 '-' 都被替换为空格 ' '。 +/// 4. 由原始 '-' 分隔的各部分(处理后)首字母大写 (Title Case)。 +/// 5. 特殊规则:如果原始标识符以 "gpt" 开头,则输出的对应部分为 "GPT"。 +/// +/// # Arguments +/// +/// * `identifier` - AI 模型的原始标识符字符串。 +/// +/// # Returns +/// +/// * `String` - 计算得到的显示名称。 +/// +/// # Examples +/// +/// ``` +/// assert_eq!(calculate_display_name_v3("claude-3-5-sonnet"), "Claude 3.5 Sonnet"); +/// assert_eq!(calculate_display_name_v3("gpt-4-turbo-2024-04-09"), "GPT 4 Turbo 2024-04-09"); // 日期 '-' 不变 +/// assert_eq!(calculate_display_name_v3("gemini-1.5-flash-500k"), "Gemini 1.5 Flash 500k"); +/// assert_eq!(calculate_display_name_v3("deepseek-v3"), "Deepseek V3"); +/// assert_eq!(calculate_display_name_v3("gpt-4o"), "GPT 4o"); +/// assert_eq!(calculate_display_name_v3("gpt-3.5-turbo"), "GPT 3.5 Turbo"); // 输入有 . +/// assert_eq!(calculate_display_name_v3("gemini-2.5-pro-exp-03-25"), "Gemini 2.5 Pro Exp 03-25"); // 日期 '-' 不变 +/// assert_eq!(calculate_display_name_v3("version-10-beta"), "Version 10 Beta"); // 10 不是单数字 +/// assert_eq!(calculate_display_name_v3("model-1-test-9-case"), "Model 1 Test 9 Case"); // d-d 转义被空格隔开 +/// ``` +pub fn calculate_display_name_v3(identifier: &str) -> String { + if identifier.is_empty() { + return String::new(); + } + + let mut result = String::new(); + let mut capitalize_next = true; + let mut prev_char: Option = None; + let mut prev_prev_char: Option = None; + + let mut char_iter = identifier.chars().peekable(); + if identifier.starts_with("gpt-") { + result.push_str("GPT"); + for _ in 0..4 { + char_iter.next(); + } + result.push(' '); + capitalize_next = true; + prev_char = Some('-'); + prev_prev_char = Some('t'); + } else if identifier == "gpt" { + return "GPT".to_string(); + } + + while let Some(current_char) = char_iter.next() { + match current_char { + '-' => { + let prev_is_digit = prev_char.map_or(false, |p| p.is_ascii_digit()); + let next_is_digit = char_iter.peek().map_or(false, |&n| n.is_ascii_digit()); + + if prev_is_digit && next_is_digit { + let prev_prev_is_digit = prev_prev_char.map_or(false, |pp| pp.is_ascii_digit()); + + let mut next_next_is_digit = false; + let mut lookahead = char_iter.clone(); + lookahead.next(); + if let Some(next_next_char) = lookahead.peek() { + if next_next_char.is_ascii_digit() { + next_next_is_digit = true; + } + } + + if prev_prev_is_digit || next_next_is_digit { + result.push('-'); + capitalize_next = true; + } else { + result.push('.'); + capitalize_next = false; + } + } else { + result.push(' '); + capitalize_next = true; + } + prev_prev_char = prev_char; + prev_char = Some('-'); + } + c => { + if capitalize_next { + result.extend(c.to_uppercase()); + capitalize_next = false; + } else { + result.push(c); + } + prev_prev_char = prev_char; + prev_char = Some(c); + } + } + } + + result +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_display_name_v3_final() { + // Anthropic + assert_eq!(calculate_display_name_v3("claude-3-opus"), "Claude 3 Opus"); + assert_eq!( + calculate_display_name_v3("claude-3.5-sonnet"), + "Claude 3.5 Sonnet" + ); // Input has dot + assert_eq!( + calculate_display_name_v3("claude-3-5-sonnet"), + "Claude 3.5 Sonnet" + ); // d-d conversion + assert_eq!( + calculate_display_name_v3("claude-3-haiku-200k"), + "Claude 3 Haiku 200k" + ); + + // OpenAI (GPT & Date Preservation) + assert_eq!(calculate_display_name_v3("gpt-4"), "GPT 4"); + assert_eq!(calculate_display_name_v3("gpt-4o"), "GPT 4o"); + assert_eq!(calculate_display_name_v3("gpt-3.5-turbo"), "GPT 3.5 Turbo"); // Input has dot + assert_eq!( + calculate_display_name_v3("gpt-4-turbo-2024-04-09"), + "GPT 4 Turbo 2024-04-09" + ); // Date preserved! + assert_eq!(calculate_display_name_v3("gpt-4o-mini"), "GPT 4o Mini"); + assert_eq!(calculate_display_name_v3("gpt"), "GPT"); + assert_eq!(calculate_display_name_v3("gpt-"), "GPT "); // Trailing hyphen becomes space + + // Google (Date Preservation) + assert_eq!( + calculate_display_name_v3("gemini-1.5-flash-500k"), + "Gemini 1.5 Flash 500k" + ); // Input has dot + assert_eq!( + calculate_display_name_v3("gemini-2.5-pro-exp-03-25"), + "Gemini 2.5 Pro Exp 03-25" + ); // Date preserved! + + // Deepseek + assert_eq!(calculate_display_name_v3("deepseek-v3"), "Deepseek V3"); + + // Other & Edge Cases + assert_eq!(calculate_display_name_v3("o1-mini"), "O1 Mini"); + assert_eq!( + calculate_display_name_v3("model-1-test-9-case"), + "Model 1 Test 9 Case" + ); // d-d handled + assert_eq!( + calculate_display_name_v3("version-10-beta"), + "Version 10 Beta" + ); // 10 is not single digit + assert_eq!( + calculate_display_name_v3("alpha-1-5-omega"), + "Alpha 1.5 Omega" + ); // d-d handled + assert_eq!(calculate_display_name_v3("my-gpt-model"), "My Gpt Model"); // gpt not at start + assert_eq!(calculate_display_name_v3(""), ""); // Empty + assert_eq!(calculate_display_name_v3("-start-"), " Start "); // Leading/trailing hyphens + assert_eq!(calculate_display_name_v3("a-b-c"), "A B C"); + assert_eq!(calculate_display_name_v3("3-5"), "3.5"); // Only d-d + assert_eq!(calculate_display_name_v3("2024-release"), "2024 Release"); // Number-text + assert_eq!(calculate_display_name_v3("data-01-01"), "Data 01-01"); // Date like MM-DD + } +} diff --git a/src/core/error.rs b/src/core/error.rs index 01b814e..11878bb 100644 --- a/src/core/error.rs +++ b/src/core/error.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use super::{aiserver::v1::ErrorDetails, constant::UNKNOWN}; use crate::common::model::{ApiStatus, ErrorResponse as CommonErrorResponse}; use base64::{Engine as _, engine::general_purpose::STANDARD_NO_PAD}; @@ -120,11 +122,13 @@ impl ErrorResponse { .error .as_mut() .map(|error| std::mem::take(&mut error.message)) - .or(Some(self.code)), + .or(Some(self.code.clone())) + .map(Cow::from), message: self .error .as_mut() - .map(|error| std::mem::take(&mut error.details)), + .map(|error| std::mem::take(&mut error.details)) + .map(Cow::from), } } } diff --git a/src/core/middleware/auth.rs b/src/core/middleware/auth.rs index 2be79c5..ace29a4 100644 --- a/src/core/middleware/auth.rs +++ b/src/core/middleware/auth.rs @@ -27,19 +27,3 @@ pub async fn admin_auth_middleware(request: Request, next: Next) -> Respon .into_response(), } } - -// 旧的认证中间件函数,保留向后兼容性 -// pub async fn auth_middleware(request: Request, next: Next) -> Result { -// let auth_header = request -// .headers() -// .get(AUTHORIZATION) -// .and_then(|h| h.to_str().ok()) -// .and_then(|h| h.strip_prefix(AUTHORIZATION_BEARER_PREFIX)) -// .ok_or(StatusCode::UNAUTHORIZED)?; - -// if auth_header != AUTH_TOKEN.as_str() { -// return Err(StatusCode::UNAUTHORIZED); -// } - -// Ok(next.run(request).await) -// } diff --git a/src/core/model.rs b/src/core/model.rs index e834f8e..6d0778e 100644 --- a/src/core/model.rs +++ b/src/core/model.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use serde::{Deserialize, Serialize}; +use serde::{ser::SerializeStruct as _, Deserialize, Serialize}; #[derive(Serialize, Deserialize)] #[serde(untagged)] @@ -117,14 +117,33 @@ pub struct StreamOptions { } // 模型定义 -#[derive(Serialize)] pub struct Model { pub id: &'static str, + pub display_name: &'static str, pub created: &'static i64, pub object: &'static str, pub owned_by: &'static str, } +impl Serialize for Model { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut state = serializer.serialize_struct("Model", 7)?; + + state.serialize_field("id", &self.id)?; + state.serialize_field("display_name", &self.display_name)?; + state.serialize_field("created", self.created)?; + state.serialize_field("created_at", self.created)?; + state.serialize_field("object", &self.object)?; + state.serialize_field("type", &self.object)?; + state.serialize_field("owned_by", &self.owned_by)?; + + state.end() + } +} + impl PartialEq for Model { fn eq(&self, other: &Self) -> bool { self.id == other.id diff --git a/src/core/route.rs b/src/core/route.rs index ce581a7..6e2c722 100644 --- a/src/core/route.rs +++ b/src/core/route.rs @@ -7,17 +7,17 @@ pub use token::{handle_basic_calibration, handle_build_key}; mod tokens; pub use tokens::{ handle_add_tokens, handle_delete_tokens, handle_get_token_tags, handle_get_tokens, - handle_get_tokens_by_tag, handle_update_token_tags, handle_update_tokens, - handle_update_tokens_profile, + handle_get_tokens_by_tag, handle_set_token_tags, handle_set_tokens, handle_set_tokens_status, + handle_update_tokens_profile, handle_upgrade_tokens, }; mod checksum; pub use checksum::{handle_get_checksum, handle_get_hash, handle_get_timestamp_header}; mod profile; -pub use profile::handle_user_info; +pub use profile::{handle_token_upgrade, handle_user_info}; mod proxies; pub use proxies::{ handle_add_proxy, handle_delete_proxies, handle_get_proxies, handle_set_general_proxy, - handle_update_proxies, + handle_set_proxies, }; mod page; pub use page::{ diff --git a/src/core/route/health.rs b/src/core/route/health.rs index ab50de8..a86f970 100644 --- a/src/core/route/health.rs +++ b/src/core/route/health.rs @@ -7,13 +7,16 @@ use crate::{ ROUTE_ENV_EXAMPLE_PATH, ROUTE_GET_CHECKSUM, ROUTE_GET_HASH, ROUTE_GET_TIMESTAMP_HEADER, ROUTE_HEALTH_PATH, ROUTE_LOGS_PATH, ROUTE_PROXIES_ADD_PATH, ROUTE_PROXIES_DELETE_PATH, ROUTE_PROXIES_GET_PATH, ROUTE_PROXIES_PATH, ROUTE_PROXIES_SET_GENERAL_PATH, - ROUTE_PROXIES_UPDATE_PATH, ROUTE_README_PATH, ROUTE_ROOT_PATH, ROUTE_STATIC_PATH, - ROUTE_TOKENS_ADD_PATH, ROUTE_TOKENS_BY_TAG_GET_PATH, ROUTE_TOKENS_DELETE_PATH, - ROUTE_TOKENS_GET_PATH, ROUTE_TOKENS_PATH, ROUTE_TOKENS_PROFILE_UPDATE_PATH, - ROUTE_TOKENS_TAGS_GET_PATH, ROUTE_TOKENS_TAGS_UPDATE_PATH, ROUTE_TOKENS_UPDATE_PATH, + ROUTE_PROXIES_SET_PATH, ROUTE_README_PATH, ROUTE_ROOT_PATH, ROUTE_STATIC_PATH, + ROUTE_TOKEN_UPGRADE_PATH, ROUTE_TOKENS_ADD_PATH, ROUTE_TOKENS_BY_TAG_GET_PATH, + ROUTE_TOKENS_DELETE_PATH, ROUTE_TOKENS_GET_PATH, ROUTE_TOKENS_PATH, + ROUTE_TOKENS_PROFILE_UPDATE_PATH, ROUTE_TOKENS_SET_PATH, ROUTE_TOKENS_STATUS_SET_PATH, + ROUTE_TOKENS_TAGS_GET_PATH, ROUTE_TOKENS_TAGS_SET_PATH, ROUTE_TOKENS_UPGRADE_PATH, ROUTE_USER_INFO_PATH, }, - lazy::{AUTH_TOKEN, ROUTE_CHAT_PATH, ROUTE_MODELS_PATH, get_start_time}, + lazy::{ + AUTH_TOKEN, ROUTE_CHAT_PATH, ROUTE_MESSAGES_PATH, ROUTE_MODELS_PATH, get_start_time, + }, model::{AppConfig, AppState, PageContent}, }, common::model::{ @@ -55,6 +58,45 @@ pub async fn handle_root() -> impl IntoResponse { } } +static ENDPOINTS: std::sync::LazyLock<[&'static str; 34]> = std::sync::LazyLock::new(|| { + [ + &*ROUTE_CHAT_PATH, + &*ROUTE_MESSAGES_PATH, + &*ROUTE_MODELS_PATH, + ROUTE_TOKENS_PATH, + ROUTE_TOKENS_GET_PATH, + ROUTE_TOKENS_SET_PATH, + ROUTE_TOKENS_ADD_PATH, + ROUTE_TOKENS_DELETE_PATH, + ROUTE_TOKENS_TAGS_GET_PATH, + ROUTE_TOKENS_TAGS_SET_PATH, + ROUTE_TOKENS_BY_TAG_GET_PATH, + ROUTE_TOKENS_PROFILE_UPDATE_PATH, + ROUTE_TOKENS_UPGRADE_PATH, + ROUTE_TOKENS_STATUS_SET_PATH, + ROUTE_PROXIES_PATH, + ROUTE_PROXIES_GET_PATH, + ROUTE_PROXIES_SET_PATH, + ROUTE_PROXIES_ADD_PATH, + ROUTE_PROXIES_DELETE_PATH, + ROUTE_PROXIES_SET_GENERAL_PATH, + ROUTE_LOGS_PATH, + ROUTE_ENV_EXAMPLE_PATH, + ROUTE_CONFIG_PATH, + ROUTE_STATIC_PATH, + ROUTE_ABOUT_PATH, + ROUTE_README_PATH, + ROUTE_API_PATH, + ROUTE_GET_HASH, + ROUTE_GET_CHECKSUM, + ROUTE_GET_TIMESTAMP_HEADER, + ROUTE_BASIC_CALIBRATION_PATH, + ROUTE_USER_INFO_PATH, + ROUTE_BUILD_KEY_PATH, + ROUTE_TOKEN_UPGRADE_PATH, + ] +}); + pub async fn handle_health( State(state): State>>, headers: HeaderMap, @@ -116,37 +158,6 @@ pub async fn handle_health( uptime, stats, models: Models::ids(), - endpoints: vec![ - ROUTE_CHAT_PATH.as_str(), - ROUTE_MODELS_PATH.as_str(), - ROUTE_TOKENS_PATH, - ROUTE_TOKENS_GET_PATH, - ROUTE_TOKENS_UPDATE_PATH, - ROUTE_TOKENS_ADD_PATH, - ROUTE_TOKENS_DELETE_PATH, - ROUTE_TOKENS_TAGS_GET_PATH, - ROUTE_TOKENS_TAGS_UPDATE_PATH, - ROUTE_TOKENS_BY_TAG_GET_PATH, - ROUTE_TOKENS_PROFILE_UPDATE_PATH, - ROUTE_PROXIES_PATH, - ROUTE_PROXIES_GET_PATH, - ROUTE_PROXIES_UPDATE_PATH, - ROUTE_PROXIES_ADD_PATH, - ROUTE_PROXIES_DELETE_PATH, - ROUTE_PROXIES_SET_GENERAL_PATH, - ROUTE_LOGS_PATH, - ROUTE_ENV_EXAMPLE_PATH, - ROUTE_CONFIG_PATH, - ROUTE_STATIC_PATH, - ROUTE_ABOUT_PATH, - ROUTE_README_PATH, - ROUTE_API_PATH, - ROUTE_GET_HASH, - ROUTE_GET_CHECKSUM, - ROUTE_GET_TIMESTAMP_HEADER, - ROUTE_BASIC_CALIBRATION_PATH, - ROUTE_USER_INFO_PATH, - ROUTE_BUILD_KEY_PATH, - ], + endpoints: &*ENDPOINTS, }) } diff --git a/src/core/route/profile.rs b/src/core/route/profile.rs index 451a61d..6832c71 100644 --- a/src/core/route/profile.rs +++ b/src/core/route/profile.rs @@ -1,8 +1,8 @@ use crate::{ app::model::proxy_pool::ProxyPool, common::{ - model::userinfo::GetUserInfo, - utils::{extract_token, get_token_profile}, + model::{ApiStatus, userinfo::GetUserInfo}, + utils::{extract_token, get_new_token, get_token_profile}, }, core::constant::ERR_NODATA, }; @@ -36,3 +36,49 @@ pub async fn handle_user_info(Json(request): Json) -> Json, +} + +pub async fn handle_token_upgrade(Json(request): Json) -> Json { + // 从请求头中获取并验证 auth token + let auth_token = match request.token { + Some(token) => token, + None => { + return Json(TokenUpgradeResponse { + status: ApiStatus::Error, + message: "未提供授权令牌", + result: None, + }); + } + }; + + let token = match extract_token(&auth_token) { + Some(token) => token, + None => { + return Json(TokenUpgradeResponse { + status: ApiStatus::Error, + message: "无法解析授权令牌", + result: None, + }); + } + }; + + match get_new_token(ProxyPool::get_general_client(), &token, false).await { + Some(token) => Json(TokenUpgradeResponse { + status: ApiStatus::Success, + message: "升级成功", + result: Some(token), + }), + None => Json(TokenUpgradeResponse { + status: ApiStatus::Failure, + message: "升级失败", + result: None, + }), + } +} diff --git a/src/core/route/proxies.rs b/src/core/route/proxies.rs index ebf12ba..ba0861e 100644 --- a/src/core/route/proxies.rs +++ b/src/core/route/proxies.rs @@ -6,7 +6,7 @@ use crate::{ common::model::{ApiStatus, ErrorResponse}, }; use axum::{Json, extract::State, http::StatusCode}; -use std::sync::Arc; +use std::{borrow::Cow, sync::Arc}; use tokio::sync::Mutex; // 获取所有代理配置 @@ -32,7 +32,7 @@ pub async fn handle_get_proxies( } // 更新代理配置 -pub async fn handle_update_proxies( +pub async fn handle_set_proxies( State(state): State>>, Json(request): Json, ) -> Result, (StatusCode, Json)> { @@ -46,8 +46,10 @@ pub async fn handle_update_proxies( Json(ErrorResponse { status: ApiStatus::Error, code: None, - error: Some(format!("Failed to save proxy configuration: {e}")), - message: Some("无法保存代理配置".to_string()), + error: Some(Cow::Owned(format!( + "Failed to save proxy configuration: {e}" + ))), + message: Some(Cow::Borrowed("无法保存代理配置")), }), )); } @@ -109,8 +111,10 @@ pub async fn handle_add_proxy( Json(ErrorResponse { status: ApiStatus::Error, code: None, - error: Some(format!("Failed to save proxy configuration: {e}")), - message: Some("无法保存代理配置".to_string()), + error: Some(Cow::Owned(format!( + "Failed to save proxy configuration: {e}" + ))), + message: Some(Cow::Borrowed("无法保存代理配置")), }), )); } @@ -177,8 +181,10 @@ pub async fn handle_delete_proxies( Json(ErrorResponse { status: ApiStatus::Error, code: None, - error: Some(format!("Failed to save proxy configuration: {e}")), - message: Some("无法保存代理配置".to_string()), + error: Some(Cow::Owned(format!( + "Failed to save proxy configuration: {e}" + ))), + message: Some(Cow::Borrowed("无法保存代理配置")), }), )); } @@ -225,8 +231,8 @@ pub async fn handle_set_general_proxy( Json(ErrorResponse { status: ApiStatus::Error, code: None, - error: Some("Proxy name not found".to_string()), - message: Some("代理名称不存在".to_string()), + error: Some(Cow::Borrowed("Proxy name not found")), + message: Some(Cow::Borrowed("代理名称不存在")), }), )); } @@ -241,8 +247,10 @@ pub async fn handle_set_general_proxy( Json(ErrorResponse { status: ApiStatus::Error, code: None, - error: Some(format!("Failed to save proxy configuration: {e}")), - message: Some("无法保存代理配置".to_string()), + error: Some(Cow::Owned(format!( + "Failed to save proxy configuration: {e}" + ))), + message: Some(Cow::Borrowed("无法保存代理配置")), }), )); } diff --git a/src/core/route/token.rs b/src/core/route/token.rs index 25ccdfc..8ebbd47 100644 --- a/src/core/route/token.rs +++ b/src/core/route/token.rs @@ -7,7 +7,7 @@ use crate::{ common::{ model::ApiStatus, utils::{ - extract_time, extract_time_ks, extract_user_id, to_base64, token_to_tokeninfo, + JwtTime, extract_time, extract_time_ks, extract_user_id, to_base64, token_to_tokeninfo, validate_token_and_checksum, }, }, @@ -28,11 +28,11 @@ pub struct TokenRequest { #[derive(Serialize)] pub struct BasicCalibrationResponse { pub status: ApiStatus, - pub message: Option, + pub message: &'static str, #[serde(skip_serializing_if = "Option::is_none")] pub user_id: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub create_at: Option, + pub time: Option, #[serde(skip_serializing_if = "Option::is_none")] pub checksum_time: Option, } @@ -46,9 +46,9 @@ pub async fn handle_basic_calibration( None => { return Json(BasicCalibrationResponse { status: ApiStatus::Error, - message: Some("未提供授权令牌".to_string()), + message: "未提供授权令牌", user_id: None, - create_at: None, + time: None, checksum_time: None, }); } @@ -60,9 +60,9 @@ pub async fn handle_basic_calibration( None => { return Json(BasicCalibrationResponse { status: ApiStatus::Error, - message: Some("无效令牌或无效校验和".to_string()), + message: "无效令牌或无效校验和", user_id: None, - create_at: None, + time: None, checksum_time: None, }); } @@ -70,15 +70,15 @@ pub async fn handle_basic_calibration( // 提取用户ID和创建时间 let user_id = extract_user_id(&token); - let create_at = extract_time(&token).map(|dt| dt.to_string()); + let time = extract_time(&token); let checksum_time = extract_time_ks(&checksum[..8]); // 返回校验结果 Json(BasicCalibrationResponse { status: ApiStatus::Success, - message: Some("校验成功".to_string()), + message: "校验成功", user_id, - create_at, + time, checksum_time, }) } @@ -94,12 +94,10 @@ pub async fn handle_build_key( .and_then(|h| h.to_str().ok()) .and_then(|h| h.strip_prefix(AUTHORIZATION_BEARER_PREFIX)); - if auth_header - .is_none_or(|h| h != AppConfig::get_share_token().as_str() && h != AUTH_TOKEN.as_str()) - { + if auth_header.is_none_or(|h| !AppConfig::share_token_eq(h) && h != AUTH_TOKEN.as_str()) { return ( StatusCode::UNAUTHORIZED, - Json(BuildKeyResponse::Error("Unauthorized".to_owned())), + Json(BuildKeyResponse::Error("Unauthorized")), ); } } @@ -110,7 +108,7 @@ pub async fn handle_build_key( None => { return ( StatusCode::BAD_REQUEST, - Json(BuildKeyResponse::Error("Invalid auth token".to_owned())), + Json(BuildKeyResponse::Error("Invalid auth token")), ); } }; diff --git a/src/core/route/tokens.rs b/src/core/route/tokens.rs index a93f4e0..49bcfeb 100644 --- a/src/core/route/tokens.rs +++ b/src/core/route/tokens.rs @@ -1,7 +1,8 @@ use crate::{ app::model::{ AppState, CommonResponse, TokenAddRequest, TokenInfo, TokenInfoResponse, TokenManager, - TokenTagsUpdateRequest, TokenUpdateRequest, TokensDeleteRequest, TokensDeleteResponse, + TokenStatusSetRequest, TokenTagsUpdateRequest, TokenUpdateRequest, TokensDeleteRequest, + TokensDeleteResponse, }, common::{ model::{ApiStatus, ErrorResponse, NormalResponse}, @@ -12,7 +13,7 @@ use crate::{ }, }; use axum::{Json, extract::State, http::StatusCode}; -use std::sync::Arc; +use std::{borrow::Cow, collections::HashSet, sync::Arc}; use tokio::sync::Mutex; pub async fn handle_get_tokens( @@ -30,7 +31,7 @@ pub async fn handle_get_tokens( })) } -pub async fn handle_update_tokens( +pub async fn handle_set_tokens( State(state): State>>, Json(tokens): Json, ) -> Result, StatusCode> { @@ -44,7 +45,7 @@ pub async fn handle_update_tokens( .await .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; - // 更新应用状态 + // 设置应用状态 { let mut state = state.lock().await; state.token_manager = token_manager; @@ -87,6 +88,7 @@ pub async fn handle_add_tokens( .as_deref() .map(generate_checksum_with_repair) .unwrap_or_else(generate_checksum_with_default), + status: request.status, client_key: Some(generate_hash()), profile: None, tags: request.tags.clone(), @@ -100,7 +102,7 @@ pub async fn handle_add_tokens( token_manager.tokens.extend(new_tokens); let tokens_count = token_manager.tokens.len(); - // 更新全局标签 + // 设置全局标签 if let Some(ref tags) = request.tags { token_manager.update_global_tags(tags); } @@ -112,13 +114,13 @@ pub async fn handle_add_tokens( Json(ErrorResponse { status: ApiStatus::Error, code: None, - error: Some("Failed to save token list".to_string()), - message: Some("无法保存token list".to_string()), + error: Some(Cow::Borrowed("Failed to save token list")), + message: Some(Cow::Borrowed("无法保存token list")), }), ) })?; - // 更新应用状态 + // 设置应用状态 { let mut state = state.lock().await; state.token_manager = token_manager; @@ -184,7 +186,7 @@ pub async fn handle_delete_tokens( let new_count: usize = token_manager.tokens.len(); - // 如果有tokens被删除才进行更新操作 + // 如果有tokens被删除才进行设置操作 if new_count < original_count { // 保存到文件 token_manager.save_tokens().await.map_err(|_| { @@ -193,8 +195,8 @@ pub async fn handle_delete_tokens( Json(ErrorResponse { status: ApiStatus::Error, code: None, - error: Some("Failed to save token list".to_string()), - message: Some("无法保存token list".to_string()), + error: Some(Cow::Borrowed("Failed to save token list")), + message: Some(Cow::Borrowed("无法保存token list")), }), ) })?; @@ -212,7 +214,7 @@ pub async fn handle_delete_tokens( None }; - // 更新状态 + // 设置状态 { let mut state = state.lock().await; state.token_manager = token_manager; @@ -243,24 +245,24 @@ pub async fn handle_delete_tokens( } } -pub async fn handle_update_token_tags( +pub async fn handle_set_token_tags( State(state): State>>, Json(request): Json, ) -> Result, (StatusCode, Json)> { - // 获取并更新 token_manager + // 获取并设置 token_manager { let mut state = state.lock().await; if let Err(e) = state .token_manager - .update_tokens_tags(request.tokens, request.tags) + .update_tokens_tags(&request.tokens, request.tags) { return Err(( StatusCode::BAD_REQUEST, Json(ErrorResponse { status: ApiStatus::Error, code: None, - error: Some(e.to_string()), - message: Some("更新标签失败".to_string()), + error: Some(Cow::Owned(e.to_string())), + message: Some(Cow::Borrowed("设置标签失败")), }), )); } @@ -272,8 +274,8 @@ pub async fn handle_update_token_tags( Json(ErrorResponse { status: ApiStatus::Error, code: None, - error: Some("Failed to save token tags".to_string()), - message: Some("无法保存标签信息".to_string()), + error: Some(Cow::Borrowed("Failed to save token tags")), + message: Some(Cow::Borrowed("无法保存标签信息")), }), )); } @@ -281,13 +283,13 @@ pub async fn handle_update_token_tags( Ok(Json(CommonResponse { status: ApiStatus::Success, - message: Some("标签更新成功".to_string()), + message: Some("标签设置成功".to_string()), })) } pub async fn handle_update_tokens_profile( State(state): State>>, - Json(tokens): Json>, + Json(tokens): Json>, ) -> Result, (StatusCode, Json)> { // 验证请求 if tokens.is_empty() { @@ -296,8 +298,8 @@ pub async fn handle_update_tokens_profile( Json(ErrorResponse { status: ApiStatus::Error, code: None, - error: Some("No tokens provided".to_string()), - message: Some("未提供任何令牌".to_string()), + error: Some(Cow::Borrowed("No tokens provided")), + message: Some(Cow::Borrowed("未提供任何令牌")), }), )); } @@ -306,7 +308,7 @@ pub async fn handle_update_tokens_profile( let mut state_guard = state.lock().await; let token_manager = &mut state_guard.token_manager; - // 批量更新tokens的profile + // 批量设置tokens的profile let mut updated_count: u32 = 0; let mut failed_count: u32 = 0; @@ -325,7 +327,7 @@ pub async fn handle_update_tokens_profile( ) .await { - // 更新profile + // 设置profile token_manager.tokens[token_idx].profile = Some(profile); updated_count += 1; } else { @@ -343,8 +345,8 @@ pub async fn handle_update_tokens_profile( Json(ErrorResponse { status: ApiStatus::Error, code: None, - error: Some("Failed to save token profiles".to_string()), - message: Some("无法保存令牌配置数据".to_string()), + error: Some(Cow::Borrowed("Failed to save token profiles")), + message: Some(Cow::Borrowed("无法保存令牌配置数据")), }), )); } @@ -357,6 +359,135 @@ pub async fn handle_update_tokens_profile( })) } +pub async fn handle_upgrade_tokens( + State(state): State>>, + Json(tokens): Json>, +) -> Result, (StatusCode, Json)> { + // 验证请求 + if tokens.is_empty() { + return Err(( + StatusCode::BAD_REQUEST, + Json(ErrorResponse { + status: ApiStatus::Error, + code: None, + error: Some(Cow::Borrowed("No tokens provided")), + message: Some(Cow::Borrowed("未提供任何令牌")), + }), + )); + } + + // 获取当前的 token_manager + let mut state_guard = state.lock().await; + let token_manager = &mut state_guard.token_manager; + + // 批量设置tokens的profile + let mut updated_count: u32 = 0; + let mut failed_count: u32 = 0; + + for token in &tokens { + if let Some(token_idx) = token_manager + .tokens + .iter() + .position(|info| info.token == *token) + { + if let Some(new_token) = crate::common::utils::get_new_token( + token_manager.tokens[token_idx].get_client(), + token, + true, + ) + .await + { + token_manager.tokens[token_idx].token = new_token; + updated_count += 1; + } else { + failed_count += 1; + } + } else { + failed_count += 1; + } + } + + // 保存更改 + if updated_count > 0 && token_manager.save_tokens().await.is_err() { + return Err(( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ErrorResponse { + status: ApiStatus::Error, + code: None, + error: Some(Cow::Borrowed("Failed to save tokens")), + message: Some(Cow::Borrowed("无法保存令牌数据")), + }), + )); + } + + let message = format!("已升级{updated_count}个令牌, {failed_count}个令牌升级失败"); + + Ok(Json(CommonResponse { + status: ApiStatus::Success, + message: Some(message), + })) +} + +pub async fn handle_set_tokens_status( + State(state): State>>, + Json(request): Json, +) -> Result, (StatusCode, Json)> { + // 验证请求 + if request.tokens.is_empty() { + return Err(( + StatusCode::BAD_REQUEST, + Json(ErrorResponse { + status: ApiStatus::Error, + code: None, + error: Some(Cow::Borrowed("No tokens provided")), + message: Some(Cow::Borrowed("未提供任何令牌")), + }), + )); + } + + // 获取当前的 token_manager + let mut state_guard = state.lock().await; + let token_manager = &mut state_guard.token_manager; + + // 批量设置tokens的profile + let mut updated_count: u32 = 0; + let mut failed_count: u32 = 0; + + for token in &request.tokens { + // 验证token是否在token_manager中存在 + if let Some(token_idx) = token_manager + .tokens + .iter() + .position(|info| info.token == *token) + { + token_manager.tokens[token_idx].status = request.status; + updated_count += 1; + } else { + failed_count += 1; + } + } + + // 保存更改 + if updated_count > 0 && token_manager.save_tokens().await.is_err() { + return Err(( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ErrorResponse { + status: ApiStatus::Error, + code: None, + error: Some(Cow::Borrowed("Failed to save token statuses")), + message: Some(Cow::Borrowed("无法保存令牌状态数据")), + }), + )); + } + + let message = format!("已设置{updated_count}个令牌状态, {failed_count}个令牌设置失败"); + + Ok(Json(CommonResponse { + status: ApiStatus::Success, + message: Some(message), + })) +} + pub async fn handle_get_token_tags( State(state): State>>, ) -> Result>>, StatusCode> { @@ -367,7 +498,7 @@ pub async fn handle_get_token_tags( Ok(Json(NormalResponse { status: ApiStatus::Success, data: Some(tags), - message: Some(format!("获取到{len}个标签")), + message: Some(Cow::Owned(format!("获取到{len}个标签"))), })) } @@ -397,8 +528,8 @@ pub async fn handle_get_tokens_by_tag( Json(ErrorResponse { status: ApiStatus::Error, code: None, - error: Some(e.to_string()), - message: Some(format!("标签\"{tag}\"不存在")), + error: Some(Cow::Owned(e.to_string())), + message: Some(Cow::Owned(format!("标签\"{tag}\"不存在"))), }), )), } diff --git a/src/core/service.rs b/src/core/service.rs index 34ae4dd..cd8ffd8 100644 --- a/src/core/service.rs +++ b/src/core/service.rs @@ -51,7 +51,7 @@ use axum::{ use bytes::Bytes; use futures::StreamExt; use prost::Message as _; -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::{borrow::Cow, sync::atomic::{AtomicUsize, Ordering}}; use std::{ convert::Infallible, sync::{Arc, atomic::AtomicBool}, @@ -63,6 +63,8 @@ use super::model::{ChatRequest, Model}; const NO_CACHE: &str = "no-cache, must-revalidate"; const KEEP_ALIVE: &str = "keep-alive"; +static CURRENT_KEY_INDEX: AtomicUsize = AtomicUsize::new(0); + pub async fn handle_models( State(state): State>>, headers: HeaderMap, @@ -87,10 +89,15 @@ pub async fn handle_models( // 管理员Token token if token == AUTH_TOKEN.as_str() - || (AppConfig::is_share() && token == AppConfig::get_share_token().as_str()) => + || (AppConfig::is_share() && AppConfig::share_token_eq(token)) => { let state_guard = state.lock().await; - let token_infos = &state_guard.token_manager.tokens; + let token_infos: Vec<_> = state_guard + .token_manager + .tokens + .iter() + .filter(|t| t.is_enabled()) + .collect(); if token_infos.is_empty() { return Err(( @@ -99,7 +106,6 @@ pub async fn handle_models( )); } - static CURRENT_KEY_INDEX: AtomicUsize = AtomicUsize::new(0); let index = CURRENT_KEY_INDEX.fetch_add(1, Ordering::SeqCst) % token_infos.len(); let token_info = &token_infos[index]; is_pri = true; @@ -152,8 +158,8 @@ pub async fn handle_models( Json(ErrorResponse { status: ApiStatus::Failure, code: Some(StatusCode::INTERNAL_SERVER_ERROR.as_u16()), - error: Some("Failed to fetch available models".to_string()), - message: Some("Unable to get available models".to_string()), + error: Some(Cow::Borrowed("Failed to fetch available models")), + message: Some(Cow::Borrowed("Unable to get available models")), }), ))?; @@ -164,8 +170,8 @@ pub async fn handle_models( Json(ErrorResponse { status: ApiStatus::Failure, code: Some(StatusCode::INTERNAL_SERVER_ERROR.as_u16()), - error: Some("Failed to update models".to_string()), - message: Some(e.to_string()), + error: Some(Cow::Borrowed("Failed to update models")), + message: Some(Cow::Borrowed(e)), }), ) })?; @@ -223,15 +229,20 @@ pub async fn handle_chat( let mut is_pri = false; // 验证认证token并获取token信息 + let mut now_with_tz = None; let (auth_token, checksum, client_key, client, timezone) = match auth_header { // 管理员Token验证逻辑 token if token == AUTH_TOKEN.as_str() - || (AppConfig::is_share() && token == AppConfig::get_share_token().as_str()) => + || (AppConfig::is_share() && AppConfig::share_token_eq(token)) => { - static CURRENT_KEY_INDEX: AtomicUsize = AtomicUsize::new(0); let state_guard = state.lock().await; - let token_infos = &state_guard.token_manager.tokens; + let token_infos: Vec<_> = state_guard + .token_manager + .tokens + .iter() + .filter(|t| t.is_enabled()) + .collect(); // 检查是否存在可用的token if token_infos.is_empty() { @@ -245,6 +256,7 @@ pub async fn handle_chat( let index = CURRENT_KEY_INDEX.fetch_add(1, Ordering::SeqCst) % token_infos.len(); let token_info = &token_infos[index]; is_pri = true; + now_with_tz = Some(token_info.now()); ( token_info.token.clone(), token_info.checksum.clone(), @@ -393,6 +405,7 @@ pub async fn handle_chat( token_info: TokenInfo { token: auth_token.clone(), checksum: checksum.clone(), + status: Default::default(), client_key: None, profile: None, tags: None, @@ -416,6 +429,7 @@ pub async fn handle_chat( // 将消息转换为hex格式 let hex_data = match super::adapter::encode_chat_message( request.messages, + now_with_tz, model, current_config.disable_vision(), current_config.enable_slow_pool(), @@ -1048,7 +1062,7 @@ pub async fn handle_chat( let error_response = ErrorResponse { status: ApiStatus::Error, code: Some(500), - error: Some(e.to_string()), + error: Some(Cow::Owned(e.to_string())), message: None, }; return Err((StatusCode::INTERNAL_SERVER_ERROR, Json(error_response))); diff --git a/src/core/stream/decoder.rs b/src/core/stream/decoder.rs index dbc8d8d..951d851 100644 --- a/src/core/stream/decoder.rs +++ b/src/core/stream/decoder.rs @@ -11,6 +11,14 @@ use std::time::Instant; // 解压gzip数据 #[inline] fn decompress_gzip(data: &[u8]) -> Option> { + if data.len() < 3 + || unsafe { *data.get_unchecked(0) } != 0x1f + || unsafe { *data.get_unchecked(1) } != 0x8b + || unsafe { *data.get_unchecked(2) } != 0x08 + { + return None; + } + let mut decoder = GzDecoder::new(data); let mut decompressed = Vec::new(); diff --git a/src/main.rs b/src/main.rs index 80ec3c5..cf9ce78 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,11 +10,12 @@ use app::{ ROUTE_BUILD_KEY_PATH, ROUTE_CONFIG_PATH, ROUTE_ENV_EXAMPLE_PATH, ROUTE_GET_CHECKSUM, ROUTE_GET_HASH, ROUTE_GET_TIMESTAMP_HEADER, ROUTE_HEALTH_PATH, ROUTE_LOGS_PATH, ROUTE_PROXIES_ADD_PATH, ROUTE_PROXIES_DELETE_PATH, ROUTE_PROXIES_GET_PATH, - ROUTE_PROXIES_PATH, ROUTE_PROXIES_SET_GENERAL_PATH, ROUTE_PROXIES_UPDATE_PATH, - ROUTE_README_PATH, ROUTE_ROOT_PATH, ROUTE_STATIC_PATH, ROUTE_TOKENS_ADD_PATH, - ROUTE_TOKENS_BY_TAG_GET_PATH, ROUTE_TOKENS_DELETE_PATH, ROUTE_TOKENS_GET_PATH, - ROUTE_TOKENS_PATH, ROUTE_TOKENS_PROFILE_UPDATE_PATH, ROUTE_TOKENS_TAGS_GET_PATH, - ROUTE_TOKENS_TAGS_UPDATE_PATH, ROUTE_TOKENS_UPDATE_PATH, ROUTE_USER_INFO_PATH, + ROUTE_PROXIES_PATH, ROUTE_PROXIES_SET_GENERAL_PATH, ROUTE_PROXIES_SET_PATH, + ROUTE_README_PATH, ROUTE_ROOT_PATH, ROUTE_STATIC_PATH, ROUTE_TOKEN_UPGRADE_PATH, + ROUTE_TOKENS_ADD_PATH, ROUTE_TOKENS_BY_TAG_GET_PATH, ROUTE_TOKENS_DELETE_PATH, + ROUTE_TOKENS_GET_PATH, ROUTE_TOKENS_PATH, ROUTE_TOKENS_PROFILE_UPDATE_PATH, + ROUTE_TOKENS_SET_PATH, ROUTE_TOKENS_STATUS_SET_PATH, ROUTE_TOKENS_TAGS_GET_PATH, + ROUTE_TOKENS_TAGS_SET_PATH, ROUTE_TOKENS_UPGRADE_PATH, ROUTE_USER_INFO_PATH, }, lazy::{AUTH_TOKEN, ROUTE_CHAT_PATH, ROUTE_MODELS_PATH}, model::*, @@ -32,9 +33,10 @@ use core::{ handle_delete_proxies, handle_delete_tokens, handle_env_example, handle_get_checksum, handle_get_hash, handle_get_proxies, handle_get_timestamp_header, handle_get_token_tags, handle_get_tokens, handle_get_tokens_by_tag, handle_health, handle_logs, handle_logs_post, - handle_proxies_page, handle_readme, handle_root, handle_set_general_proxy, handle_static, - handle_tokens_page, handle_update_proxies, handle_update_token_tags, handle_update_tokens, - handle_update_tokens_profile, handle_user_info, + handle_proxies_page, handle_readme, handle_root, handle_set_general_proxy, + handle_set_proxies, handle_set_token_tags, handle_set_tokens, handle_set_tokens_status, + handle_static, handle_token_upgrade, handle_tokens_page, handle_update_tokens_profile, + handle_upgrade_tokens, handle_user_info, }, service::{handle_chat, handle_models}, }; @@ -80,10 +82,7 @@ async fn main() { tokio::spawn(async move { loop { // 获取当前时间戳 - let now = std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .as_secs(); + let now = common::utils::now_secs(); // 计算距离下一个整1000秒的等待时间 let next_reload = (now / 1000 + 1) * 1000; @@ -152,21 +151,20 @@ async fn main() { .merge( Router::new() .route(ROUTE_TOKENS_GET_PATH, post(handle_get_tokens)) - .route(ROUTE_TOKENS_UPDATE_PATH, post(handle_update_tokens)) + .route(ROUTE_TOKENS_SET_PATH, post(handle_set_tokens)) .route(ROUTE_TOKENS_ADD_PATH, post(handle_add_tokens)) .route(ROUTE_TOKENS_DELETE_PATH, post(handle_delete_tokens)) .route(ROUTE_TOKENS_TAGS_GET_PATH, post(handle_get_token_tags)) - .route( - ROUTE_TOKENS_TAGS_UPDATE_PATH, - post(handle_update_token_tags), - ) + .route(ROUTE_TOKENS_TAGS_SET_PATH, post(handle_set_token_tags)) .route(ROUTE_TOKENS_BY_TAG_GET_PATH, post(handle_get_tokens_by_tag)) .route( ROUTE_TOKENS_PROFILE_UPDATE_PATH, post(handle_update_tokens_profile), ) + .route(ROUTE_TOKENS_UPGRADE_PATH, post(handle_upgrade_tokens)) + .route(ROUTE_TOKENS_STATUS_SET_PATH, post(handle_set_tokens_status)) .route(ROUTE_PROXIES_GET_PATH, post(handle_get_proxies)) - .route(ROUTE_PROXIES_UPDATE_PATH, post(handle_update_proxies)) + .route(ROUTE_PROXIES_SET_PATH, post(handle_set_proxies)) .route(ROUTE_PROXIES_ADD_PATH, post(handle_add_proxy)) .route(ROUTE_PROXIES_DELETE_PATH, post(handle_delete_proxies)) .route( @@ -177,6 +175,7 @@ async fn main() { ) .route(ROUTE_MODELS_PATH.as_str(), get(handle_models)) .route(ROUTE_CHAT_PATH.as_str(), post(handle_chat)) + // .route(ROUTE_MESSAGES_PATH.as_str(), post(handle_chat)) .route(ROUTE_LOGS_PATH, get(handle_logs)) .route(ROUTE_LOGS_PATH, post(handle_logs_post)) .route(ROUTE_ENV_EXAMPLE_PATH, get(handle_env_example)) @@ -193,6 +192,7 @@ async fn main() { .route(ROUTE_USER_INFO_PATH, post(handle_user_info)) .route(ROUTE_BUILD_KEY_PATH, get(handle_build_key_page)) .route(ROUTE_BUILD_KEY_PATH, post(handle_build_key)) + .route(ROUTE_TOKEN_UPGRADE_PATH, post(handle_token_upgrade)) .layer(RequestBodyLimitLayer::new( 1024 * 1024 * parse_usize_from_env("REQUEST_BODY_LIMIT_MB", 2), )) diff --git a/static/api.html b/static/api.html index 850ed6d..ceccd81 100644 --- a/static/api.html +++ b/static/api.html @@ -267,7 +267,7 @@ // 缓存校准结果 calibrationCache.set(token, { user_id: result.user_id, - create_at: result.create_at, + time: result.time, checksum_time: result.checksum_time }); @@ -317,7 +317,7 @@ // 添加用户基本信息 if (tokenInfo.user || calibInfo) { const user = tokenInfo.user || {}; - userDetails.innerHTML += `

用户ID: ${calibInfo ? calibInfo.user_id : user.id}

邮箱: ${user.email || ''}

用户名: ${user.name || ''}

${user.updated_at ? `

更新时间: ${new Date(user.updated_at).toLocaleString()}

` : ''}${calibInfo ? `

令牌创建时间: ${new Date(calibInfo.create_at).toLocaleString()}

` : ''}${calibInfo && calibInfo.checksum_time ? `

校验和时间区间: ${new Date(calibInfo.checksum_time * 1e6).toLocaleString()} - ${new Date((calibInfo.checksum_time + 1) * 1e6 - 1).toLocaleString()}

` : ''}`; + userDetails.innerHTML += `

用户ID: ${calibInfo ? calibInfo.user_id : user.id}

邮箱: ${user.email || ''}

用户名: ${user.name || ''}

${user.updated_at ? `

更新时间: ${new Date(user.updated_at).toLocaleString()}

` : ''}${calibInfo ? `

令牌创建时间: ${new Date(calibInfo.time.iat).toLocaleString()}

` : ''}${calibInfo ? `

令牌过期时间: ${new Date(calibInfo.time.exp).toLocaleString()}

` : ''}${calibInfo && calibInfo.checksum_time ? `

校验和时间区间: ${new Date(calibInfo.checksum_time * 1e6).toLocaleString()} - ${new Date((calibInfo.checksum_time + 1) * 1e6 - 1).toLocaleString()}

` : ''}`; } // 添加 Stripe 会员信息 diff --git a/static/logs.html b/static/logs.html index 296b56f..713a89d 100644 --- a/static/logs.html +++ b/static/logs.html @@ -846,7 +846,7 @@ return; } - const data = await makeAuthenticatedRequest('/tokens/delete', { + const data = await makeAuthenticatedRequest('/tokens/del', { method: 'POST', body: JSON.stringify({ tokens: [currentToken], @@ -861,8 +861,6 @@ message = 'Token删除失败:未找到该Token'; } showGlobalMessage(message); - // 刷新日志列表 - fetchLogs(); } }; @@ -1070,7 +1068,7 @@ ${formatTiming(log.timing.total)} ${log.stream ? '是' : '否'} ${log.status} - ${log.error || '-'} + ${log.error.details || log.error || '-'} `; }).join(''); diff --git a/static/proxies.html b/static/proxies.html index c208ae1..d57c438 100644 --- a/static/proxies.html +++ b/static/proxies.html @@ -1020,7 +1020,7 @@ closeModal('confirmModal'); showToast('正在删除代理...', 'info'); - const data = await makeAuthenticatedRequest('/proxies/delete', { + const data = await makeAuthenticatedRequest('/proxies/del', { body: JSON.stringify({ names: proxiesToDelete, expectation: 'detailed' @@ -1185,7 +1185,7 @@ closeModal('importModal'); showToast('正在导入代理配置...', 'info'); - const data = await makeAuthenticatedRequest('/proxies/update', { + const data = await makeAuthenticatedRequest('/proxies/set', { body: JSON.stringify({ proxies: config }) diff --git a/static/tokens.html b/static/tokens.html index 4a31778..deeb16c 100644 --- a/static/tokens.html +++ b/static/tokens.html @@ -649,6 +649,74 @@ .proxy-name:hover::after { opacity: 1; } + + /* 状态指示标样式 */ + .status-indicator { + display: inline-block; + width: 8px; + height: 8px; + border-radius: 50%; + margin-right: 5px; + } + + .status-enabled { + background-color: #4CAF50; + /* 绿色 */ + } + + .status-disabled { + background-color: #F44336; + /* 红色 */ + } + + .status-other { + background-color: #FFC107; + /* 黄色 */ + } + + /* 状态子菜单样式 */ + .status-menu { + position: relative; + } + + .status-submenu { + position: absolute; + left: 100%; + top: 0; + background: var(--card-background); + border: 1px solid var(--border-color); + border-radius: var(--border-radius); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); + padding: 4px 0; + min-width: 150px; + z-index: 1001; + opacity: 0; + visibility: hidden; + transition: opacity 0.2s, visibility 0.2s; + } + + .status-menu:hover .status-submenu { + opacity: 1; + visibility: visible; + } + + /* 添加向上和向左打开的样式 */ + .status-menu.open-upward .status-submenu { + top: auto; + bottom: 0; + } + + .status-menu.open-leftward .status-submenu { + left: auto; + right: 100%; + } + + /* 添加状态计数样式 */ + .status-count { + color: var(--text-secondary); + font-size: 12px; + margin-left: 8px; + } @@ -774,6 +842,21 @@
+
+ 切换状态 +
+
+ 启用 + 0 + +
+
+ 禁用 + 0 + +
+
+
查看详情 Enter @@ -782,6 +865,10 @@ 刷新Profile F5
+
+ 升级Token + Ctrl+U +
生成Key Ctrl+G @@ -925,6 +1012,13 @@
+
+ + +