diff --git a/.github/workflows/deploy_to_minebot_server.yml b/.github/workflows/deploy_to_minebot_server.yml index 322957d..9590fee 100644 --- a/.github/workflows/deploy_to_minebot_server.yml +++ b/.github/workflows/deploy_to_minebot_server.yml @@ -92,7 +92,19 @@ jobs: docker compose pull docker compose down docker compose up -d - - - + + webhook: + needs: + - deploy + runs-on: ubuntu-latest + steps: + - name: Discord Webhook Action + uses: tsickert/discord-webhook@v5.3.0 + with: + webhook-url: ${{ secrets.MINEBOT__WEBHOOK__URL }} + embed-title: "Minebot" + embed-color: 4771125 + embed-description: "Uma nova versão do bot foi deployada e já está disponível para uso!" + username: "Minebot" + diff --git a/Cargo.lock b/Cargo.lock index 531e990..3fadf38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -129,6 +129,61 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "axum" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +dependencies = [ + "async-trait", + "axum-core", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "hyper 1.3.1", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper 1.0.1", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper 0.1.2", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "backtrace" version = "0.3.73" @@ -719,6 +774,29 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "http-body" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "pin-project-lite", +] + [[package]] name = "httparse" version = "1.9.3" @@ -749,7 +827,7 @@ dependencies = [ "futures-util", "h2", "http 0.2.12", - "http-body", + "http-body 0.4.6", "httparse", "httpdate", "itoa", @@ -761,6 +839,25 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", +] + [[package]] name = "hyper-rustls" version = "0.24.2" @@ -769,12 +866,27 @@ checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http 0.2.12", - "hyper", + "hyper 0.14.29", "rustls 0.21.12", "tokio", "tokio-rustls 0.24.1", ] +[[package]] +name = "hyper-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "hyper 1.3.1", + "pin-project-lite", + "tokio", +] + [[package]] name = "iana-time-zone" version = "0.1.60" @@ -1017,6 +1129,12 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + [[package]] name = "memchr" version = "2.7.4" @@ -1044,6 +1162,7 @@ name = "minebot" version = "0.1.0" dependencies = [ "async-minecraft-ping", + "axum", "config", "dotenv", "env_logger", @@ -1180,6 +1299,26 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "pin-project-lite" version = "0.2.14" @@ -1343,8 +1482,8 @@ dependencies = [ "futures-util", "h2", "http 0.2.12", - "http-body", - "hyper", + "http-body 0.4.6", + "hyper 0.14.29", "hyper-rustls", "ipnet", "js-sys", @@ -1359,7 +1498,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 0.1.2", "system-configuration", "tokio", "tokio-rustls 0.24.1", @@ -1470,6 +1609,12 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + [[package]] name = "ryu" version = "1.0.18" @@ -1560,6 +1705,16 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" +dependencies = [ + "itoa", + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -1718,6 +1873,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" + [[package]] name = "synstructure" version = "0.13.1" @@ -1907,6 +2068,28 @@ dependencies = [ "tokio", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + [[package]] name = "tower-service" version = "0.3.2" diff --git a/Cargo.toml b/Cargo.toml index b743dcb..e7a259d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,9 +10,9 @@ dotenv = "0.15.0" serenity = "0.12" tokio = { version = "1.21.2", features = ["macros", "rt-multi-thread"] } async-minecraft-ping = "0.8.0" -#config = "0.14.0" config = { version = "0.14.0", default-features = false, features = [] } serde = "1.0.203" poise = "0.6.1" env_logger = "0.11.3" log = "0.4.21" +axum = "0.7.5" diff --git a/src/commands/status/embeds/status/error.rs b/src/commands/status/embeds/error.rs similarity index 100% rename from src/commands/status/embeds/status/error.rs rename to src/commands/status/embeds/error.rs diff --git a/src/commands/status/embeds/mod.rs b/src/commands/status/embeds/mod.rs index 822c729..9cadc24 100644 --- a/src/commands/status/embeds/mod.rs +++ b/src/commands/status/embeds/mod.rs @@ -1 +1,2 @@ -pub mod status; +pub mod error; +pub mod success; diff --git a/src/commands/status/embeds/status/mod.rs b/src/commands/status/embeds/status/mod.rs deleted file mode 100644 index 9cadc24..0000000 --- a/src/commands/status/embeds/status/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod error; -pub mod success; diff --git a/src/commands/status/embeds/status/success.rs b/src/commands/status/embeds/success.rs similarity index 100% rename from src/commands/status/embeds/status/success.rs rename to src/commands/status/embeds/success.rs diff --git a/src/commands/status/mod.rs b/src/commands/status/mod.rs index 2f5f641..344d57b 100644 --- a/src/commands/status/mod.rs +++ b/src/commands/status/mod.rs @@ -1,8 +1,8 @@ use log::info; use poise::CreateReply; -use crate::commands::status::embeds::status::error::create_failure_embed; -use crate::commands::status::embeds::status::success::create_success_embed; +use crate::commands::status::embeds::error::create_failure_embed; +use crate::commands::status::embeds::success::create_success_embed; use crate::types::{MinebotError, MinebotPoiseContext}; mod embeds; diff --git a/src/event_handler.rs b/src/event_handler.rs new file mode 100644 index 0000000..69940b6 --- /dev/null +++ b/src/event_handler.rs @@ -0,0 +1,16 @@ +use poise::serenity_prelude; + +use crate::{config::MinebotConfig, types::MinebotError}; + +pub async fn event_handler( + event: &serenity_prelude::FullEvent, + _framework: poise::FrameworkContext<'_, MinebotConfig, MinebotError>, +) -> Result<(), MinebotError> { + match event { + serenity::all::FullEvent::Ready { data_about_bot, .. } => { + println!("Logged in as {}", data_about_bot.user.name); + } + _ => {} + } + Ok(()) +} diff --git a/src/http/handlers/mod.rs b/src/http/handlers/mod.rs new file mode 100644 index 0000000..3b4d28a --- /dev/null +++ b/src/http/handlers/mod.rs @@ -0,0 +1,40 @@ +use std::sync::Arc; + +use axum::Json; +use serenity::{ + all::{ChannelId, CreateEmbed, CreateMessage}, + model::colour, +}; +use tokio::sync::Mutex; + +use crate::{types::MessagePayload, BotState}; + +pub async fn send_message( + axum::Extension(state): axum::Extension>>, + Json(payload): Json, +) -> Result { + let state = state.lock().await; + let http = &state.http; + + match ChannelId::new(payload.channel_id) + .send_message( + &http, + CreateMessage::new().add_embed( + CreateEmbed::new() + .title("Message from Minecraft") + .fields(vec![ + ("User", &payload.user, false), + ("Message", &payload.content, false), + ]) + .color(colour::Colour::from_rgb(100, 255, 100)), + ), + ) + .await + { + Ok(_) => Ok("Message sent".to_string()), + Err(err) => Err(( + axum::http::StatusCode::INTERNAL_SERVER_ERROR, + err.to_string(), + )), + } +} diff --git a/src/http/mod.rs b/src/http/mod.rs new file mode 100644 index 0000000..c3d4495 --- /dev/null +++ b/src/http/mod.rs @@ -0,0 +1 @@ +pub mod handlers; diff --git a/src/main.rs b/src/main.rs index 74b5f6f..f671576 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,25 @@ mod commands; mod config; +mod event_handler; mod types; +use std::sync::Arc; use crate::commands::status::server_status; use crate::config::load_config; +use axum::routing::post; +use axum::{Extension, Router}; use dotenv::dotenv; +use http::handlers::send_message; use serenity::all::{ClientBuilder, GuildId}; use serenity::prelude::GatewayIntents; +use tokio::net::TcpListener; +use tokio::sync::Mutex; +mod http; + +#[derive(Clone)] +struct BotState { + http: Arc, +} #[tokio::main] async fn main() { @@ -19,6 +32,9 @@ async fn main() { let framework = poise::Framework::builder() .options(poise::FrameworkOptions { commands: vec![server_status()], + event_handler: |_, event, framework, _| { + Box::pin(event_handler::event_handler(event, framework)) + }, ..Default::default() }) .setup(|ctx, _ready, framework| { @@ -35,9 +51,24 @@ async fn main() { .build(); let intents = GatewayIntents::non_privileged(); - let client = ClientBuilder::new(&c.discord_token, intents) + let mut client = ClientBuilder::new(&c.discord_token, intents) .framework(framework) - .await; + .await + .expect("Error creating client"); + + let http = client.http.clone(); + let bot_state = Arc::new(Mutex::new(BotState { http })); + + tokio::spawn(async move { + if let Err(why) = client.start().await { + println!("Client error: {:?}", why); + } + }); + + let app = Router::new() + .route("/send_message", post(send_message)) + .layer(Extension(bot_state)); - client.unwrap().start().await.unwrap(); + let listener = TcpListener::bind("127.0.0.1:3000").await.unwrap(); + axum::serve(listener, app).await.unwrap(); } diff --git a/src/types.rs b/src/types.rs index df4125d..708d5c3 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,5 +1,14 @@ +use serde::Deserialize; + use crate::config::MinebotConfig; pub type MinebotPoiseContext<'a> = poise::Context<'a, MinebotConfig, MinebotError>; pub type MinebotError = Box; + +#[derive(Deserialize)] +pub struct MessagePayload { + pub channel_id: u64, + pub content: String, + pub user: String, +}