refactor: dump database to json

This commit is contained in:
mokurin000
2025-07-31 11:25:04 +08:00
parent 3ab53b426d
commit b72addd661
7 changed files with 84 additions and 52 deletions

View File

@@ -1,16 +1,10 @@
use std::{
fs::OpenOptions,
io::{self, BufRead},
sync::atomic::{AtomicBool, Ordering},
};
use std::sync::atomic::{AtomicBool, Ordering};
use futures_util::StreamExt;
use nyquest_preset::nyquest::ClientBuilder;
use palc::Parser;
use spdlog::{Level, LevelFilter::MoreSevereEqual};
use sdgb_api::{
ApiError,
all_net::QRCode,
auth_lite::{SDGB, SDHJ, delivery_raw},
title::{
@@ -26,7 +20,7 @@ use spdlog::{error, info, warn};
use crate::{commands::Cli, utils::login_action};
#[cfg(feature = "cache")]
#[cfg(feature = "fetchall")]
mod cache;
mod commands;
mod utils;
@@ -49,7 +43,7 @@ async fn main() -> Result<(), Box<dyn snafu::Error>> {
EARLY_QUIT.store(true, Ordering::Relaxed);
})?;
let Cli { command } = <Cli as Parser>::parse();
let Cli { command } = <Cli as Parser>::parse();
let client = ClientBuilder::default().build_async().await?;
@@ -108,7 +102,13 @@ async fn main() -> Result<(), Box<dyn snafu::Error>> {
println!("{}", String::from_utf8_lossy(&resp));
}
#[cfg(feature = "fetchall")]
commands::Commands::ListAllUser { concurrency } => {
use futures_util::StreamExt;
use redb::ReadableTable;
use sdgb_api::bincode::borrow_decode_from_slice;
use std::io::{self, BufRead};
let mut stdin = io::stdin().lock();
let mut buf = String::new();
let mut user_ids = Vec::new();
@@ -123,31 +123,22 @@ async fn main() -> Result<(), Box<dyn snafu::Error>> {
user_ids.push(user_id);
}
#[cfg(feature = "cache")]
let _ = cache::init_db();
#[cfg(feature = "cache")]
let write = cache::write_txn()?;
#[cfg(feature = "cache")]
let config = sdgb_api::bincode::config::Configuration::<
sdgb_api::bincode::config::LittleEndian,
>::default()
.with_no_limit();
let players = futures_util::stream::iter(user_ids)
let _ = futures_util::stream::iter(user_ids)
.map(async |user_id| {
#[cfg(feature = "cache")]
{
use redb::ReadableTable;
use sdgb_api::bincode::borrow_decode_from_slice;
let cache_table = cache::open_table(&write)?;
let data = cache_table.get(user_id)?;
if let Some(data) = data {
let decoded: (GetUserPreviewApiResp, _) =
borrow_decode_from_slice(&data.value(), config)?;
let cache_table = cache::open_table(&write)?;
let data = cache_table.get(user_id)?;
if let Some(data) = data {
let decoded: (GetUserPreviewApiResp, _) =
borrow_decode_from_slice(&data.value(), config)?;
return Ok(decoded.0);
}
return Ok(decoded.0);
}
if EARLY_QUIT.load(Ordering::Relaxed) {
@@ -166,18 +157,15 @@ async fn main() -> Result<(), Box<dyn snafu::Error>> {
Ok(resp) => {
info!("preview: {user_id} succeed");
#[cfg(feature = "cache")]
{
use sdgb_api::bincode::encode_to_vec;
use sdgb_api::bincode::encode_to_vec;
if let Ok(mut table) = cache::open_table(&write)
&& let Ok(encoded) = encode_to_vec(resp, config)
{
_ = table.insert(resp.user_id, encoded);
}
if let Ok(mut table) = cache::open_table(&write)
&& let Ok(encoded) = encode_to_vec(resp, config)
{
_ = table.insert(resp.user_id, encoded);
}
}
Err(ApiError::JSON { .. }) => {
Err(sdgb_api::ApiError::JSON { .. }) => {
warn!("account unregistered: {user_id}");
}
Err(e) => {
@@ -192,20 +180,40 @@ async fn main() -> Result<(), Box<dyn snafu::Error>> {
.collect::<Vec<_>>()
.await;
#[cfg(feature = "cache")]
let _ = write.commit();
if !EARLY_QUIT.load(Ordering::Relaxed) {
let output = OpenOptions::new()
.write(true)
.truncate(true)
.create(true)
.open("players.json")?;
serde_json::to_writer_pretty(output, &players)?;
} else {
info!("current progress: {}", players.len());
}
}
#[cfg(feature = "fetchall")]
commands::Commands::ListAllUserDump { .. } => {
use std::fs::OpenOptions;
use redb::ReadableTable;
use sdgb_api::bincode::{self, borrow_decode_from_slice};
use crate::cache::{open_table_read, read_txn};
let txn = read_txn()?;
let table = open_table_read(&txn)?;
let config = bincode::config::Configuration::<bincode::config::LittleEndian>::default()
.with_no_limit();
let user_ids = table
.iter()?
.flatten()
.map(|d| borrow_decode_from_slice(&d.1.value(), config))
.flatten()
.map(|(value, _)| value)
.collect::<Vec<GetUserPreviewApiResp>>();
let file = OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.open("players.json")?;
file.lock()?;
serde_json::to_writer(file, &user_ids)?;
}
commands::Commands::Userdata { user_id } => {
let action = async |_| match Sdgb1_50::request::<_, GetUserDataApiResp>(
&client,
@@ -228,3 +236,6 @@ async fn main() -> Result<(), Box<dyn snafu::Error>> {
Ok(())
}
#[cfg(all(feature = "compio", feature = "tokio"))]
compile_error!("you must not enable both `compio` and `tokio`");