diff --git a/Cargo.lock b/Cargo.lock index 507f85e..82e63e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -438,6 +438,7 @@ dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", + "serde", "windows-link", ] @@ -1161,7 +1162,7 @@ dependencies = [ "hyper-util", "rustls", "rustls-pki-types", - "rustls-platform-verifier 0.6.1", + "rustls-platform-verifier 0.6.2", "tokio", "tokio-rustls", "tower-service", @@ -1755,7 +1756,7 @@ dependencies = [ "libc", "log", "openssl", - "openssl-probe", + "openssl-probe 0.1.6", "openssl-sys", "schannel", "security-framework 2.11.1", @@ -1948,6 +1949,12 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + [[package]] name = "openssl-src" version = "300.5.5+3.5.5" @@ -2006,7 +2013,7 @@ checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] name = "payphone" -version = "4.4.18" +version = "4.4.19" dependencies = [ "anyhow", "async-trait", @@ -2037,11 +2044,12 @@ dependencies = [ "thiserror 2.0.12", "time", "tokio", + "topgg", "tower-http", "twilight-cache-inmemory", "twilight-gateway", "twilight-http", - "twilight-model", + "twilight-model 0.16.0", "twilight-util", "twilight-validate", "unicode-segmentation", @@ -2341,18 +2349,18 @@ dependencies = [ [[package]] name = "ref-cast" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", @@ -2489,14 +2497,14 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" dependencies = [ - "openssl-probe", + "openssl-probe 0.2.1", "rustls-pki-types", "schannel", - "security-framework 3.2.0", + "security-framework 3.6.0", ] [[package]] @@ -2523,7 +2531,7 @@ dependencies = [ "rustls-native-certs", "rustls-platform-verifier-android", "rustls-webpki", - "security-framework 3.2.0", + "security-framework 3.6.0", "security-framework-sys", "webpki-root-certs 0.26.11", "windows-sys 0.59.0", @@ -2531,9 +2539,9 @@ dependencies = [ [[package]] name = "rustls-platform-verifier" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be59af91596cac372a6942530653ad0c3a246cdd491aaa9dcaee47f88d67d5a0" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" dependencies = [ "core-foundation 0.10.1", "core-foundation-sys", @@ -2544,10 +2552,10 @@ dependencies = [ "rustls-native-certs", "rustls-platform-verifier-android", "rustls-webpki", - "security-framework 3.2.0", + "security-framework 3.6.0", "security-framework-sys", - "webpki-root-certs 1.0.2", - "windows-sys 0.59.0", + "webpki-root-certs 1.0.6", + "windows-sys 0.60.2", ] [[package]] @@ -2691,9 +2699,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "3.2.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" +checksum = "d17b898a6d6948c3a8ee4372c17cb384f90d2e6e912ef00895b14fd7ab54ec38" dependencies = [ "bitflags 2.9.1", "core-foundation 0.10.1", @@ -2704,9 +2712,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "321c8673b092a9a42605034a9879d73cb79101ed5fd117bc9a597b89b4e9e61a" dependencies = [ "core-foundation-sys", "libc", @@ -3197,6 +3205,20 @@ dependencies = [ "winnow", ] +[[package]] +name = "topgg" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ed67b6c13c05e039e1239c421b8e658b1fff440376311bb81473bf86efbca10" +dependencies = [ + "cfg-if", + "chrono", + "reqwest", + "serde", + "serde_json", + "twilight-model 0.15.4", +] + [[package]] name = "tower" version = "0.5.2" @@ -3300,7 +3322,7 @@ dependencies = [ "bitflags 2.9.1", "dashmap", "serde", - "twilight-model", + "twilight-model 0.16.0", "twilight-util", ] @@ -3322,7 +3344,7 @@ dependencies = [ "tracing", "twilight-gateway-queue", "twilight-http", - "twilight-model", + "twilight-model 0.16.0", ] [[package]] @@ -3356,7 +3378,7 @@ dependencies = [ "tokio", "tracing", "twilight-http-ratelimiting", - "twilight-model", + "twilight-model 0.16.0", "twilight-validate", ] @@ -3370,6 +3392,19 @@ dependencies = [ "tracing", ] +[[package]] +name = "twilight-model" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276bd50f4817b3b421395afac89f5d7b61fdfd0f00a28b2a7db983e4878b4a1a" +dependencies = [ + "bitflags 1.3.2", + "serde", + "serde-value", + "serde_repr", + "time", +] + [[package]] name = "twilight-model" version = "0.16.0" @@ -3389,7 +3424,7 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5777d71286611c1639021f5f6e6b40300eb8da278449ac1cf6da01c94053425" dependencies = [ - "twilight-model", + "twilight-model 0.16.0", "twilight-validate", ] @@ -3399,7 +3434,7 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f8d106028ede53708526364b03318bbf846babe146e3ff9e39821a0ca25ff4" dependencies = [ - "twilight-model", + "twilight-model 0.16.0", ] [[package]] @@ -3634,14 +3669,14 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75c7f0ef91146ebfb530314f5f1d24528d7f0767efbfd31dce919275413e393e" dependencies = [ - "webpki-root-certs 1.0.2", + "webpki-root-certs 1.0.6", ] [[package]] name = "webpki-root-certs" -version = "1.0.2" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4ffd8df1c57e87c325000a3d6ef93db75279dc3a231125aac571650f22b12a" +checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca" dependencies = [ "rustls-pki-types", ] diff --git a/Cargo.toml b/Cargo.toml index 97ba17c..aec1a91 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "payphone" -version = "4.4.18" +version = "4.4.19" edition = "2024" default-run = "payphone" @@ -26,20 +26,36 @@ open = "5.3.2" rand = "0.9.2" rand_chacha = { version = "0.9.0", features = ["os_rng"] } regex = "1.11.1" -reqwest = { version = "0.12.23", features = ["gzip", "brotli", "zstd", "native-tls-vendored"] } +reqwest = { version = "0.12.23", features = [ + "gzip", + "brotli", + "zstd", + "native-tls-vendored", +] } rgb = "0.8.52" scc = "2.3.4" scylla = { version = "1.3.1", features = ["time-03"] } serde_json = "1.0.143" thiserror = "2.0.12" -time = { version = "0.3.41", features = ["formatting", "local-offset", "macros"] } +time = { version = "0.3.41", features = [ + "formatting", + "local-offset", + "macros", +] } tokio = { version = "1.47.1", features = ["macros", "rt-multi-thread"] } +topgg = { version = "1.4.2", features = ["twilight"] } tower-http = { version = "0.6.6", features = ["fs"] } -twilight-cache-inmemory = { version = "0.16.0", features = ["permission-calculator"] } +twilight-cache-inmemory = { version = "0.16.0", features = [ + "permission-calculator", +] } twilight-gateway = "0.16.0" twilight-http = { version = "0.16.0", features = ["simd-json"] } twilight-model = "0.16.0" -twilight-util = { version = "0.16.0", features = ["builder", "permission-calculator", "snowflake"] } +twilight-util = { version = "0.16.0", features = [ + "builder", + "permission-calculator", + "snowflake", +] } twilight-validate = "0.16.0" unicode-segmentation = "1.12.0" unidecode = "0.3.0" diff --git a/playbooks/00-vault.yml b/playbooks/00-vault.yml index b437142..3fd3b6e 100644 --- a/playbooks/00-vault.yml +++ b/playbooks/00-vault.yml @@ -1,14 +1,24 @@ $ANSIBLE_VAULT;1.1;AES256 -31353838363564633532353539313763643561396661313030346466653839663931323961663362 -6333376338336336346562643136316439393962356236640a653836643066346564663363633364 -30616634363430646335663339613333616334393037333065336664396338346135353239346261 -3366303231616166300a613566643231303066373266646665343637353364303939346464323633 -37623565643063353435376238326564353563653735393164616136373531356135666337353765 -39326463633965383463353335306432326433313132373461633666343934616638346666306339 -36313561363965663662313163663362333466663135363731643737386466643134396564353439 -32313936316432313433336235643337386430633434363764666439386234323933313465306638 -65396532396533303662326338376661343962613432393735356130613165626465656464343434 -63646265333064623735646161656236623366623265626664313564316665396331616631613536 -38646264656563353934383237626534663563666335666430326562303862616461343935393737 -62343637336563383864383732303861633634303061376666353231323331643538333633643762 -35623539303562643763336232353633666661626539356465383631336261363532 +38323862623762363734393366316436666137373937653630656665666232333435326166306633 +6438393065663630383537316230336633363932646663300a666666393930376638663537663837 +64366231366561623365363634323466626333626534326631323964613361373339333639623137 +3335376535313338390a373262393230353238373332316464653165363762323634646335613564 +31356633643837643437366130623638643133333336343264623536346339313365663533346566 +61333564323066386639353032306639656465383263616263386563343539313530396662613831 +61393030363264346564626239663531343433616231643732343835333338326538393838396132 +36316331666131616264613461323432663430616562303865636461306264336330646263313439 +66633261333063313162393765653263356263333934366333363037363765646264386632393733 +39663339313939366162656336353563643836376366363032363430306162666331373165643462 +32363930373231646135306466613935646636386639643137313830346531393735373938373531 +63356665613434353162366638396339396130643066336135616433633830313736343265646165 +61373461616363623239616534396431646561333630666230633766363832613365636664633865 +32626636393262303235626132666661623134373766663135643131626363383238363836326232 +62363962613965356165653134366235376364333965303361643634636231323639373132623336 +33383532383237636436303164396531343134633838373936646132353132386465636330363161 +65653937313032346138373435656663653639653133373564366137363261326438336436303330 +32386434663236643132326536306437653231383366366363666461323931613839383762343361 +38343138613466346335396136313334343731313265633365646666366131653837343664663666 +62616336386339393465626138613465316334303239643335633239666165373630333135373062 +35353530643164643732633732336364326161366666333233313833313939663535653763636237 +62633064363561323065653162336134643338623065356536613961303034323235363631343530 +663832616435656433306266643463373930 diff --git a/playbooks/09-payphone.yml b/playbooks/09-payphone.yml index e78b16b..8b3237e 100644 --- a/playbooks/09-payphone.yml +++ b/playbooks/09-payphone.yml @@ -49,6 +49,7 @@ type: Opaque stringData: PAYPHONE_TOKEN: "{{ bot_token }}" + PAYPHONE_TOPGG_TOKEN: "{{ topgg_token }}" kubeconfig: /etc/rancher/k3s/k3s.yaml - name: Set Git credentials diff --git a/src/cli.rs b/src/cli.rs index a0b7db8..3bac15b 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -230,6 +230,14 @@ pub enum Commands { default_value_t = 0 )] bot_owner_id: u64, + + #[arg( + long, + env = "PAYPHONE_TOPGG_TOKEN", + value_name = "TOKEN", + help = "The token to use for the Top.gg API, used for posting server counts and other stats. If not provided, Top.gg integration will be disabled." + )] + topgg_token: Option, }, /// Starts a documentation server for the project which serves `cargo doc` and refreshes on diff --git a/src/framework/bot.rs b/src/framework/bot.rs index 326745f..948165f 100644 --- a/src/framework/bot.rs +++ b/src/framework/bot.rs @@ -1,7 +1,8 @@ -use std::{fmt::Debug, sync::Arc}; +use std::{fmt::Debug, sync::Arc, time::Duration}; use async_trait::async_trait; use thiserror::Error; +use topgg::Stats; use twilight_cache_inmemory::{DefaultInMemoryCache, ResourceType}; use twilight_gateway::{ConfigBuilder, Event, EventTypeFlags, Intents, Shard, ShardId, StreamExt}; use twilight_http::Client; @@ -113,6 +114,7 @@ pub struct Bot { on_server_create_handlers: Vec>>, on_server_update_handlers: Vec>>, on_server_delete_handlers: Vec>>, + topgg_token: Option, } impl Bot @@ -145,6 +147,7 @@ where on_server_create_handlers: Vec::new(), on_server_update_handlers: Vec::new(), on_server_delete_handlers: Vec::new(), + topgg_token: None, } } @@ -173,6 +176,7 @@ where self } + #[allow(dead_code)] pub fn task(mut self, task: impl Task + 'static) -> Self { self.tasks.push(Arc::new(task)); self @@ -237,6 +241,11 @@ where self } + pub fn topgg_token(mut self, token: impl ToString) -> Self { + self.topgg_token = Some(token.to_string()); + self + } + pub async fn run(self, token: &str) -> Result<(), RuntimeError> { let http = Client::new(token.to_string()); let app = http @@ -248,6 +257,60 @@ where .await .inspect_err(|e| log::error!("Could not parse application data! {e:?}")) .map_err(|_| RuntimeError::ApplicationFetchingFailed)?; + + if let Some(topgg_token) = &self.topgg_token + && self.shard.number() == 0 + { + let topgg_token = topgg_token.clone(); + let http = Client::new(token.to_string()); + tokio::spawn(async move { + let topgg_client = topgg::Client::new(topgg_token); + + loop { + let app = match http + .current_user_application() + .await + .map_err(|_| RuntimeError::ApplicationFetchingFailed) + { + Ok(v) => { + match v + .model() + .await + .map_err(|_| RuntimeError::ApplicationFetchingFailed) + { + Ok(app) => app, + Err(err) => { + log::warn!( + "Could not parse application data, skipping stats post to Top.gg! {err:?}" + ); + continue; + } + } + } + Err(err) => { + log::warn!( + "Could not fetch application data, skipping stats post to Top.gg! {err:?}" + ); + continue; + } + }; + + topgg_client + .post_stats(Stats::from_count( + app.approximate_guild_count.unwrap() as usize, + Some(self.shard.total() as usize), + )) + .await + .inspect_err(|err| { + log::warn!("Could not report bot stats to Top.gg: {err}") + }) + .ok(); + + tokio::time::sleep(Duration::from_secs(120)).await; + } + }); + } + let registry = ComponentRegistry::new(); for component in &self.components { diff --git a/src/groups/calls/strings/tips.json b/src/groups/calls/strings/tips.json index ece778d..7cbe409 100644 --- a/src/groups/calls/strings/tips.json +++ b/src/groups/calls/strings/tips.json @@ -15,7 +15,7 @@ "Help us sharing Payphone to make it more active!", "Emojis will only show if they're from a server Payphone's in.", "You cannot send links.", - "[Vote for Payphone on top.gg]() to help us reach more users!", + "[Vote for Payphone on top.gg]() to see more people around!", "[Write a review]() to tell everyone your opinion about Payphone!", "Calls will be automatically hung up after 15 minutes if nobody talks.", "You can change Payphone's prefix with `{prefix}prefix`.", diff --git a/src/main.rs b/src/main.rs index a4d8a76..c53e4f6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -192,6 +192,7 @@ pub async fn main() { shard, redis_urls, bot_owner_id, + topgg_token } => { start( token, @@ -201,6 +202,7 @@ pub async fn main() { shard.into(), redis_urls, bot_owner_id, + topgg_token ) .await; } @@ -256,6 +258,7 @@ impl ExtrasGetter for PayphoneExtrasGetter { } /// Starts a Payphone shard. +#[allow(clippy::too_many_arguments)] async fn start( token: String, database_addr: String, @@ -264,6 +267,7 @@ async fn start( shard: ShardId, redis_urls: Vec, bot_owner_id: u64, + topgg_token: Option, ) { log::info!("Welcome to Payphone, Nyeki!"); log::info!("Payphone is running on version v{VERSION}"); @@ -289,7 +293,7 @@ async fn start( init_color_fetching_queue_listener(color_queue_receiver, state.clone()); - let bot = Bot::new(state, ServerPrefixOrPayphoneMention, PayphoneExtrasGetter) + let mut bot = Bot::new(state, ServerPrefixOrPayphoneMention, PayphoneExtrasGetter) .shard(shard) .intent(Intents::GUILDS) .intent(Intents::GUILD_MESSAGES) @@ -348,6 +352,10 @@ async fn start( .expect("Could not set bot presence since the parameters passed were invalid"), ); + if let Some(topgg_token) = topgg_token { + bot = bot.topgg_token(topgg_token); + } + bot.run(&token).await.expect("Could not run bot!"); }