diff --git a/CHANGELOG.md b/CHANGELOG.md index 4df2737..c759e4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Hydrogen // Changelog +## [Unreleased] + +### Added + +- Add a warning about the public instance ending. +- Add Portuguese Brazil translation to the public instance warning. + ## [0.0.1-alpha.7] - 2024-04-15 ### Added diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index db56028..42bb4b6 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -2,6 +2,11 @@ "generic": { "embed_footer": "Hydrogen by Nashira Deer" }, + "public_instance": { + "title": "Hydrogen public instance is ending!", + "ending": "It will be ending on {time}. But you can still use it by hosting your own instance. Check the [GitHub repository]({url}) for more information.", + "running_in": "Your command will be executed in {time}." + }, "error": { "not_intentional": "If you believe this is an error, please report it [here]({url}).", "unknown": "An unknown error has happened! Please report it [here]({url}).", diff --git a/assets/langs/pt-BR.json b/assets/langs/pt-BR.json index 021981e..44ff140 100644 --- a/assets/langs/pt-BR.json +++ b/assets/langs/pt-BR.json @@ -2,6 +2,11 @@ "generic": { "embed_footer": "Hydrogen por Nashira Deer" }, + "public_instance": { + "title": "A instância pública de Hydrogen está terminando!", + "ending": "Ela será terminada no dia {time}. Se você gostaria de continuar usando Hydrogen, você pode hospedar sua própria instância. Cheque o [repositório do GitHub]({url}) para mais informações.", + "running_in": "Seu comando será executado em {time}." + }, "error": { "not_intentional": "Se você acredita que isso é um erro, por favor reporte [aqui]({url}).", "unknown": "Um erro estranho ocorreu! Por favor reporte [aqui]({url}).", diff --git a/src/handler.rs b/src/handler.rs index d70113a..93f210a 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -2,12 +2,21 @@ //! //! Command and component handler for Hydrogen. Created to decrease the repeated code and heap allocations from the original handler. -use std::{collections::HashMap, result, sync::Arc, time::Duration}; +use std::{ + collections::HashMap, + result, + sync::Arc, + time::{Duration, SystemTime}, +}; use dashmap::DashMap; use hydrogen_i18n::I18n; +use rand::{thread_rng, Rng}; use serenity::{ - all::{ChannelId, Command, CommandId, CommandInteraction, ComponentInteraction, UserId}, + all::{ + ChannelId, Command, CommandId, CommandInteraction, ComponentInteraction, + CreateInteractionResponse, CreateInteractionResponseMessage, UserId, + }, builder::{CreateEmbed, CreateEmbedFooter, EditInteractionResponse}, client::Context, http::{CacheHttp, Http}, @@ -16,8 +25,9 @@ use tokio::{spawn, sync::RwLock, task::JoinHandle, time::sleep}; use tracing::{debug, error, info, warn}; use crate::{ - commands, components, HydrogenContext, HYDROGEN_ERROR_COLOR, HYDROGEN_LOGO_URL, - HYDROGEN_PRIMARY_COLOR, + commands, components, HydrogenContext, HYDROGEN_COLOR, HYDROGEN_ERROR_COLOR, HYDROGEN_LOGO_URL, + HYDROGEN_PRIMARY_COLOR, HYDROGEN_REPOSITORY_URL, HYDROGEN_WARNING_PROBABILITY, + HYDROGEN_WARNING_TIMEOUT, }; /// Type returned by commands and components to indicate how to respond to the interaction. @@ -44,10 +54,23 @@ pub async fn handle_command( context: &Context, command: &CommandInteraction, ) { - // Defer the interaction to avoid the "This interaction failed" message. - if let Err(e) = command.defer_ephemeral(&context.http).await { - error!("(handle_command): failed to defer interaction: {}", e); - return; + if thread_rng().gen_bool(HYDROGEN_WARNING_PROBABILITY) && hydrogen.public_instance { + // Send a message to the user. + if let Err(e) = command + .create_response(&context.http, hydrogen_end_message(command, &hydrogen.i18n)) + .await + { + error!("(handle_command): cannot respond to the interaction: {}", e); + return; + } + + sleep(Duration::from_secs(HYDROGEN_WARNING_TIMEOUT)).await; + } else { + // Defer the interaction to avoid the "This interaction failed" message. + if let Err(e) = command.defer_ephemeral(&context.http).await { + error!("(handle_command): failed to defer interaction: {}", e); + return; + } } // Execute the command. @@ -223,3 +246,41 @@ async fn autoremover( debug!("(autoremover): removing response {:?} from cache...", key); responses.remove(&key); } + +fn hydrogen_end_message(command: &CommandInteraction, i18n: &I18n) -> CreateInteractionResponse { + CreateInteractionResponse::Message( + CreateInteractionResponseMessage::new() + .ephemeral(true) + .embed( + CreateEmbed::new() + .title(i18n.translate(&command.locale, "public_instance", "title")) + .description(format!( + "{}\n\n{}", + i18n.translate(&command.locale, "public_instance", "ending") + .replace("{time}", "") + .replace("{url}", HYDROGEN_REPOSITORY_URL), + i18n.translate(&command.locale, "public_instance", "running_in") + .replace( + "{time}", + &format!( + "", + (SystemTime::now() + + Duration::from_secs(HYDROGEN_WARNING_TIMEOUT + 2)) + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_secs() + ) + ) + )) + .color(HYDROGEN_COLOR) + .footer( + CreateEmbedFooter::new(i18n.translate( + &command.locale, + "generic", + "embed_footer", + )) + .icon_url(HYDROGEN_LOGO_URL), + ), + ), + ) +} diff --git a/src/main.rs b/src/main.rs index 6f29cac..523eb17 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,6 +45,9 @@ pub const HYDROGEN_ERROR_COLOR: i32 = 0xf04747; pub const HYDROGEN_EMPTY_CHAT_TIMEOUT: u64 = 10; pub const HYDROGEN_QUEUE_LIMIT: usize = 1000; pub const HYDROGEN_SEARCH_PREFIX: &str = "ytsearch:"; +pub const HYDROGEN_WARNING_TIMEOUT: u64 = 10; +pub const HYDROGEN_WARNING_PROBABILITY: f64 = 0.1; +pub const HYDROGEN_COLOR: i32 = 0x009b60; pub const LAVALINK_CONNECTION_TIMEOUT: u64 = 5000; pub static HYDROGEN_LOGO_URL: &str = @@ -79,6 +82,8 @@ struct HydrogenContext { /// The responses from the components. pub components_responses: Arc, ComponentInteraction)>>, + /// Whether this is the public instance. + pub public_instance: bool, } #[derive(Clone)] @@ -300,6 +305,10 @@ async fn main() { // Load configuration from file or environment. let mut config = load_configuration().or_from_env(); + if config.public_instance.unwrap_or_default() { + warn!("you are running this instance as a public instance"); + } + // Load language files. if let Some(language_path) = config.language_path { if let Err(e) = @@ -352,6 +361,7 @@ async fn main() { commands_id: Arc::new(RwLock::new(HashMap::new())), i18n: Arc::new(i18n), components_responses: Arc::new(DashMap::new()), + public_instance: config.public_instance.unwrap_or_default(), time_parsers, roll_parser, },