Compare commits
10 Commits
4a8ca4cd22
...
1bc2990aa6
Author | SHA1 | Date |
---|---|---|
|
1bc2990aa6 | |
|
271e628987 | |
|
dbe2d553da | |
|
f126073ce7 | |
|
3ca85a4749 | |
|
e42b952649 | |
|
5144b988cd | |
|
ee5b9739a4 | |
|
5e1226a2b5 | |
|
0eb68e974e |
|
@ -42,13 +42,13 @@ jobs:
|
|||
|
||||
- name: Package artifact
|
||||
run: |
|
||||
mv target/${{ matrix.target_triple }}/release/${{ matrix.artifact_name }} ${{ matrix.release_name }}
|
||||
mv target/${{ matrix.target_triple }}/release/${{ matrix.artifact_name }} ${{ matrix.artifact_name }}
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.release_name }}
|
||||
path: ${{ matrix.release_name }}
|
||||
path: ${{ matrix.artifact_name }}
|
||||
retention-days: 30
|
||||
|
||||
windows:
|
||||
|
@ -71,14 +71,13 @@ jobs:
|
|||
|
||||
- name: Package artifact
|
||||
run: |
|
||||
mkdir -p release-package
|
||||
mv target/${{ matrix.target_triple }}/release/${{ matrix.artifact_name }} ${{ matrix.release_name }}
|
||||
mv target/${{ matrix.target_triple }}/release/${{ matrix.artifact_name }} ${{ matrix.artifact_name }}
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.release_name }}
|
||||
path: ${{ matrix.release_name }}
|
||||
path: ${{ matrix.artifact_name }}
|
||||
retention-days: 30
|
||||
|
||||
macos:
|
||||
|
@ -108,11 +107,11 @@ jobs:
|
|||
|
||||
- name: Package artifact
|
||||
run: |
|
||||
mv target/${{ matrix.target_triple }}/release/${{ matrix.artifact_name }} ${{ matrix.release_name }}
|
||||
mv target/${{ matrix.target_triple }}/release/${{ matrix.artifact_name }} ${{ matrix.artifact_name }}
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.release_name }}
|
||||
path: ${{ matrix.release_name }}
|
||||
path: ${{ matrix.artifact_name }}
|
||||
retention-days: 30
|
||||
|
|
|
@ -177,9 +177,9 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.29"
|
||||
version = "1.2.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362"
|
||||
checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
@ -198,9 +198,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.40"
|
||||
version = "4.5.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f"
|
||||
checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
@ -208,9 +208,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.40"
|
||||
version = "4.5.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e"
|
||||
checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
|
@ -220,9 +220,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.40"
|
||||
version = "4.5.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce"
|
||||
checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
|
@ -404,7 +404,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gemini-keychecker"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"async-stream",
|
||||
"backon",
|
||||
|
@ -419,7 +419,7 @@ dependencies = [
|
|||
"serde_json",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"toml 0.9.5",
|
||||
"toml 0.9.2",
|
||||
"tracing",
|
||||
"tracing-indicatif",
|
||||
"tracing-subscriber",
|
||||
|
@ -581,9 +581,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.14"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb"
|
||||
checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bytes",
|
||||
|
@ -597,7 +597,7 @@ dependencies = [
|
|||
"libc",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"socket2 0.5.10",
|
||||
"socket2 0.6.0",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
|
@ -742,9 +742,9 @@ checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb"
|
|||
|
||||
[[package]]
|
||||
name = "io-uring"
|
||||
version = "0.7.8"
|
||||
version = "0.7.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013"
|
||||
checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
|
@ -1069,9 +1069,9 @@ checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
|||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.1"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
|
||||
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
|
||||
dependencies = [
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
|
@ -1207,9 +1207,9 @@ checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
|||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.23.28"
|
||||
version = "0.23.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643"
|
||||
checksum = "2491382039b29b9b11ff08b76ff6c97cf287671dbb74f0be44bda389fffe9bd1"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"ring",
|
||||
|
@ -1231,9 +1231,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.103.3"
|
||||
version = "0.103.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435"
|
||||
checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
|
@ -1274,9 +1274,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.140"
|
||||
version = "1.0.141"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
|
||||
checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
|
@ -1466,9 +1466,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
|||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.47.0"
|
||||
version = "1.46.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43864ed400b6043a4757a25c7a64a8efde741aed79a056a2fb348a406701bb35"
|
||||
checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
|
@ -1477,9 +1477,9 @@ dependencies = [
|
|||
"mio",
|
||||
"pin-project-lite",
|
||||
"slab",
|
||||
"socket2 0.6.0",
|
||||
"socket2 0.5.10",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1530,9 +1530,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.9.5"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8"
|
||||
checksum = "ed0aee96c12fa71097902e0bb061a5e1ebd766a6636bb605ba401c45c1650eac"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
|
@ -1577,9 +1577,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "toml_parser"
|
||||
version = "1.0.2"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10"
|
||||
checksum = "97200572db069e74c512a14117b296ba0a80a30123fbbb5aa1f4a348f639ca30"
|
||||
dependencies = [
|
||||
"winnow",
|
||||
]
|
||||
|
@ -1675,9 +1675,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tracing-indicatif"
|
||||
version = "0.3.12"
|
||||
version = "0.3.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1983afead46ff13a3c93581e0cec31d20b29efdd22cbdaa8b9f850eccf2c352"
|
||||
checksum = "8c714cc8fc46db04fcfddbd274c6ef59bebb1b435155984e7c6e89c3ce66f200"
|
||||
dependencies = [
|
||||
"indicatif",
|
||||
"tracing",
|
||||
|
@ -1974,12 +1974,6 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
|
@ -2004,7 +1998,7 @@ version = "0.60.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
||||
dependencies = [
|
||||
"windows-targets 0.53.3",
|
||||
"windows-targets 0.53.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2025,11 +2019,10 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.53.3"
|
||||
version = "0.53.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91"
|
||||
checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows_aarch64_gnullvm 0.53.0",
|
||||
"windows_aarch64_msvc 0.53.0",
|
||||
"windows_i686_gnu 0.53.0",
|
||||
|
|
10
Cargo.toml
10
Cargo.toml
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gemini-keychecker"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
|
@ -11,7 +11,7 @@ futures = "0.3"
|
|||
regex = "1.11"
|
||||
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls","http2"] }
|
||||
serde_json = "1.0"
|
||||
tokio = { version = "1.47", features = [
|
||||
tokio = { version = "1.46.1", features = [
|
||||
"macros",
|
||||
"rt-multi-thread",
|
||||
"time",
|
||||
|
@ -21,9 +21,9 @@ url = { version = "2.5", features = ["serde"] }
|
|||
async-stream = "0.3"
|
||||
figment = { version = "0.10", features = ["env", "toml"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
toml = "0.9.5"
|
||||
toml = "0.9"
|
||||
thiserror = "2.0"
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] }
|
||||
tracing-indicatif = "0.3.12"
|
||||
indicatif = "0.18.0"
|
||||
tracing-indicatif = "0.3"
|
||||
indicatif = "0.18"
|
||||
|
|
|
@ -2,4 +2,4 @@ pub mod input;
|
|||
pub mod output;
|
||||
|
||||
pub use input::load_keys_from_txt;
|
||||
pub use output::write_validated_key_to_tier_files;
|
||||
|
||||
|
|
|
@ -1,31 +1,9 @@
|
|||
use crate::error::ValidatorError;
|
||||
use crate::types::{GeminiKey, KeyTier, ValidatedKey};
|
||||
use crate::types::GeminiKey;
|
||||
use std::{fs, io::Write};
|
||||
use tokio::io::{AsyncWriteExt, BufWriter};
|
||||
use toml::Value;
|
||||
use tracing::info;
|
||||
|
||||
// Write valid key to appropriate tier file
|
||||
pub async fn write_validated_key_to_tier_files(
|
||||
free_file: &mut BufWriter<tokio::fs::File>,
|
||||
paid_file: &mut BufWriter<tokio::fs::File>,
|
||||
validated_key: &ValidatedKey,
|
||||
) -> Result<(), ValidatorError> {
|
||||
match validated_key.tier {
|
||||
KeyTier::Free => {
|
||||
free_file
|
||||
.write_all(format!("{}\n", validated_key.key.as_ref()).as_bytes())
|
||||
.await?;
|
||||
}
|
||||
KeyTier::Paid => {
|
||||
paid_file
|
||||
.write_all(format!("{}\n", validated_key.key.as_ref()).as_bytes())
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Write valid key to output file in Clewdr format
|
||||
pub fn write_keys_clewdr_format(
|
||||
file: &mut fs::File,
|
||||
|
|
|
@ -79,6 +79,9 @@ pub struct KeyCheckerConfig {
|
|||
|
||||
#[serde(default)]
|
||||
pub log_level: String,
|
||||
|
||||
#[serde(default)]
|
||||
pub model: String,
|
||||
}
|
||||
|
||||
impl Default for KeyCheckerConfig {
|
||||
|
@ -112,7 +115,9 @@ impl KeyCheckerConfig {
|
|||
/// Returns the complete Gemini API URL for generateContent endpoint
|
||||
pub fn gemini_api_url(&self) -> Url {
|
||||
self.api_host
|
||||
.join("v1beta/models/gemini-2.5-flash-lite:generateContent")
|
||||
.join("v1beta/models/")
|
||||
.join(self.model)
|
||||
.join(":generateContent")
|
||||
.expect("Failed to join API URL")
|
||||
}
|
||||
|
||||
|
@ -162,6 +167,7 @@ static DEFAULT_CONFIG: LazyLock<KeyCheckerConfig> = LazyLock::new(|| KeyCheckerC
|
|||
proxy: None,
|
||||
enable_multiplexing: true,
|
||||
log_level: "info".to_string(),
|
||||
model: "gemini-2.5-flash-lite".to_string(),
|
||||
});
|
||||
|
||||
fn default_api_host() -> Url {
|
||||
|
|
|
@ -21,7 +21,12 @@ async fn main() -> Result<(), ValidatorError> {
|
|||
|
||||
tracing_subscriber::registry()
|
||||
.with(env_filter)
|
||||
.with(tracing_subscriber::fmt::layer().with_writer(indicatif_layer.get_stderr_writer()))
|
||||
.with(
|
||||
tracing_subscriber::fmt::layer()
|
||||
.with_writer(indicatif_layer.get_stderr_writer())
|
||||
.with_level(true)
|
||||
.with_target(false),
|
||||
)
|
||||
.with(indicatif_layer)
|
||||
.init();
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
pub mod http;
|
||||
pub mod writer;
|
||||
|
||||
pub use http::{client_builder, send_request};
|
||||
pub use writer::write_key_into_file;
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
use crate::error::ValidatorError;
|
||||
use crate::types::ValidatedKey;
|
||||
use tokio::io::{AsyncWrite, AsyncWriteExt};
|
||||
|
||||
pub async fn write_key_into_file<W>(
|
||||
writer: &mut W,
|
||||
validated_key: &ValidatedKey,
|
||||
) -> Result<(), ValidatorError>
|
||||
where
|
||||
W: AsyncWrite + Unpin,
|
||||
{
|
||||
writer
|
||||
.write_all(format!("{}\n", validated_key.key.as_ref()).as_bytes())
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
|
@ -12,7 +12,7 @@ pub async fn test_generate_content_api(
|
|||
api_endpoint: impl IntoUrl,
|
||||
api_key: GeminiKey,
|
||||
config: KeyCheckerConfig,
|
||||
) -> Result<ValidatedKey, ValidatorError> {
|
||||
) -> Result<(), ValidatorError> {
|
||||
let api_endpoint = api_endpoint.into_url().unwrap();
|
||||
|
||||
match send_request(
|
||||
|
@ -29,7 +29,7 @@ pub async fn test_generate_content_api(
|
|||
"BASIC API VALID - {}... - Passed generate content API test",
|
||||
&api_key.as_ref()[..10]
|
||||
);
|
||||
Ok(ValidatedKey::new(api_key))
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => match &e {
|
||||
ValidatorError::HttpBadRequest { .. }
|
||||
|
|
|
@ -64,8 +64,10 @@ pub static GENERATE_CONTENT_TEST_BODY: LazyLock<Value> = LazyLock::new(|| {
|
|||
|
||||
// LazyLock for the cached content test body used in cache API validation
|
||||
pub static CACHE_CONTENT_TEST_BODY: LazyLock<GeminiRequest> = LazyLock::new(|| {
|
||||
// Generate random text content to meet the minimum 1024 tokens requirement for cache API
|
||||
let long_text = "You are an expert at analyzing transcripts.".repeat(150);
|
||||
// Generate random text content to meet the minimum 2048 tokens requirement for cache API
|
||||
// models/gemini-2.5-flash need 1024 tokens
|
||||
// models/gemini-2.5-flash-lite need 2048 tokens
|
||||
let long_text = "You are an expert at analyzing transcripts.".repeat(128);
|
||||
GeminiRequest {
|
||||
model: Some("models/gemini-2.5-flash".to_string()),
|
||||
contents: vec![ContentPart {
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
use super::key_validator::{test_cache_content_api, test_generate_content_api};
|
||||
use crate::adapters::{load_keys_from_txt, write_validated_key_to_tier_files};
|
||||
use crate::adapters::load_keys_from_txt;
|
||||
use crate::config::KeyCheckerConfig;
|
||||
use crate::error::ValidatorError;
|
||||
use crate::types::GeminiKey;
|
||||
use crate::utils::client_builder;
|
||||
use crate::types::{GeminiKey, KeyTier, ValidatedKey};
|
||||
use crate::utils::{client_builder, write_key_into_file};
|
||||
use async_stream::stream;
|
||||
use futures::{pin_mut, stream::StreamExt};
|
||||
use indicatif::ProgressStyle;
|
||||
use reqwest::Client;
|
||||
use std::time::Instant;
|
||||
use tokio::{fs, io::AsyncWriteExt, sync::mpsc};
|
||||
use tracing::{Span, error, info_span};
|
||||
use tracing_indicatif::span_ext::IndicatifSpanExt;
|
||||
|
@ -30,8 +29,20 @@ impl ValidationService {
|
|||
}
|
||||
|
||||
pub async fn validate_keys(&self, keys: Vec<GeminiKey>) -> Result<(), ValidatorError> {
|
||||
let start_time = Instant::now();
|
||||
let total_keys = keys.len();
|
||||
// Create a progress bar to track validation progress
|
||||
let progress_span = info_span!("key_checker");
|
||||
progress_span.pb_set_style(
|
||||
&ProgressStyle::with_template(
|
||||
"[{bar:60.cyan/blue}] {pos}/{len} ({percent}%) [{elapsed_precise}] ETA:{eta} Speed:{per_sec}",
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
progress_span.pb_set_length(total_keys as u64);
|
||||
progress_span.pb_set_message("Validating keys...");
|
||||
progress_span.pb_set_finish_message("All items processed");
|
||||
let progress_span_enter = progress_span.enter();
|
||||
|
||||
// Create channel for streaming keys from producer to consumer
|
||||
let (tx, mut rx) = mpsc::unbounded_channel::<GeminiKey>();
|
||||
let stream = stream! {
|
||||
|
@ -48,35 +59,38 @@ impl ValidationService {
|
|||
}
|
||||
}
|
||||
});
|
||||
// Create a progress bar to track validation progress
|
||||
let progress_span = info_span!("key_checker");
|
||||
progress_span.pb_set_style(
|
||||
&ProgressStyle::with_template(
|
||||
"[{bar:60.cyan/blue}] {pos}/{len} ({percent}%) [{elapsed_precise}] ETA:{eta} Speed:{per_sec}",
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
progress_span.pb_set_length(total_keys as u64);
|
||||
progress_span.pb_set_message("Validating keys...");
|
||||
progress_span.pb_set_finish_message("All items processed");
|
||||
let progress_span_enter = progress_span.enter();
|
||||
|
||||
// Create stream to validate keys concurrently (two-stage pipeline)
|
||||
let (invalid_tx, mut invalid_rx) = mpsc::unbounded_channel::<GeminiKey>();
|
||||
let invalid_stream = stream! {
|
||||
while let Some(item) = invalid_rx.recv().await {
|
||||
yield ValidatedKey::new(item);
|
||||
}
|
||||
};
|
||||
|
||||
// Create invalid keys stream
|
||||
let cache_api_url = self.config.cache_api_url();
|
||||
let valid_keys_stream = stream
|
||||
.map(|key| async move {
|
||||
let result = test_generate_content_api(
|
||||
self.client.clone(),
|
||||
self.full_url.clone(),
|
||||
key,
|
||||
key.clone(),
|
||||
self.config.clone(),
|
||||
)
|
||||
.await;
|
||||
Span::current().pb_inc(1);
|
||||
result
|
||||
(key, result)
|
||||
})
|
||||
.buffer_unordered(self.config.concurrency)
|
||||
.filter_map(|result| async { result.ok() })
|
||||
.filter_map(|(key, result)| async {
|
||||
match result {
|
||||
Ok(()) => Some(ValidatedKey::new(key)),
|
||||
Err(_e) => {
|
||||
let _ = invalid_tx.send(key);
|
||||
None
|
||||
}
|
||||
}
|
||||
})
|
||||
.map(|validated_key| {
|
||||
test_cache_content_api(self.client.clone(), cache_api_url.clone(), validated_key)
|
||||
})
|
||||
|
@ -86,34 +100,56 @@ impl ValidationService {
|
|||
// Open output files for writing keys by tier (fixed filenames)
|
||||
let free_keys_path = "freekey.txt";
|
||||
let paid_keys_path = "paidkey.txt";
|
||||
let invalid_keys_path = "invalidkey.txt";
|
||||
|
||||
let free_file = fs::File::create(&free_keys_path).await?;
|
||||
let paid_file = fs::File::create(&paid_keys_path).await?;
|
||||
let invalid_file = fs::File::create(&invalid_keys_path).await?;
|
||||
|
||||
let mut free_buffer_writer = tokio::io::BufWriter::new(free_file);
|
||||
let mut paid_buffer_writer = tokio::io::BufWriter::new(paid_file);
|
||||
let mut invalid_buffer_writer = tokio::io::BufWriter::new(invalid_file);
|
||||
|
||||
// Process validated keys and write to appropriate tier files
|
||||
while let Some(valid_key) = valid_keys_stream.next().await {
|
||||
if let Err(e) = write_validated_key_to_tier_files(
|
||||
&mut free_buffer_writer,
|
||||
&mut paid_buffer_writer,
|
||||
&valid_key,
|
||||
)
|
||||
.await
|
||||
{
|
||||
error!("Failed to write key to output file: {e}");
|
||||
// Spawn task to process invalid keys stream
|
||||
tokio::spawn(async move {
|
||||
let mut pinned_stream = Box::pin(invalid_stream);
|
||||
while let Some(invalid_key) = pinned_stream.next().await {
|
||||
if let Err(e) = write_key_into_file(&mut invalid_buffer_writer, &invalid_key).await
|
||||
{
|
||||
error!("Failed to write invalid key to file: {e}");
|
||||
}
|
||||
}
|
||||
if let Err(e) = invalid_buffer_writer.flush().await {
|
||||
error!("Failed to flush invalid keys buffer: {e}");
|
||||
}
|
||||
});
|
||||
|
||||
// Process all keys and write to appropriate tier files
|
||||
while let Some(validated_key) = valid_keys_stream.next().await {
|
||||
match validated_key.tier {
|
||||
KeyTier::Free => {
|
||||
if let Err(e) =
|
||||
write_key_into_file(&mut free_buffer_writer, &validated_key).await
|
||||
{
|
||||
error!("Failed to write free key to file: {e}");
|
||||
}
|
||||
}
|
||||
KeyTier::Paid => {
|
||||
if let Err(e) =
|
||||
write_key_into_file(&mut paid_buffer_writer, &validated_key).await
|
||||
{
|
||||
error!("Failed to write paid key to file: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Flush both buffers to ensure all data is written to files
|
||||
// Flush buffers for valid keys
|
||||
free_buffer_writer.flush().await?;
|
||||
paid_buffer_writer.flush().await?;
|
||||
|
||||
std::mem::drop(progress_span_enter);
|
||||
std::mem::drop(progress_span);
|
||||
|
||||
println!("Total Elapsed Time: {:?}", start_time.elapsed());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue