feat: swordfish-user

Also move tesseract implementation to swordfish cuz only the bot uses it.
This commit is contained in:
tretrauit 2024-01-07 19:19:40 +07:00
parent ebafd93110
commit 8eb622f479
12 changed files with 291 additions and 22 deletions

71
Cargo.lock generated
View File

@ -289,9 +289,9 @@ dependencies = [
[[package]]
name = "clang-sys"
version = "1.6.1"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f"
checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1"
dependencies = [
"glob",
"libc",
@ -315,6 +315,16 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "command_attr"
version = "0.5.1"
source = "git+https://github.com/nshout/serenity-self#6b62ca61aa592d4fd22dc42848388c5fb3889161"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "convert_case"
version = "0.4.0"
@ -1141,12 +1151,12 @@ checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
[[package]]
name = "libloading"
version = "0.7.4"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161"
dependencies = [
"cfg-if",
"winapi",
"windows-sys 0.48.0",
]
[[package]]
@ -1974,7 +1984,42 @@ dependencies = [
"bitflags 2.4.1",
"bytes",
"chrono",
"command_attr",
"command_attr 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"dashmap",
"flate2",
"futures",
"fxhash",
"levenshtein",
"mime_guess",
"parking_lot",
"percent-encoding",
"reqwest",
"secrecy",
"serde",
"serde_json",
"static_assertions",
"time",
"tokio",
"tokio-tungstenite",
"tracing",
"typemap_rev",
"typesize",
"url",
"uwl",
]
[[package]]
name = "serenity"
version = "0.13.0-alpha2"
source = "git+https://github.com/nshout/serenity-self#6b62ca61aa592d4fd22dc42848388c5fb3889161"
dependencies = [
"arrayvec",
"async-trait",
"base64 0.21.5",
"bitflags 2.4.1",
"bytes",
"chrono",
"command_attr 0.5.1 (git+https://github.com/nshout/serenity-self)",
"dashmap",
"flate2",
"futures",
@ -2174,9 +2219,11 @@ version = "0.1.0"
dependencies = [
"dotenvy",
"image",
"leptess",
"regex",
"rusty-tesseract",
"serde",
"serenity",
"serenity 0.12.0",
"swordfish-common",
"tokio",
"toml",
@ -2186,16 +2233,22 @@ dependencies = [
name = "swordfish-common"
version = "0.1.0"
dependencies = [
"leptess",
"log",
"mongodb",
"rusty-tesseract",
"serde",
"tokio",
"tracing",
"tracing-subscriber",
]
[[package]]
name = "swordfish-user"
version = "0.1.0"
dependencies = [
"serenity 0.13.0-alpha2",
"swordfish-common",
]
[[package]]
name = "syn"
version = "1.0.109"

View File

@ -3,5 +3,5 @@ resolver = "1"
members = [
"swordfish-common",
"swordfish"
]
, "swordfish-user"]
default-members = ["swordfish"]

View File

@ -6,9 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
leptess = "0.14.0"
log = "0.4.20"
rusty-tesseract = "1.1.9"
serde = "1.0.195"
tokio = "1.35.1"
tracing = "0.1.40"

View File

@ -1,12 +1,12 @@
#![feature(lazy_cell)]
#![feature(string_remove_matches)]
pub use log;
pub use tokio;
pub use tracing::{debug, error, info, trace, warn};
use tracing_subscriber::{self, fmt, EnvFilter};
pub mod constants;
pub mod database;
pub mod structs;
pub mod tesseract;
pub mod utils;
pub fn setup_logger(level: &str) -> Result<(), ()> {

13
swordfish-user/Cargo.toml Normal file
View File

@ -0,0 +1,13 @@
[package]
name = "swordfish-user"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
serenity = { git = "https://github.com/nshout/serenity-self", version = "0.13.0-alpha2" }
[dependencies.swordfish-common]
path = "../swordfish-common"

202
swordfish-user/src/main.rs Normal file
View File

@ -0,0 +1,202 @@
use std::env;
use serenity::all::{Embed, MessageUpdateEvent};
use serenity::async_trait;
use serenity::model::channel::Message;
use serenity::prelude::*;
use swordfish_common::setup_logger;
use swordfish_common::{constants, database, utils};
use swordfish_common::{debug, tokio};
use swordfish_common::{error, info, trace};
const GITHUB_URL: &str = "https://github.com/teppyboy/swordfish";
async fn parse_katana(ctx: &Context, msg: &Message) -> Result<(), String> {
if msg.embeds.len() == 0 {
return Ok(());
}
let embed = &msg.embeds[0];
parse_katana_embed(embed).await;
Ok(())
}
async fn parse_katana_embed(embed: &Embed) {
match embed.author {
Some(ref author) => match author.name.as_str() {
"Card Collection" => {
let cards = utils::katana::parse_cards_from_katana_kc_ow(
&embed.description.as_ref().unwrap(),
);
if cards.len() == 0 {
return;
}
debug!("Importing cards from Katana 'Card Collection'");
match database::katana::write_cards(cards).await {
Ok(_) => {
debug!("Imported successully");
}
Err(why) => {
error!("Failed to import card: {:?}", why);
}
}
}
_ => {}
},
None => {}
};
match embed.title {
Some(ref title) => match title.as_str() {
"Character Lookup" => {
let card = match utils::katana::parse_cards_from_katana_klu_lookup(
&embed.description.as_ref().unwrap(),
) {
Some(card) => card,
None => {
return;
}
};
debug!("Importing a card from Katana 'Character Lookup'");
match database::katana::write_card(card).await {
Ok(_) => {
debug!("Imported successully");
}
Err(why) => {
error!("Failed to import card: {:?}", why);
}
}
}
"Character Results" => {
let fields = match embed.fields.len() {
0 => {
return;
}
_ => &embed.fields,
};
let embed_field = fields.get(0).unwrap();
let cards = utils::katana::parse_cards_from_katana_klu_results(&embed_field.value);
if cards.len() == 0 {
return;
}
debug!("Importing cards from Katana 'Character Results'");
match database::katana::write_cards(cards).await {
Ok(_) => {
debug!("Imported successully");
}
Err(why) => {
error!("Failed to import card: {:?}", why);
}
}
}
_ => {}
},
None => {}
};
}
async fn parse_qingque_event(ctx: &Context, event: MessageUpdateEvent) -> Result<(), String> {
if event.embeds.is_none() || event.embeds.clone().unwrap().len() == 0 {
return Ok(());
}
let embed = &event.embeds.unwrap()[0];
let embed_title = match embed.title {
Some(ref title) => title,
None => {
return Ok(());
}
};
match embed_title.as_str() {
"Top Wishlist" => {
let cards = utils::katana::parse_cards_from_qingque_atopwl(
&embed.description.as_ref().unwrap(),
);
debug!("Importing cards from Qingque 'Top Wishlist'");
match database::katana::write_cards(cards).await {
Ok(_) => {
debug!("Imported successully");
}
Err(why) => {
error!("Failed to import card: {:?}", why);
}
}
}
_ => {
return Ok(());
}
}
Ok(())
}
async fn parse_katana_event(ctx: &Context, event: MessageUpdateEvent) -> Result<(), String> {
if event.embeds.is_none() || event.embeds.clone().unwrap().len() == 0 {
return Ok(());
}
let embed = &event.embeds.unwrap()[0];
parse_katana_embed(embed).await;
Ok(())
}
struct Handler;
#[async_trait]
impl EventHandler for Handler {
async fn message(&self, ctx: Context, msg: Message) {
if msg.author.id.get() == constants::KATANA_ID {
parse_katana(&ctx, &msg).await.unwrap();
}
}
async fn message_update(
&self,
ctx: Context,
old_if_available: Option<Message>,
new: Option<Message>,
event: MessageUpdateEvent,
) {
let author = match event.author {
Some(ref v) => v,
None => {
return;
}
};
if author.id == ctx.cache.current_user().id {
return;
}
let content = match event.content {
Some(ref v) => v,
None => {
return;
}
};
trace!("Message update: {}, sender: {}", content, author.id);
match author.id.get() {
constants::KATANA_ID => {
parse_katana_event(&ctx, event).await.unwrap();
}
constants::QINGQUE_ID => {
parse_qingque_event(&ctx, event).await.unwrap();
}
_ => {}
}
}
}
#[tokio::main]
async fn main() {
// Login with a user token from the environment
let log_level = env::var("LOG_LEVEL").unwrap_or("info".to_string());
setup_logger(log_level.as_str()).expect("Failed to setup logger");
let token = env::var("DISCORD_TOKEN").expect("Token not found");
info!("Swordfish v{} - {}", env!("CARGO_PKG_VERSION"), GITHUB_URL);
info!("Log level: {}", log_level);
info!("Initializing database...");
swordfish_common::database::init().await;
info!("Initializing Discord client...");
let mut client = Client::builder(token)
.event_handler(Handler)
.await
.expect("Error creating client");
// start listening for events by starting a single shard
if let Err(why) = client.start().await {
error!("An error occurred while running the client: {:?}", why);
}
}

View File

@ -8,7 +8,9 @@ edition = "2021"
[dependencies]
dotenvy = "0.15.7"
image = "0.24.7"
leptess = "0.14.0"
regex = "1.10.2"
rusty-tesseract = "1.1.9"
serde = "1.0.193"
serenity = { version = "0.12.0", features = ["builder"] }
tokio = { version = "1.35.1", features = ["full"] }

View File

@ -1,3 +1,4 @@
use crate::tesseract::{libtesseract, subprocess};
use crate::CONFIG;
use image::imageops::colorops::contrast_in_place;
use image::io::Reader as ImageReader;
@ -8,7 +9,6 @@ use std::io::Cursor;
use std::sync::LazyLock;
use swordfish_common::database::katana as db;
use swordfish_common::structs::Card;
use swordfish_common::tesseract::{libtesseract, subprocess};
use swordfish_common::{trace, warn};
use tokio::task;

View File

@ -19,6 +19,7 @@ mod debug;
mod helper;
mod katana;
mod template;
mod tesseract;
const GITHUB_URL: &str = "https://github.com/teppyboy/swordfish";
static CONFIG: OnceLock<Config> = OnceLock::new();
@ -95,10 +96,10 @@ async fn parse_qingque_event(ctx: &Context, event: MessageUpdateEvent) -> Result
let cards = utils::katana::parse_cards_from_qingque_atopwl(
&embed.description.as_ref().unwrap(),
);
trace!("Begin importing cards");
debug!("Importing cards from Qingque 'Top Wishlist'");
match database::katana::write_cards(cards).await {
Ok(_) => {
trace!("Imported successully");
debug!("Imported successully");
}
Err(why) => {
error!("Failed to import card: {:?}", why);
@ -206,10 +207,10 @@ async fn parse_katana_embed(embed: &Embed) {
if cards.len() == 0 {
return;
}
trace!("Begin importing cards");
debug!("Importing cards from Katana 'Card Collection'");
match database::katana::write_cards(cards).await {
Ok(_) => {
trace!("Imported successully");
debug!("Imported successully");
}
Err(why) => {
error!("Failed to import card: {:?}", why);
@ -231,10 +232,10 @@ async fn parse_katana_embed(embed: &Embed) {
return;
}
};
trace!("Begin importing a card");
debug!("Importing a card from Katana 'Character Lookup'");
match database::katana::write_card(card).await {
Ok(_) => {
trace!("Imported successully");
debug!("Imported successully");
}
Err(why) => {
error!("Failed to import card: {:?}", why);
@ -253,10 +254,10 @@ async fn parse_katana_embed(embed: &Embed) {
if cards.len() == 0 {
return;
}
trace!("Begin importing cards");
debug!("Importing cards from Katana 'Character Results'");
match database::katana::write_cards(cards).await {
Ok(_) => {
trace!("Imported successully");
debug!("Imported successully");
}
Err(why) => {
error!("Failed to import card: {:?}", why);