feat: add structured logging with tracing
parent
f10c2a8afb
commit
e5821f5b4c
|
@ -394,6 +394,8 @@ dependencies = [
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"toml 0.9.2",
|
"toml 0.9.2",
|
||||||
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -746,6 +748,12 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.174"
|
version = "0.2.174"
|
||||||
|
@ -780,6 +788,15 @@ version = "0.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
|
checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matchers"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
|
||||||
|
dependencies = [
|
||||||
|
"regex-automata 0.1.10",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.7.5"
|
version = "2.7.5"
|
||||||
|
@ -815,6 +832,16 @@ dependencies = [
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nu-ansi-term"
|
||||||
|
version = "0.46.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
|
||||||
|
dependencies = [
|
||||||
|
"overload",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "object"
|
name = "object"
|
||||||
version = "0.36.7"
|
version = "0.36.7"
|
||||||
|
@ -836,6 +863,12 @@ version = "1.70.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
|
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "overload"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pear"
|
name = "pear"
|
||||||
version = "0.2.9"
|
version = "0.2.9"
|
||||||
|
@ -1024,8 +1057,17 @@ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
"regex-automata",
|
"regex-automata 0.4.9",
|
||||||
"regex-syntax",
|
"regex-syntax 0.8.5",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||||
|
dependencies = [
|
||||||
|
"regex-syntax 0.6.29",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1036,9 +1078,15 @@ checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
"regex-syntax",
|
"regex-syntax 0.8.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.6.29"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.8.5"
|
version = "0.8.5"
|
||||||
|
@ -1219,6 +1267,15 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sharded-slab"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shlex"
|
name = "shlex"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
|
@ -1326,6 +1383,15 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thread_local"
|
||||||
|
version = "1.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinystr"
|
name = "tinystr"
|
||||||
version = "0.8.1"
|
version = "0.8.1"
|
||||||
|
@ -1535,9 +1601,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
|
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
|
"tracing-attributes",
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-attributes"
|
||||||
|
version = "0.1.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-core"
|
name = "tracing-core"
|
||||||
version = "0.1.34"
|
version = "0.1.34"
|
||||||
|
@ -1545,6 +1623,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
|
checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
"valuable",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-log"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"once_cell",
|
||||||
|
"tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-subscriber"
|
||||||
|
version = "0.3.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
|
||||||
|
dependencies = [
|
||||||
|
"matchers",
|
||||||
|
"nu-ansi-term",
|
||||||
|
"once_cell",
|
||||||
|
"regex",
|
||||||
|
"sharded-slab",
|
||||||
|
"smallvec",
|
||||||
|
"thread_local",
|
||||||
|
"tracing",
|
||||||
|
"tracing-core",
|
||||||
|
"tracing-log",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1598,6 +1706,12 @@ version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "valuable"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.5"
|
version = "0.9.5"
|
||||||
|
@ -1728,6 +1842,28 @@ dependencies = [
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[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]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.52.0"
|
version = "0.52.0"
|
||||||
|
|
|
@ -23,3 +23,5 @@ figment = { version = "0.10", features = ["env", "toml"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
toml = "0.9"
|
toml = "0.9"
|
||||||
thiserror = "2.0"
|
thiserror = "2.0"
|
||||||
|
tracing = "0.1"
|
||||||
|
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] }
|
||||||
|
|
|
@ -6,3 +6,4 @@ timeout_sec = 20
|
||||||
concurrency = 30
|
concurrency = 30
|
||||||
proxy = "http://username:password@host:port"
|
proxy = "http://username:password@host:port"
|
||||||
enable_multiplexing = true
|
enable_multiplexing = true
|
||||||
|
log_level = "info"
|
||||||
|
|
|
@ -3,6 +3,7 @@ use crate::error::Result;
|
||||||
use std::{fs, io::Write};
|
use std::{fs, io::Write};
|
||||||
use tokio::io::{AsyncWriteExt, BufWriter};
|
use tokio::io::{AsyncWriteExt, BufWriter};
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
|
use tracing::info;
|
||||||
|
|
||||||
// Write valid key to output file
|
// Write valid key to output file
|
||||||
pub async fn write_keys_txt_file(
|
pub async fn write_keys_txt_file(
|
||||||
|
@ -31,6 +32,6 @@ pub fn write_keys_clewdr_format(file: &mut fs::File, key: &GeminiKey) -> Result<
|
||||||
pub fn write_keys_to_file(keys: &[String], filename: &str) -> Result<()> {
|
pub fn write_keys_to_file(keys: &[String], filename: &str) -> Result<()> {
|
||||||
let content = keys.join("\n");
|
let content = keys.join("\n");
|
||||||
fs::write(filename, content)?;
|
fs::write(filename, content)?;
|
||||||
println!("File '{}' created with {} keys", filename, keys.len());
|
info!("File '{}' created with {} keys", filename, keys.len());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,6 +77,9 @@ pub struct KeyCheckerConfig {
|
||||||
// Whether to enable HTTP/2 multiplexing for requests.
|
// Whether to enable HTTP/2 multiplexing for requests.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub enable_multiplexing: bool,
|
pub enable_multiplexing: bool,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub log_level: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for KeyCheckerConfig {
|
impl Default for KeyCheckerConfig {
|
||||||
|
@ -110,33 +113,36 @@ impl KeyCheckerConfig {
|
||||||
/// Returns the complete Gemini API URL for generateContent endpoint
|
/// Returns the complete Gemini API URL for generateContent endpoint
|
||||||
pub fn gemini_api_url(&self) -> Url {
|
pub fn gemini_api_url(&self) -> Url {
|
||||||
self.api_host
|
self.api_host
|
||||||
.join("v1beta/models/gemini-2.0-flash-exp:generateContent")
|
.join("v1beta/models/gemini-2.5-flash-lite:generateContent")
|
||||||
.expect("Failed to join API URL")
|
.expect("Failed to join API URL")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for KeyCheckerConfig {
|
impl Display for KeyCheckerConfig {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
writeln!(f, "API Host: {}", self.api_host)?;
|
|
||||||
|
|
||||||
let proxy_status = match &self.proxy {
|
let proxy_status = match &self.proxy {
|
||||||
Some(proxy) => proxy.to_string(),
|
Some(proxy) => proxy.to_string(),
|
||||||
None => "Disabled".to_string(),
|
None => "Disabled".to_string(),
|
||||||
};
|
};
|
||||||
writeln!(f, "Proxy: {}", proxy_status)?;
|
|
||||||
|
|
||||||
let protocol_status = if self.enable_multiplexing {
|
let protocol_status = if self.enable_multiplexing {
|
||||||
"HTTP/2 (Multiplexing Enabled)"
|
"HTTP/2 (Multiplexing Enabled)"
|
||||||
} else {
|
} else {
|
||||||
"HTTP/1.1 (Multiplexing Disabled)"
|
"HTTP/1.1 (Multiplexing Disabled)"
|
||||||
};
|
};
|
||||||
writeln!(f, "Protocol: {}", protocol_status)?;
|
|
||||||
|
|
||||||
writeln!(f, "Timeout: {}s", self.timeout_sec)?;
|
write!(
|
||||||
writeln!(f, "Concurrency: {}", self.concurrency)?;
|
f,
|
||||||
writeln!(f, "Input: {}", self.input_path.display())?;
|
"Host={}, Proxy={}, Protocol={}, Timeout={}s, Concurrency={}, Input={}, Output={}, Backup={}",
|
||||||
writeln!(f, "Output: {}", self.output_path.display())?;
|
self.api_host,
|
||||||
write!(f, "Backup: {}", self.backup_path.display())
|
proxy_status,
|
||||||
|
protocol_status,
|
||||||
|
self.timeout_sec,
|
||||||
|
self.concurrency,
|
||||||
|
self.input_path.display(),
|
||||||
|
self.output_path.display(),
|
||||||
|
self.backup_path.display()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,6 +156,7 @@ static DEFAULT_CONFIG: LazyLock<KeyCheckerConfig> = LazyLock::new(|| KeyCheckerC
|
||||||
concurrency: 50,
|
concurrency: 50,
|
||||||
proxy: None,
|
proxy: None,
|
||||||
enable_multiplexing: true,
|
enable_multiplexing: true,
|
||||||
|
log_level: "info".to_string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// LazyLock for the test message body used in API key validation
|
// LazyLock for the test message body used in API key validation
|
||||||
|
|
10
src/error.rs
10
src/error.rs
|
@ -5,9 +5,6 @@ pub enum ValidatorError {
|
||||||
#[error("HTTP error: {0}")]
|
#[error("HTTP error: {0}")]
|
||||||
ReqwestError(#[from] reqwest::Error),
|
ReqwestError(#[from] reqwest::Error),
|
||||||
|
|
||||||
#[error("Key is unavailable or invalid")]
|
|
||||||
KeyInvalid,
|
|
||||||
|
|
||||||
#[error("IO error: {0}")]
|
#[error("IO error: {0}")]
|
||||||
Io(#[from] std::io::Error),
|
Io(#[from] std::io::Error),
|
||||||
|
|
||||||
|
@ -26,8 +23,11 @@ pub enum ValidatorError {
|
||||||
#[error("URL parse error: {0}")]
|
#[error("URL parse error: {0}")]
|
||||||
UrlParse(#[from] url::ParseError),
|
UrlParse(#[from] url::ParseError),
|
||||||
|
|
||||||
#[error("Key validation failed: {0}")]
|
#[error("Key is unavailable or invalid")]
|
||||||
Validation(String),
|
KeyInvalid,
|
||||||
|
|
||||||
|
#[error("Invalid Google API key format: {0}")]
|
||||||
|
KeyFormatInvalid(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, ValidatorError>;
|
pub type Result<T> = std::result::Result<T, ValidatorError>;
|
||||||
|
|
16
src/main.rs
16
src/main.rs
|
@ -1,7 +1,7 @@
|
||||||
use gemini_keychecker::error::ValidatorError;
|
use gemini_keychecker::error::ValidatorError;
|
||||||
use gemini_keychecker::{BANNER, config::KeyCheckerConfig, service::start_validation};
|
use gemini_keychecker::{BANNER, config::KeyCheckerConfig, service::start_validation};
|
||||||
|
|
||||||
use mimalloc::MiMalloc;
|
use mimalloc::MiMalloc;
|
||||||
|
use tracing::info;
|
||||||
|
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
static GLOBAL: MiMalloc = MiMalloc;
|
static GLOBAL: MiMalloc = MiMalloc;
|
||||||
|
@ -9,11 +9,19 @@ static GLOBAL: MiMalloc = MiMalloc;
|
||||||
/// Main function - displays banner and starts validation service
|
/// Main function - displays banner and starts validation service
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), ValidatorError> {
|
async fn main() -> Result<(), ValidatorError> {
|
||||||
|
let config = KeyCheckerConfig::load_config()?;
|
||||||
|
// Initialize tracing with professional format using configured log level
|
||||||
|
tracing_subscriber::fmt()
|
||||||
|
.with_target(false)
|
||||||
|
.with_level(true)
|
||||||
|
.with_env_filter(
|
||||||
|
tracing_subscriber::EnvFilter::try_from_default_env()
|
||||||
|
.unwrap_or_else(|_| tracing_subscriber::EnvFilter::new(&config.log_level)),
|
||||||
|
)
|
||||||
|
.init();
|
||||||
// Display banner and configuration status at startup
|
// Display banner and configuration status at startup
|
||||||
println!("{BANNER}");
|
println!("{BANNER}");
|
||||||
|
info!("Configuration loaded: {}", config);
|
||||||
let config = KeyCheckerConfig::load_config()?;
|
|
||||||
println!("{config}");
|
|
||||||
|
|
||||||
// Start validation service
|
// Start validation service
|
||||||
start_validation().await
|
start_validation().await
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use backon::{ExponentialBuilder, Retryable};
|
use backon::{ExponentialBuilder, Retryable};
|
||||||
use reqwest::{Client, IntoUrl, StatusCode};
|
use reqwest::{Client, IntoUrl, StatusCode};
|
||||||
use tokio::time::Duration;
|
use tokio::time::Duration;
|
||||||
|
use tracing::{debug, error, info, warn};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use crate::config::TEST_MESSAGE_BODY;
|
use crate::config::TEST_MESSAGE_BODY;
|
||||||
|
@ -15,19 +16,23 @@ pub async fn validate_key(
|
||||||
let api_endpoint = api_endpoint.into_url()?;
|
let api_endpoint = api_endpoint.into_url()?;
|
||||||
|
|
||||||
match send_test_request(client, &api_endpoint, api_key.clone()).await {
|
match send_test_request(client, &api_endpoint, api_key.clone()).await {
|
||||||
Ok(response) => {
|
Ok(_) => {
|
||||||
let status = response.status();
|
info!("SUCCESS - {}... - Valid key found", &api_key.as_ref()[..10]);
|
||||||
match status {
|
Ok(api_key)
|
||||||
StatusCode::OK => Ok(api_key),
|
}
|
||||||
StatusCode::UNAUTHORIZED
|
Err(e) => {
|
||||||
| StatusCode::FORBIDDEN
|
match e.status() {
|
||||||
| StatusCode::TOO_MANY_REQUESTS => Err(ValidatorError::KeyInvalid),
|
Some(StatusCode::UNAUTHORIZED | StatusCode::FORBIDDEN | StatusCode::TOO_MANY_REQUESTS) => {
|
||||||
_ => Err(ValidatorError::ReqwestError(
|
warn!("INVALID - {}... - {}", &api_key.as_ref()[..10], ValidatorError::KeyInvalid);
|
||||||
response.error_for_status().unwrap_err(),
|
Err(ValidatorError::KeyInvalid)
|
||||||
)),
|
}
|
||||||
|
_ => {
|
||||||
|
let req_error = ValidatorError::ReqwestError(e);
|
||||||
|
error!("ERROR- {}... - {}", &api_key.as_ref()[..10], req_error);
|
||||||
|
Err(req_error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => Err(ValidatorError::ReqwestError(e)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +54,7 @@ async fn send_test_request(
|
||||||
.json(&*TEST_MESSAGE_BODY)
|
.json(&*TEST_MESSAGE_BODY)
|
||||||
.send()
|
.send()
|
||||||
.await?;
|
.await?;
|
||||||
|
debug!("Response for key {}: {:?}", key.as_ref(), response.status());
|
||||||
response.error_for_status()
|
response.error_for_status()
|
||||||
})
|
})
|
||||||
.retry(&retry_policy)
|
.retry(&retry_policy)
|
||||||
|
|
|
@ -59,7 +59,6 @@ impl ValidationService {
|
||||||
|
|
||||||
// Process validated keys and write to output file
|
// Process validated keys and write to output file
|
||||||
while let Some(valid_key) = valid_keys_stream.next().await {
|
while let Some(valid_key) = valid_keys_stream.next().await {
|
||||||
println!("Valid key found: {}", valid_key.as_ref());
|
|
||||||
if let Err(e) = write_keys_txt_file(&mut buffer_writer, &valid_key).await {
|
if let Err(e) = write_keys_txt_file(&mut buffer_writer, &valid_key).await {
|
||||||
eprintln!("Failed to write key to output file: {}", e);
|
eprintln!("Failed to write key to output file: {}", e);
|
||||||
}
|
}
|
||||||
|
@ -73,7 +72,7 @@ impl ValidationService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 启动验证服务 - 封装了所有启动逻辑
|
|
||||||
pub async fn start_validation() -> Result<(), ValidatorError> {
|
pub async fn start_validation() -> Result<(), ValidatorError> {
|
||||||
let config = KeyCheckerConfig::load_config()?;
|
let config = KeyCheckerConfig::load_config()?;
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::error::ValidatorError;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
|
@ -14,9 +15,8 @@ impl AsRef<str> for GeminiKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for GeminiKey {
|
impl FromStr for GeminiKey {
|
||||||
type Err = &'static str;
|
type Err = ValidatorError;
|
||||||
|
fn from_str(s: &str) -> Result<Self, ValidatorError> {
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
static RE: LazyLock<Regex> =
|
static RE: LazyLock<Regex> =
|
||||||
LazyLock::new(|| Regex::new(r"^AIzaSy[A-Za-z0-9_-]{33}$").unwrap());
|
LazyLock::new(|| Regex::new(r"^AIzaSy[A-Za-z0-9_-]{33}$").unwrap());
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ impl FromStr for GeminiKey {
|
||||||
inner: cleaned.to_string(),
|
inner: cleaned.to_string(),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err("Invalid Google API key format")
|
Err(ValidatorError::KeyFormatInvalid(cleaned.to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue