feat: use embeds for the message and add startup and shutdown messages!

This commit is contained in:
Jet Pham 2025-06-06 19:44:41 -07:00
parent baef052a4a
commit aa434ed39b
No known key found for this signature in database
5 changed files with 99 additions and 17 deletions

View file

@ -2,7 +2,7 @@ use std::env;
use std::time::Instant;
use anyhow::Result;
use serenity::prelude::*;
use serenity::all::{prelude::*, Color, CreateEmbed, CreateMessage};
use serenity::model::id::ChannelId;
use tracing::{info, error};
@ -40,9 +40,21 @@ impl DiscordClient {
let start = Instant::now();
info!("Sending Discord message for circuit event: {:?}", event);
let message = format!("Circuit state changed: {:?}", event);
if let Err(why) = self.channel_id.say(&self.client.http, message).await {
let embed = CreateEmbed::new()
.title(format!("Noisebridge is {}!", event))
.description(match event {
crate::gpio::CircuitEvent::Open => "It's time to start hacking.",
crate::gpio::CircuitEvent::Closed => "We'll see you again soon.",
})
.color(match event {
crate::gpio::CircuitEvent::Open => Color::new(0x00FF00), // Red for open
crate::gpio::CircuitEvent::Closed => Color::new(0xFF0000), // Green for closed
}).thumbnail(match event {
crate::gpio::CircuitEvent::Open => "https://www.noisebridge.net/images/7/7f/Open.png", // Image that says "Open"
crate::gpio::CircuitEvent::Closed => "https://www.noisebridge.net/images/c/c9/Closed.png", // Image that says "Closed"
});
if let Err(why) = self.channel_id.send_message(&self.client.http, CreateMessage::default().add_embed(embed)).await {
error!("Error sending Discord message: {:?}", why);
return Err(anyhow::anyhow!("Failed to send Discord message: {}", why));
}
@ -51,4 +63,44 @@ impl DiscordClient {
info!("Discord message sent successfully in {:?}", duration);
Ok(())
}
pub async fn send_startup_message(&self) -> Result<()> {
let start = Instant::now();
info!("Sending Discord startup message");
let embed = CreateEmbed::new()
.title("Noisebell is starting up!")
.description("The Noisebell service is initializing and will begin monitoring the space status.")
.color(Color::new(0xFFA500)) // Orange for startup
.thumbnail("https://cats.com/wp-content/uploads/2024/07/Beautiful-red-cat-stretches-and-shows-tongue.jpg");
if let Err(why) = self.channel_id.send_message(&self.client.http, CreateMessage::default().add_embed(embed)).await {
error!("Error sending Discord startup message: {:?}", why);
return Err(anyhow::anyhow!("Failed to send Discord startup message: {}", why));
}
let duration = start.elapsed();
info!("Discord startup message sent successfully in {:?}", duration);
Ok(())
}
pub async fn send_shutdown_message(&self) -> Result<()> {
let start = Instant::now();
info!("Sending Discord shutdown message");
let embed = CreateEmbed::new()
.title("Noisebell is shutting down")
.description("The Noisebell service is stopping. Status updates won't go through")
.color(Color::new(0x800080)) // Purple for shutdown
.thumbnail("https://static.vecteezy.com/system/resources/thumbnails/050/619/685/large/a-laptop-computer-on-fire-on-a-desk-in-a-dark-room-video.jpg");
if let Err(why) = self.channel_id.send_message(&self.client.http, CreateMessage::default().add_embed(embed)).await {
error!("Error sending Discord shutdown message: {:?}", why);
return Err(anyhow::anyhow!("Failed to send Discord shutdown message: {}", why));
}
let duration = start.elapsed();
info!("Discord shutdown message sent successfully in {:?}", duration);
Ok(())
}
}

View file

@ -3,6 +3,7 @@ mod discord;
use std::fs;
use std::time::Duration;
use std::sync::Arc;
use anyhow::Result;
use tracing::{error, info};
@ -10,6 +11,22 @@ use tracing_appender::rolling::{RollingFileAppender, Rotation};
use tracing_subscriber::filter::LevelFilter;
use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt};
struct ShutdownGuard {
discord_client: Arc<discord::DiscordClient>,
}
impl Drop for ShutdownGuard {
fn drop(&mut self) {
info!("Shutdown guard triggered");
let runtime = tokio::runtime::Runtime::new().unwrap();
runtime.block_on(async {
if let Err(e) = self.discord_client.send_shutdown_message().await {
error!("Failed to send shutdown message: {}", e);
}
});
}
}
#[tokio::main]
async fn main() -> Result<()> {
info!("creating logs directory");
@ -39,18 +56,27 @@ async fn main() -> Result<()> {
info!("initializing Discord client");
let discord_client = discord::DiscordClient::new().await?;
let discord_client = Arc::new(discord_client);
// Create shutdown guard that will send message on any exit
let _guard = ShutdownGuard {
discord_client: Arc::clone(&discord_client),
};
discord_client.send_startup_message().await?;
const DEFAULT_GPIO_PIN: u8 = 17;
info!("initializing gpio monitor");
let mut gpio_monitor = gpio::GpioMonitor::new(DEFAULT_GPIO_PIN, Duration::from_millis(100))?;
let discord_client = std::sync::Arc::new(discord_client);
let discord_client_clone = discord_client.clone();
// Send initial state
discord_client.clone().send_circuit_event(&gpio_monitor.get_current_state()).await?;
// Set up the callback for state changes
let callback = move |event: gpio::CircuitEvent| {
info!("Circuit state changed: {:?}", event);
let discord_client = discord_client_clone.clone();
info!("Circuit state changed to: {:?}", event);
let discord_client = discord_client.clone();
tokio::spawn(async move {
if let Err(e) = discord_client.send_circuit_event(&event).await {
error!("Failed to send Discord message: {}", e);
@ -58,10 +84,10 @@ async fn main() -> Result<()> {
});
};
info!("starting GPIO monitor");
// Start monitoring - this will block until an error occurs
if let Err(e) = gpio_monitor.monitor(callback).await {
error!("GPIO monitoring error: {}", e);
return Err(anyhow::anyhow!("GPIO monitoring failed"));
}
Ok(())