chore: restructure the structs and its functions a bit

This commit is contained in:
tretrauit 2024-01-08 20:56:02 +07:00
parent b757dfc13a
commit c347abd07d
7 changed files with 80 additions and 66 deletions

View File

@ -1,12 +1,12 @@
use crate::database; use crate::database;
use crate::structs::Card; use crate::structs::Character;
use mongodb::Collection; use mongodb::Collection;
use std::sync::OnceLock; use std::sync::OnceLock;
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
use tokio::task; use tokio::task;
use tracing::trace; use tracing::trace;
pub static KATANA: OnceLock<Collection<Card>> = OnceLock::new(); pub static KATANA: OnceLock<Collection<Character>> = OnceLock::new();
/// ///
/// Initialize the "katana" collection in MongoDB /// Initialize the "katana" collection in MongoDB
@ -20,12 +20,12 @@ pub fn init() {
database::MONGO_DATABASE database::MONGO_DATABASE
.get() .get()
.unwrap() .unwrap()
.collection::<Card>("katana"), .collection::<Character>("katana"),
) )
.unwrap(); .unwrap();
} }
pub async fn query_card(name: &String, series: &String) -> Option<Card> { pub async fn query_character(name: &String, series: &String) -> Option<Character> {
KATANA KATANA
.get() .get()
.unwrap() .unwrap()
@ -40,7 +40,7 @@ pub async fn query_card(name: &String, series: &String) -> Option<Card> {
.unwrap() .unwrap()
} }
pub async fn query_card_regex(name: &String, series: &String) -> Option<Card> { pub async fn query_character_regex(name: &String, series: &String) -> Option<Character> {
let mut name_regex = String::new(); let mut name_regex = String::new();
let mut ascii_name = String::new(); let mut ascii_name = String::new();
for c in name.chars() { for c in name.chars() {
@ -85,7 +85,7 @@ pub async fn query_card_regex(name: &String, series: &String) -> Option<Card> {
.unwrap() .unwrap()
} }
pub async fn write_card(mut card: Card) -> Result<(), String> { pub async fn write_character(mut card: Character) -> Result<(), String> {
let old_card = KATANA let old_card = KATANA
.get() .get()
.unwrap() .unwrap()
@ -136,12 +136,11 @@ pub async fn write_card(mut card: Card) -> Result<(), String> {
} }
} }
pub async fn write_cards(cards: Vec<Card>) -> Result<(), String> { pub async fn write_characters(cards: Vec<Character>) -> Result<(), String> {
let mut new_cards: Vec<Card> = Vec::new(); let mut new_cards: Vec<Character> = Vec::new();
let mut handles: Vec<task::JoinHandle<Result<Option<Card>, String>>> = Vec::new(); let mut handles: Vec<task::JoinHandle<Result<Option<Character>, String>>> = Vec::new();
let start = SystemTime::now(); let start = SystemTime::now();
let current_time_ts = start let current_time_ts = start.duration_since(UNIX_EPOCH).unwrap();
.duration_since(UNIX_EPOCH).unwrap();
for mut card in cards { for mut card in cards {
let current_time_ts_clone = current_time_ts.clone(); let current_time_ts_clone = current_time_ts.clone();
trace!("Writing card: {:?}", card); trace!("Writing card: {:?}", card);

View File

@ -1,10 +1,16 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize, Clone)] #[derive(Debug, Deserialize, Serialize, Clone)]
pub struct Card { pub struct Character {
pub wishlist: Option<u32>, pub wishlist: Option<u32>,
pub name: String, pub name: String,
pub series: String, pub series: String,
pub print: i32,
pub last_update_ts: i64, pub last_update_ts: i64,
} }
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct DroppedCard {
pub character: Character,
pub print: i32,
pub edition: i32,
}

View File

@ -1,9 +1,9 @@
use crate::structs::Card; use crate::structs::Character;
use log::{error, trace}; use log::{error, trace};
// atopwl // atopwl
pub fn parse_cards_from_qingque_atopwl(content: &String) -> Vec<Card> { pub fn parse_cards_from_qingque_atopwl(content: &String) -> Vec<Character> {
let mut cards: Vec<Card> = Vec::new(); let mut cards: Vec<Character> = Vec::new();
for line in content.split("\n") { for line in content.split("\n") {
trace!("Parsing line: {}", line); trace!("Parsing line: {}", line);
let mut line_split = line.split(" · "); let mut line_split = line.split(" · ");
@ -48,11 +48,10 @@ pub fn parse_cards_from_qingque_atopwl(content: &String) -> Vec<Card> {
} }
None => continue, None => continue,
}; };
let card = Card { let card = Character {
wishlist: Some(wishlist), wishlist: Some(wishlist),
name, name,
series, series,
print: 0,
last_update_ts: 0, last_update_ts: 0,
}; };
trace!("Parsed card: {:?}", card); trace!("Parsed card: {:?}", card);
@ -62,8 +61,8 @@ pub fn parse_cards_from_qingque_atopwl(content: &String) -> Vec<Card> {
} }
// kc o:w // kc o:w
pub fn parse_cards_from_katana_kc_ow(content: &String) -> Vec<Card> { pub fn parse_cards_from_katana_kc_ow(content: &String) -> Vec<Character> {
let mut cards: Vec<Card> = Vec::new(); let mut cards: Vec<Character> = Vec::new();
for line in content.split("\n") { for line in content.split("\n") {
trace!("Parsing line: {}", line); trace!("Parsing line: {}", line);
if !line.ends_with("**") { if !line.ends_with("**") {
@ -103,11 +102,10 @@ pub fn parse_cards_from_katana_kc_ow(content: &String) -> Vec<Card> {
} }
None => continue, None => continue,
}; };
let card = Card { let card = Character {
wishlist: Some(wishlist), wishlist: Some(wishlist),
name, name,
series, series,
print: 0,
last_update_ts: 0, last_update_ts: 0,
}; };
trace!("Parsed card: {:?}", card); trace!("Parsed card: {:?}", card);
@ -122,8 +120,8 @@ pub fn parse_cards_from_katana_kc_ow(content: &String) -> Vec<Card> {
/// ///
/// "content" is `fields[0].value` /// "content" is `fields[0].value`
/// ///
pub fn parse_cards_from_katana_klu_results(content: &String) -> Vec<Card> { pub fn parse_cards_from_katana_klu_results(content: &String) -> Vec<Character> {
let mut cards: Vec<Card> = Vec::new(); let mut cards: Vec<Character> = Vec::new();
for line in content.split("\n") { for line in content.split("\n") {
trace!("Parsing line: {}", line); trace!("Parsing line: {}", line);
if !line.ends_with("**") { if !line.ends_with("**") {
@ -174,11 +172,10 @@ pub fn parse_cards_from_katana_klu_results(content: &String) -> Vec<Card> {
continue; continue;
} }
}; };
let card = Card { let card = Character {
wishlist: Some(wishlist), wishlist: Some(wishlist),
name, name,
series, series,
print: 0,
last_update_ts: 0, last_update_ts: 0,
}; };
trace!("Parsed card: {:?}", card); trace!("Parsed card: {:?}", card);
@ -188,7 +185,7 @@ pub fn parse_cards_from_katana_klu_results(content: &String) -> Vec<Card> {
} }
// klu (Character Lookup) // klu (Character Lookup)
pub fn parse_cards_from_katana_klu_lookup(content: &String) -> Option<Card> { pub fn parse_cards_from_katana_klu_lookup(content: &String) -> Option<Character> {
let mut lines = content.split("\n"); let mut lines = content.split("\n");
// Character // Character
let mut line_split = lines.nth(0).unwrap().split(" · "); let mut line_split = lines.nth(0).unwrap().split(" · ");
@ -242,11 +239,10 @@ pub fn parse_cards_from_katana_klu_lookup(content: &String) -> Option<Card> {
} }
None => return None, None => return None,
}; };
Some(Card { Some(Character {
wishlist: Some(wishlist), wishlist: Some(wishlist),
name, name,
series, series,
print: 0,
last_update_ts: 0, last_update_ts: 0,
}) })
} }

View File

@ -31,7 +31,7 @@ async fn parse_katana_embed(embed: &Embed) {
return; return;
} }
debug!("Importing cards from Katana 'Card Collection'"); debug!("Importing cards from Katana 'Card Collection'");
match database::katana::write_cards(cards).await { match database::katana::write_characters(cards).await {
Ok(_) => { Ok(_) => {
debug!("Imported successully"); debug!("Imported successully");
} }
@ -56,7 +56,7 @@ async fn parse_katana_embed(embed: &Embed) {
} }
}; };
debug!("Importing a card from Katana 'Character Lookup'"); debug!("Importing a card from Katana 'Character Lookup'");
match database::katana::write_card(card).await { match database::katana::write_character(card).await {
Ok(_) => { Ok(_) => {
debug!("Imported successully"); debug!("Imported successully");
} }
@ -78,7 +78,7 @@ async fn parse_katana_embed(embed: &Embed) {
return; return;
} }
debug!("Importing cards from Katana 'Character Results'"); debug!("Importing cards from Katana 'Character Results'");
match database::katana::write_cards(cards).await { match database::katana::write_characters(cards).await {
Ok(_) => { Ok(_) => {
debug!("Imported successully"); debug!("Imported successully");
} }
@ -110,7 +110,7 @@ async fn parse_qingque_event(ctx: &Context, event: MessageUpdateEvent) -> Result
&embed.description.as_ref().unwrap(), &embed.description.as_ref().unwrap(),
); );
debug!("Importing cards from Qingque 'Top Wishlist'"); debug!("Importing cards from Qingque 'Top Wishlist'");
match database::katana::write_cards(cards).await { match database::katana::write_characters(cards).await {
Ok(_) => { Ok(_) => {
debug!("Imported successully"); debug!("Imported successully");
} }

View File

@ -337,7 +337,7 @@ pub async fn dbg_kdropanalyze(ctx: &Context, msg: &Message) -> CommandResult {
let mut reply_str = String::new(); let mut reply_str = String::new();
for card in cards { for card in cards {
// reply_str.push_str(&format!("{:?}\n", card)); // reply_str.push_str(&format!("{:?}\n", card));
let wishlist_str: String = match card.wishlist { let wishlist_str: String = match card.character.wishlist {
Some(wishlist) => { Some(wishlist) => {
let mut out_str = wishlist.to_string(); let mut out_str = wishlist.to_string();
while out_str.len() < 5 { while out_str.len() < 5 {
@ -347,7 +347,7 @@ pub async fn dbg_kdropanalyze(ctx: &Context, msg: &Message) -> CommandResult {
} }
None => "None ".to_string(), None => "None ".to_string(),
}; };
let last_update_ts_str = match card.last_update_ts { let last_update_ts_str = match card.character.last_update_ts {
0 => "`Never`".to_string(), 0 => "`Never`".to_string(),
ts => { ts => {
format!("<t:{}:R>", ts.to_string()) format!("<t:{}:R>", ts.to_string())
@ -356,7 +356,11 @@ pub async fn dbg_kdropanalyze(ctx: &Context, msg: &Message) -> CommandResult {
reply_str.push_str( reply_str.push_str(
format!( format!(
":heart: `{}` • `{}` • **{}** • {} • {}\n", ":heart: `{}` • `{}` • **{}** • {} • {}\n",
wishlist_str, card.print, card.name, card.series, last_update_ts_str wishlist_str,
card.print,
card.character.name,
card.character.series,
last_update_ts_str
) )
.as_str(), .as_str(),
) )

View File

@ -10,7 +10,7 @@ use serenity::model::channel::Message;
use std::io::Cursor; use std::io::Cursor;
use std::sync::LazyLock; use std::sync::LazyLock;
use swordfish_common::database::katana as db; use swordfish_common::database::katana as db;
use swordfish_common::structs::Card; use swordfish_common::structs::{Character, DroppedCard};
use swordfish_common::{error, trace, warn}; use swordfish_common::{error, trace, warn};
use tokio::task; use tokio::task;
use tokio::time::Instant; use tokio::time::Instant;
@ -184,7 +184,7 @@ fn save_image_if_trace(img: &image::DynamicImage, path: &str) {
} }
} }
pub async fn analyze_card_libtesseract(card: image::DynamicImage, count: u32) -> Card { pub async fn analyze_card_libtesseract(card: image::DynamicImage, count: u32) -> DroppedCard {
trace!("Spawning threads for analyzing card..."); trace!("Spawning threads for analyzing card...");
// Read the name and the series // Read the name and the series
let card_clone = card.clone(); let card_clone = card.clone();
@ -245,29 +245,32 @@ pub async fn analyze_card_libtesseract(card: image::DynamicImage, count: u32) ->
let series = series_thread.await.unwrap(); let series = series_thread.await.unwrap();
trace!("Series: {}", series); trace!("Series: {}", series);
// TODO: Read the print number // TODO: Read the print number
let mut card = Card { let mut character = Character {
wishlist: None, wishlist: None,
name, name,
series, series,
print: 0,
last_update_ts: 0, last_update_ts: 0,
}; };
// Read the wishlist number // Read the wishlist number
match db::query_card(&card.name, &card.series).await { match db::query_character(&character.name, &character.series).await {
Some(c) => { Some(c) => {
card = c; character = c;
} }
None => match db::query_card_regex(&card.name, &card.series).await { None => match db::query_character_regex(&character.name, &character.series).await {
Some(c) => { Some(c) => {
card = c; character = c;
} }
None => {} None => {}
}, },
} }
card DroppedCard {
character,
print: 0,
edition: 0,
}
} }
pub async fn analyze_card_subprocess(card: image::DynamicImage, count: u32) -> Card { pub async fn analyze_card_subprocess(card: image::DynamicImage, count: u32) -> DroppedCard {
trace!("Spawning threads for analyzing card..."); trace!("Spawning threads for analyzing card...");
// Read the name and the series // Read the name and the series
let card_clone = card.clone(); let card_clone = card.clone();
@ -309,29 +312,32 @@ pub async fn analyze_card_subprocess(card: image::DynamicImage, count: u32) -> C
let series = series_thread.await.unwrap(); let series = series_thread.await.unwrap();
trace!("Series: {}", series); trace!("Series: {}", series);
// TODO: Read the print number // TODO: Read the print number
let mut card = Card { let mut character = Character {
wishlist: None, wishlist: None,
name, name,
series, series,
print: 0,
last_update_ts: 0, last_update_ts: 0,
}; };
// Read the wishlist number // Read the wishlist number
match db::query_card(&card.name, &card.series).await { match db::query_character(&character.name, &character.series).await {
Some(c) => { Some(c) => {
card = c; character = c;
} }
None => match db::query_card_regex(&card.name, &card.series).await { None => match db::query_character_regex(&character.name, &character.series).await {
Some(c) => { Some(c) => {
card = c; character = c;
} }
None => {} None => {}
}, },
} }
card DroppedCard {
character,
print: 0,
edition: 0,
}
} }
async fn execute_analyze_drop(image: DynamicImage, count: u32) -> Card { async fn execute_analyze_drop(image: DynamicImage, count: u32) -> DroppedCard {
let config = CONFIG.get().unwrap(); let config = CONFIG.get().unwrap();
match config.tesseract.backend.as_str() { match config.tesseract.backend.as_str() {
"libtesseract" => analyze_card_libtesseract(image, count).await, "libtesseract" => analyze_card_libtesseract(image, count).await,
@ -342,7 +348,7 @@ async fn execute_analyze_drop(image: DynamicImage, count: u32) -> Card {
} }
} }
pub async fn analyze_drop_message(message: &Message) -> Result<Vec<Card>, String> { pub async fn analyze_drop_message(message: &Message) -> Result<Vec<DroppedCard>, String> {
if message.attachments.len() < 1 { if message.attachments.len() < 1 {
return Err("No attachments found".to_string()); return Err("No attachments found".to_string());
}; };
@ -369,7 +375,7 @@ pub async fn analyze_drop_message(message: &Message) -> Result<Vec<Card>, String
let cards_count = img.width() / distance; let cards_count = img.width() / distance;
trace!("Cropping {} cards...", cards_count); trace!("Cropping {} cards...", cards_count);
let mut jobs: Vec<_> = Vec::new(); let mut jobs: Vec<_> = Vec::new();
let mut cards: Vec<Card> = Vec::with_capacity(cards_count.try_into().unwrap()); let mut cards: Vec<DroppedCard> = Vec::with_capacity(cards_count.try_into().unwrap());
for index in 0..cards_count { for index in 0..cards_count {
let i = index.clone(); let i = index.clone();
let x = 29 + distance * i; let x = 29 + distance * i;
@ -384,7 +390,7 @@ pub async fn analyze_drop_message(message: &Message) -> Result<Vec<Card>, String
Ok((i, execute_analyze_drop(card_img, i).await)) Ok((i, execute_analyze_drop(card_img, i).await))
}); });
} }
let mut handles: Vec<task::JoinHandle<Result<(u32, Card), String>>> = Vec::new(); let mut handles: Vec<task::JoinHandle<Result<(u32, DroppedCard), String>>> = Vec::new();
for job in jobs { for job in jobs {
let handle = task::spawn(job); let handle = task::spawn(job);
handles.push(handle); handles.push(handle);
@ -415,7 +421,7 @@ pub async fn handle_drop_message(ctx: &Context, msg: &Message) {
let mut reply_str = String::new(); let mut reply_str = String::new();
for card in cards { for card in cards {
// reply_str.push_str(&format!("{:?}\n", card)); // reply_str.push_str(&format!("{:?}\n", card));
let wishlist_str: String = match card.wishlist { let wishlist_str: String = match card.character.wishlist {
Some(wishlist) => { Some(wishlist) => {
let mut out_str = wishlist.to_string(); let mut out_str = wishlist.to_string();
while out_str.len() < 5 { while out_str.len() < 5 {
@ -425,7 +431,7 @@ pub async fn handle_drop_message(ctx: &Context, msg: &Message) {
} }
None => "None ".to_string(), None => "None ".to_string(),
}; };
let last_update_ts_str = match card.last_update_ts { let last_update_ts_str = match card.character.last_update_ts {
0 => "`Never`".to_string(), 0 => "`Never`".to_string(),
ts => { ts => {
format!("<t:{}:R>", ts.to_string()) format!("<t:{}:R>", ts.to_string())
@ -434,7 +440,11 @@ pub async fn handle_drop_message(ctx: &Context, msg: &Message) {
reply_str.push_str( reply_str.push_str(
format!( format!(
":heart: `{}` • `{}` • **{}** • {} • {}\n", ":heart: `{}` • `{}` • **{}** • {} • {}\n",
wishlist_str, card.print, card.name, card.series, last_update_ts_str wishlist_str,
card.print,
card.character.name,
card.character.series,
last_update_ts_str
) )
.as_str(), .as_str(),
) )

View File

@ -9,7 +9,6 @@ use serenity::prelude::*;
use std::env; use std::env;
use std::path::Path; use std::path::Path;
use std::sync::OnceLock; use std::sync::OnceLock;
use std::thread::current;
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
use swordfish_common::*; use swordfish_common::*;
@ -93,7 +92,7 @@ async fn parse_qingque_event(ctx: &Context, event: MessageUpdateEvent) -> Result
&embed.description.as_ref().unwrap(), &embed.description.as_ref().unwrap(),
); );
debug!("Importing cards from Qingque 'Top Wishlist'"); debug!("Importing cards from Qingque 'Top Wishlist'");
match database::katana::write_cards(cards).await { match database::katana::write_characters(cards).await {
Ok(_) => { Ok(_) => {
debug!("Imported successully"); debug!("Imported successully");
} }
@ -156,7 +155,7 @@ async fn parse_katana_embed(embed: &Embed) {
return; return;
} }
debug!("Importing cards from Katana 'Card Collection'"); debug!("Importing cards from Katana 'Card Collection'");
match database::katana::write_cards(cards).await { match database::katana::write_characters(cards).await {
Ok(_) => { Ok(_) => {
debug!("Imported successully"); debug!("Imported successully");
} }
@ -181,7 +180,7 @@ async fn parse_katana_embed(embed: &Embed) {
} }
}; };
debug!("Importing a card from Katana 'Character Lookup'"); debug!("Importing a card from Katana 'Character Lookup'");
match database::katana::write_card(card).await { match database::katana::write_character(card).await {
Ok(_) => { Ok(_) => {
debug!("Imported successully"); debug!("Imported successully");
} }
@ -203,7 +202,7 @@ async fn parse_katana_embed(embed: &Embed) {
return; return;
} }
debug!("Importing cards from Katana 'Character Results'"); debug!("Importing cards from Katana 'Character Results'");
match database::katana::write_cards(cards).await { match database::katana::write_characters(cards).await {
Ok(_) => { Ok(_) => {
debug!("Imported successully"); debug!("Imported successully");
} }
@ -285,7 +284,7 @@ async fn ping(ctx: &Context, msg: &Message) -> CommandResult {
format!( format!(
"Time taken to receive message: `{}ms`\n\n\ "Time taken to receive message: `{}ms`\n\n\
This only reflects the time taken for the bot to receive the message from Discord server.", This only reflects the time taken for the bot to receive the message from Discord server.",
(current_time_ts - msg_ts) / 1000.0 // Message timestamp can't be negative (current_time_ts - msg_ts) / 1000.0 // Message timestamp can't be negative
), ),
Some("Ping".to_string()), Some("Ping".to_string()),
) )