Compare commits
2 Commits
903c4a9afa
...
452bd92eb1
Author | SHA1 | Date | |
---|---|---|---|
452bd92eb1 | |||
55cbe57728 |
44
Cargo.lock
generated
44
Cargo.lock
generated
@ -215,9 +215,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.18"
|
||||
version = "1.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c"
|
||||
checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
@ -291,9 +291,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.14"
|
||||
version = "0.5.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471"
|
||||
checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
@ -379,9 +379,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "data-encoding"
|
||||
version = "2.8.0"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010"
|
||||
checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476"
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
@ -834,7 +834,7 @@ dependencies = [
|
||||
"http 1.3.1",
|
||||
"hyper 1.6.0",
|
||||
"hyper-util",
|
||||
"rustls 0.23.25",
|
||||
"rustls 0.23.26",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
"tokio-rustls 0.26.2",
|
||||
@ -1080,7 +1080,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kon"
|
||||
version = "0.6.10"
|
||||
version = "0.6.11"
|
||||
dependencies = [
|
||||
"kon_cmds",
|
||||
"kon_libs",
|
||||
@ -1091,7 +1091,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kon_cmds"
|
||||
version = "0.1.7"
|
||||
version = "0.1.8"
|
||||
dependencies = [
|
||||
"dashmap 6.1.0",
|
||||
"futures",
|
||||
@ -1148,9 +1148,9 @@ checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.9.3"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413"
|
||||
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||
|
||||
[[package]]
|
||||
name = "litemap"
|
||||
@ -1213,9 +1213,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.7"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430"
|
||||
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
@ -1349,9 +1349,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-src"
|
||||
version = "300.4.2+3.4.1"
|
||||
version = "300.5.0+3.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "168ce4e058f975fe43e89d9ccf78ca668601887ae736090aacc23ae353c298e2"
|
||||
checksum = "e8ce546f549326b0e6052b649198487d91320875da901e7bd11a06d1ee3f9c2f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
@ -1527,9 +1527,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "redis"
|
||||
version = "0.29.3"
|
||||
version = "0.29.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ccbf02626b0bfd9c0b34837c0e2d3305ad6d20c5a816bc25d622b971dae88a6"
|
||||
checksum = "1bc42f3a12fd4408ce64d8efef67048a924e543bd35c6591c0447fda9054695f"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"bytes",
|
||||
@ -1733,9 +1733,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.23.25"
|
||||
version = "0.23.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c"
|
||||
checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"rustls-pki-types",
|
||||
@ -2328,7 +2328,7 @@ version = "0.26.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b"
|
||||
dependencies = [
|
||||
"rustls 0.23.25",
|
||||
"rustls 0.23.26",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
@ -3125,9 +3125,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.4"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36"
|
||||
checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "kon"
|
||||
version = "0.6.10"
|
||||
version = "0.6.11"
|
||||
edition = "2024"
|
||||
|
||||
[workspace]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "kon_cmds"
|
||||
version = "0.1.7"
|
||||
version = "0.1.8"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
|
@ -7,13 +7,23 @@ use {
|
||||
serde::{
|
||||
Deserialize,
|
||||
Serialize
|
||||
},
|
||||
std::{
|
||||
collections::HashMap,
|
||||
sync::{
|
||||
LazyLock,
|
||||
RwLock
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static REQWEST_: LazyLock<reqwest::Client> = LazyLock::new(reqwest::Client::new);
|
||||
static LOCALE_CACHE: LazyLock<RwLock<HashMap<String, String>>> = LazyLock::new(|| RwLock::new(HashMap::new()));
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct DeepLRequest {
|
||||
text: Vec<String>,
|
||||
target_lang: String
|
||||
target_lang: &'static str
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@ -21,12 +31,39 @@ struct DeepLResponse {
|
||||
translations: Vec<Translation>
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct DeepLLanguage {
|
||||
language: String,
|
||||
name: String
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct DeepLUsage {
|
||||
character_count: u64,
|
||||
character_limit: u64
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Translation {
|
||||
text: String,
|
||||
detected_source_language: String
|
||||
}
|
||||
|
||||
fn prettify_nums(num: u64) -> String {
|
||||
let mut s = String::new();
|
||||
let num_str = num.to_string();
|
||||
let len = num_str.len();
|
||||
|
||||
for (i, c) in num_str.chars().enumerate() {
|
||||
s.push(c);
|
||||
if (len - i - 1) % 3 == 0 && i < len - 1 {
|
||||
s.push(',');
|
||||
}
|
||||
}
|
||||
|
||||
s
|
||||
}
|
||||
|
||||
/// Translate a given message using DeepL
|
||||
#[poise::command(
|
||||
context_menu_command = "Translate via DeepL",
|
||||
@ -55,6 +92,10 @@ pub async fn translate(
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if LOCALE_CACHE.read().unwrap().is_empty() {
|
||||
update_locale_cache(&deepl_key).await.expect("Failed to update locale cache...");
|
||||
}
|
||||
|
||||
ctx.defer().await?;
|
||||
|
||||
let api_url = if deepl_key.ends_with(":fx") {
|
||||
@ -63,15 +104,14 @@ pub async fn translate(
|
||||
"https://api.deepl.com"
|
||||
};
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let resp = match client
|
||||
let resp = match REQWEST_
|
||||
.post(format!("{api_url}/v2/translate"))
|
||||
.header("User-Agent", "kon/reqwest")
|
||||
.header("Authorization", format!("DeepL-Auth-Key {deepl_key}"))
|
||||
.header("Content-Type", "application/json")
|
||||
.json(&DeepLRequest {
|
||||
text: vec![content.to_string()],
|
||||
target_lang: "EN".to_string()
|
||||
text: vec![content.to_owned()],
|
||||
target_lang: "EN"
|
||||
})
|
||||
.send()
|
||||
.await
|
||||
@ -142,11 +182,17 @@ pub async fn translate(
|
||||
};
|
||||
|
||||
if let Some(translation) = translation.translations.first() {
|
||||
let quota_info = match get_quota(&deepl_key).await {
|
||||
Ok(u) => &format!("-# **Quota: {}/{}**", prettify_nums(u.character_count), prettify_nums(u.character_limit)),
|
||||
Err(_) => "-# *Failed to check the quota!*"
|
||||
};
|
||||
|
||||
ctx
|
||||
.send(
|
||||
CreateReply::new().content(
|
||||
[
|
||||
format!("**Translated from {}**", prettify_lang(translation.detected_source_language.as_str())),
|
||||
quota_info.to_string(),
|
||||
format!("```\n{}\n```", translation.text)
|
||||
]
|
||||
.join("\n")
|
||||
@ -162,38 +208,94 @@ pub async fn translate(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn prettify_lang(code: &str) -> &str {
|
||||
match code {
|
||||
"AR" => "Arabic",
|
||||
"BG" => "Bulgarian",
|
||||
"CS" => "Czech",
|
||||
"DA" => "Danish",
|
||||
"DE" => "German",
|
||||
"EL" => "Greek",
|
||||
"EN" => "English",
|
||||
"ES" => "Spanish",
|
||||
"ET" => "Estonian",
|
||||
"FI" => "Finnish",
|
||||
"FR" => "French",
|
||||
"HU" => "Hungarian",
|
||||
"ID" => "Indonesian",
|
||||
"IT" => "Italian",
|
||||
"JA" => "Japanese",
|
||||
"KO" => "Korean",
|
||||
"LT" => "Lithuanian",
|
||||
"LV" => "Latvian",
|
||||
"NB" => "Norwegian Bokmål",
|
||||
"NL" => "Dutch",
|
||||
"PL" => "Polish",
|
||||
"PT" => "Portuguese",
|
||||
"RO" => "Romanian",
|
||||
"RU" => "Russian",
|
||||
"SK" => "Slovak",
|
||||
"SL" => "Slovenian",
|
||||
"SV" => "Swedish",
|
||||
"TR" => "Turkish",
|
||||
"UK" => "Ukrainian",
|
||||
"ZH" => "Chinese",
|
||||
_ => code
|
||||
async fn update_locale_cache(api_key: &str) -> Result<(), reqwest::Error> {
|
||||
let api_url = if api_key.ends_with(":fx") {
|
||||
"https://api-free.deepl.com"
|
||||
} else {
|
||||
"https://api.deepl.com"
|
||||
};
|
||||
|
||||
let languages: Vec<DeepLLanguage> = REQWEST_
|
||||
.get(format!("{api_url}/v2/languages"))
|
||||
.header("User-Agent", "kon/reqwest")
|
||||
.header("Authorization", format!("DeepL-Auth-Key {api_key}"))
|
||||
.query(&[("type", "target")])
|
||||
.send()
|
||||
.await?
|
||||
.json()
|
||||
.await?;
|
||||
|
||||
let mut c = LOCALE_CACHE.write().unwrap();
|
||||
for language in languages {
|
||||
c.insert(language.language, language.name);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// List of languages that DeepL supports for translation
|
||||
static LOCALE_LOOKUP: LazyLock<HashMap<&'static str, &'static str>> = LazyLock::new(|| {
|
||||
let mut c = HashMap::new();
|
||||
|
||||
c.insert("AR", "Arabic");
|
||||
c.insert("BG", "Bulgarian");
|
||||
c.insert("CS", "Czech");
|
||||
c.insert("DA", "Danish");
|
||||
c.insert("DE", "German");
|
||||
c.insert("EL", "Greek");
|
||||
c.insert("EN", "English");
|
||||
c.insert("ES", "Spanish");
|
||||
c.insert("ET", "Estonian");
|
||||
c.insert("FI", "Finnish");
|
||||
c.insert("FR", "French");
|
||||
c.insert("HU", "Hungarian");
|
||||
c.insert("ID", "Indonesian");
|
||||
c.insert("IT", "Italian");
|
||||
c.insert("JA", "Japanese");
|
||||
c.insert("KO", "Korean");
|
||||
c.insert("LT", "Lithuanian");
|
||||
c.insert("LV", "Latvian");
|
||||
c.insert("NB", "Norwegian Bokmål");
|
||||
c.insert("NL", "Dutch");
|
||||
c.insert("PL", "Polish");
|
||||
c.insert("PT", "Portuguese");
|
||||
c.insert("RO", "Romanian");
|
||||
c.insert("RU", "Russian");
|
||||
c.insert("SK", "Slovak");
|
||||
c.insert("SL", "Slovenian");
|
||||
c.insert("SV", "Swedish");
|
||||
c.insert("TR", "Turkish");
|
||||
c.insert("UK", "Ukrainian");
|
||||
c.insert("ZH", "Chinese");
|
||||
|
||||
c
|
||||
});
|
||||
|
||||
fn prettify_lang(code: &str) -> String {
|
||||
if let Ok(cache) = LOCALE_CACHE.read() {
|
||||
if let Some(name) = cache.get(code) {
|
||||
return name.clone();
|
||||
}
|
||||
}
|
||||
|
||||
LOCALE_LOOKUP.get(code).map(|&s| s.to_string()).unwrap_or_else(|| code.to_string())
|
||||
}
|
||||
|
||||
async fn get_quota(api_key: &str) -> Result<DeepLUsage, reqwest::Error> {
|
||||
let api_url = if api_key.ends_with(":fx") {
|
||||
"https://api-free.deepl.com"
|
||||
} else {
|
||||
"https://api.deepl.com"
|
||||
};
|
||||
|
||||
let usage: DeepLUsage = REQWEST_
|
||||
.get(format!("{api_url}/v2/usage"))
|
||||
.header("User-Agent", "kon/reqwest")
|
||||
.header("Authorization", format!("DeepL-Auth-Key {api_key}"))
|
||||
.send()
|
||||
.await?
|
||||
.json()
|
||||
.await?;
|
||||
|
||||
Ok(usage)
|
||||
}
|
||||
|
@ -13,14 +13,25 @@ use {
|
||||
serde_json::Value,
|
||||
std::{
|
||||
collections::HashMap,
|
||||
sync::OnceLock,
|
||||
time::Duration
|
||||
}
|
||||
};
|
||||
|
||||
async fn pms_serverstatus(url: String) -> Result<Vec<(String, Vec<Value>)>, String> {
|
||||
let client = HttpClient::new();
|
||||
let duration = Duration::from_secs(5);
|
||||
let req = match tokio::time::timeout(duration, client.get(url.as_str(), "PMS-Status")).await {
|
||||
type IdNameHashmap = HashMap<&'static str, &'static str>;
|
||||
|
||||
const HTTP_TIMEOUT: Duration = Duration::from_secs(5);
|
||||
|
||||
fn id_name_map() -> &'static IdNameHashmap {
|
||||
static ID_NAME_MAP: OnceLock<IdNameHashmap> = OnceLock::new();
|
||||
ID_NAME_MAP.get_or_init(|| [("wotbsg", "ASIA"), ("wowssg", "ASIA"), ("wowseu", "EU")].iter().cloned().collect())
|
||||
}
|
||||
|
||||
async fn pms_serverstatus(
|
||||
http: &HttpClient,
|
||||
url: String
|
||||
) -> Result<Vec<(String, Vec<Value>)>, String> {
|
||||
let req = match tokio::time::timeout(HTTP_TIMEOUT, http.get(url.as_str(), "PMS-Status")).await {
|
||||
Ok(result) => match result {
|
||||
Ok(req) => req,
|
||||
Err(e) => return Err(format!("Failed to connect: {e}"))
|
||||
@ -28,7 +39,7 @@ async fn pms_serverstatus(url: String) -> Result<Vec<(String, Vec<Value>)>, Stri
|
||||
Err(_) => return Err("Request timed out".to_string())
|
||||
};
|
||||
|
||||
let response = match tokio::time::timeout(duration, req.json::<HashMap<String, Value>>()).await {
|
||||
let response = match tokio::time::timeout(HTTP_TIMEOUT, req.json::<HashMap<String, Value>>()).await {
|
||||
Ok(result) => match result {
|
||||
Ok(data) => data,
|
||||
Err(e) => return Err(format!("Failed to parse response: {e}"))
|
||||
@ -57,7 +68,6 @@ async fn pms_serverstatus(url: String) -> Result<Vec<(String, Vec<Value>)>, Stri
|
||||
|
||||
fn process_pms_statuses(servers: Vec<(String, Vec<Value>)>) -> Vec<(String, String, bool)> {
|
||||
let mut server_map: HashMap<String, Vec<(String, String)>> = HashMap::new();
|
||||
let id_name_map: HashMap<&str, &str> = [("wotbsg", "ASIA"), ("wowssg", "ASIA"), ("wowseu", "EU")].iter().cloned().collect();
|
||||
|
||||
for (title, mapped_servers) in servers {
|
||||
for server in mapped_servers {
|
||||
@ -68,7 +78,7 @@ fn process_pms_statuses(servers: Vec<(String, Vec<Value>)>) -> Vec<(String, Stri
|
||||
"-1" => "Offline",
|
||||
_ => "Unknown"
|
||||
};
|
||||
let name = id_name_map.get(id).unwrap_or(&name);
|
||||
let name = id_name_map().get(id).unwrap_or(&name);
|
||||
server_map
|
||||
.entry(title.clone())
|
||||
.or_default()
|
||||
@ -93,7 +103,7 @@ fn process_pms_statuses(servers: Vec<(String, Vec<Value>)>) -> Vec<(String, Stri
|
||||
pub async fn wargaming(ctx: super::PoiseCtx<'_>) -> KonResult<()> {
|
||||
ctx.defer().await?;
|
||||
|
||||
let regions = [
|
||||
static REGIONS: [(&str, &str); 4] = [
|
||||
("asia", "Asia (WoT)"),
|
||||
("eu", "Europe (WoT)"),
|
||||
("wgcb", "Console (WoTX)"),
|
||||
@ -103,17 +113,18 @@ pub async fn wargaming(ctx: super::PoiseCtx<'_>) -> KonResult<()> {
|
||||
let pms_base = token_path().await.wg_pms;
|
||||
let mut embed = CreateEmbed::new().color(BINARY_PROPERTIES.embed_color);
|
||||
|
||||
let mut futures = Vec::new();
|
||||
let mut region_names = Vec::new();
|
||||
let http = HttpClient::new();
|
||||
let mut futures = Vec::with_capacity(REGIONS.len());
|
||||
let mut region_names = Vec::with_capacity(REGIONS.len());
|
||||
|
||||
for (region, name) in ®ions {
|
||||
for (region, name) in ®IONS {
|
||||
let url = if *region == "asia" {
|
||||
pms_base.clone()
|
||||
} else {
|
||||
pms_base.replace("asia", region)
|
||||
};
|
||||
|
||||
futures.push(pms_serverstatus(url));
|
||||
futures.push(pms_serverstatus(&http, url));
|
||||
region_names.push(name);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user