feat: update validation service to handle key writing. output invalid keys to different files.
parent
f126073ce7
commit
dbe2d553da
|
@ -2,4 +2,4 @@ pub mod input;
|
||||||
pub mod output;
|
pub mod output;
|
||||||
|
|
||||||
pub use input::load_keys_from_txt;
|
pub use input::load_keys_from_txt;
|
||||||
pub use output::write_validated_key_to_tier_writers;
|
|
||||||
|
|
|
@ -1,34 +1,9 @@
|
||||||
use crate::error::ValidatorError;
|
use crate::error::ValidatorError;
|
||||||
use crate::types::{GeminiKey, KeyTier, ValidatedKey};
|
use crate::types::GeminiKey;
|
||||||
use std::{fs, io::Write};
|
use std::{fs, io::Write};
|
||||||
use tokio::io::{AsyncWrite, AsyncWriteExt};
|
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
// Write valid key to appropriate tier file
|
|
||||||
pub async fn write_validated_key_to_tier_writers<W>(
|
|
||||||
free_writer: &mut W,
|
|
||||||
paid_writer: &mut W,
|
|
||||||
validated_key: &ValidatedKey,
|
|
||||||
) -> Result<(), ValidatorError>
|
|
||||||
where
|
|
||||||
W: AsyncWrite + Unpin,
|
|
||||||
{
|
|
||||||
match validated_key.tier {
|
|
||||||
KeyTier::Free => {
|
|
||||||
free_writer
|
|
||||||
.write_all(format!("{}\n", validated_key.key.as_ref()).as_bytes())
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
KeyTier::Paid => {
|
|
||||||
paid_writer
|
|
||||||
.write_all(format!("{}\n", validated_key.key.as_ref()).as_bytes())
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write valid key to output file in Clewdr format
|
// Write valid key to output file in Clewdr format
|
||||||
pub fn write_keys_clewdr_format(
|
pub fn write_keys_clewdr_format(
|
||||||
file: &mut fs::File,
|
file: &mut fs::File,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
pub mod http;
|
pub mod http;
|
||||||
|
pub mod writer;
|
||||||
|
|
||||||
pub use http::{client_builder, send_request};
|
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_endpoint: impl IntoUrl,
|
||||||
api_key: GeminiKey,
|
api_key: GeminiKey,
|
||||||
config: KeyCheckerConfig,
|
config: KeyCheckerConfig,
|
||||||
) -> Result<ValidatedKey, ValidatorError> {
|
) -> Result<(), ValidatorError> {
|
||||||
let api_endpoint = api_endpoint.into_url().unwrap();
|
let api_endpoint = api_endpoint.into_url().unwrap();
|
||||||
|
|
||||||
match send_request(
|
match send_request(
|
||||||
|
@ -29,7 +29,7 @@ pub async fn test_generate_content_api(
|
||||||
"BASIC API VALID - {}... - Passed generate content API test",
|
"BASIC API VALID - {}... - Passed generate content API test",
|
||||||
&api_key.as_ref()[..10]
|
&api_key.as_ref()[..10]
|
||||||
);
|
);
|
||||||
Ok(ValidatedKey::new(api_key))
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(e) => match &e {
|
Err(e) => match &e {
|
||||||
ValidatorError::HttpBadRequest { .. }
|
ValidatorError::HttpBadRequest { .. }
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use super::key_validator::{test_cache_content_api, test_generate_content_api};
|
use super::key_validator::{test_cache_content_api, test_generate_content_api};
|
||||||
use crate::adapters::{load_keys_from_txt, write_validated_key_to_tier_writers};
|
use crate::adapters::load_keys_from_txt;
|
||||||
use crate::config::KeyCheckerConfig;
|
use crate::config::KeyCheckerConfig;
|
||||||
use crate::error::ValidatorError;
|
use crate::error::ValidatorError;
|
||||||
use crate::types::GeminiKey;
|
use crate::types::{GeminiKey, KeyTier, ValidatedKey};
|
||||||
use crate::utils::client_builder;
|
use crate::utils::{client_builder, write_key_into_file};
|
||||||
use async_stream::stream;
|
use async_stream::stream;
|
||||||
use futures::{pin_mut, stream::StreamExt};
|
use futures::{pin_mut, stream::StreamExt};
|
||||||
use indicatif::ProgressStyle;
|
use indicatif::ProgressStyle;
|
||||||
|
@ -30,6 +30,19 @@ impl ValidationService {
|
||||||
|
|
||||||
pub async fn validate_keys(&self, keys: Vec<GeminiKey>) -> Result<(), ValidatorError> {
|
pub async fn validate_keys(&self, keys: Vec<GeminiKey>) -> Result<(), ValidatorError> {
|
||||||
let total_keys = keys.len();
|
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
|
// Create channel for streaming keys from producer to consumer
|
||||||
let (tx, mut rx) = mpsc::unbounded_channel::<GeminiKey>();
|
let (tx, mut rx) = mpsc::unbounded_channel::<GeminiKey>();
|
||||||
let stream = stream! {
|
let stream = stream! {
|
||||||
|
@ -46,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 cache_api_url = self.config.cache_api_url();
|
||||||
let valid_keys_stream = stream
|
let valid_keys_stream = stream
|
||||||
.map(|key| async move {
|
.map(|key| async move {
|
||||||
let result = test_generate_content_api(
|
let result = test_generate_content_api(
|
||||||
self.client.clone(),
|
self.client.clone(),
|
||||||
self.full_url.clone(),
|
self.full_url.clone(),
|
||||||
key,
|
key.clone(),
|
||||||
self.config.clone(),
|
self.config.clone(),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
Span::current().pb_inc(1);
|
Span::current().pb_inc(1);
|
||||||
result
|
(key, result)
|
||||||
})
|
})
|
||||||
.buffer_unordered(self.config.concurrency)
|
.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| {
|
.map(|validated_key| {
|
||||||
test_cache_content_api(self.client.clone(), cache_api_url.clone(), validated_key)
|
test_cache_content_api(self.client.clone(), cache_api_url.clone(), validated_key)
|
||||||
})
|
})
|
||||||
|
@ -84,27 +100,50 @@ impl ValidationService {
|
||||||
// Open output files for writing keys by tier (fixed filenames)
|
// Open output files for writing keys by tier (fixed filenames)
|
||||||
let free_keys_path = "freekey.txt";
|
let free_keys_path = "freekey.txt";
|
||||||
let paid_keys_path = "paidkey.txt";
|
let paid_keys_path = "paidkey.txt";
|
||||||
|
let invalid_keys_path = "invalidkey.txt";
|
||||||
|
|
||||||
let free_file = fs::File::create(&free_keys_path).await?;
|
let free_file = fs::File::create(&free_keys_path).await?;
|
||||||
let paid_file = fs::File::create(&paid_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 free_buffer_writer = tokio::io::BufWriter::new(free_file);
|
||||||
let mut paid_buffer_writer = tokio::io::BufWriter::new(paid_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
|
// Spawn task to process invalid keys stream
|
||||||
while let Some(valid_key) = valid_keys_stream.next().await {
|
tokio::spawn(async move {
|
||||||
if let Err(e) = write_validated_key_to_tier_writers(
|
let mut pinned_stream = Box::pin(invalid_stream);
|
||||||
&mut free_buffer_writer,
|
while let Some(invalid_key) = pinned_stream.next().await {
|
||||||
&mut paid_buffer_writer,
|
if let Err(e) = write_key_into_file(&mut invalid_buffer_writer, &invalid_key).await
|
||||||
&valid_key,
|
{
|
||||||
)
|
error!("Failed to write invalid key to file: {e}");
|
||||||
.await
|
}
|
||||||
{
|
}
|
||||||
error!("Failed to write key to output 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 buffers for valid keys
|
||||||
// Flush both buffers to ensure all data is written to files
|
|
||||||
free_buffer_writer.flush().await?;
|
free_buffer_writer.flush().await?;
|
||||||
paid_buffer_writer.flush().await?;
|
paid_buffer_writer.flush().await?;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue