initial commit

This commit is contained in:
Hampus Kraft
2026-01-01 20:42:59 +00:00
commit 2f557eda8c
9029 changed files with 1490197 additions and 0 deletions

View File

@@ -0,0 +1,118 @@
/*
* Copyright (C) 2026 Fluxer Contributors
*
* This file is part of Fluxer.
*
* Fluxer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fluxer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
*/
use anyhow::Result;
use serde::Serialize;
use time::OffsetDateTime;
use time::format_description::well_known::Rfc3339;
use tracing::info;
use crate::db::CrashEventData;
#[derive(Serialize)]
struct DiscordWebhookPayload {
embeds: Vec<DiscordEmbed>,
}
#[derive(Serialize)]
struct DiscordEmbed {
title: String,
description: String,
color: u32,
fields: Vec<DiscordField>,
timestamp: String,
footer: DiscordFooter,
}
#[derive(Serialize)]
struct DiscordField {
name: String,
value: String,
inline: bool,
}
#[derive(Serialize)]
struct DiscordFooter {
text: String,
}
pub async fn send_discord_crash_alert(
webhook_url: &str,
crash: &CrashEventData,
admin_endpoint: Option<&str>,
) -> Result<()> {
let timestamp =
OffsetDateTime::from_unix_timestamp_nanos(i128::from(crash.timestamp) * 1_000_000)
.unwrap_or_else(|_| OffsetDateTime::now_utc());
let stacktrace = if crash.stacktrace.len() > 1000 {
format!("{}...\n\n(truncated)", &crash.stacktrace[..1000])
} else {
crash.stacktrace.clone()
};
let guild_link = admin_endpoint.map_or_else(
|| format!("Guild ID: {}", crash.guild_id),
|ep| format!("{ep}/guilds/{}", crash.guild_id),
);
let payload = DiscordWebhookPayload {
embeds: vec![DiscordEmbed {
title: "Guild Crash Detected".to_string(),
description: format!(
"A guild process has crashed on the gateway.\n\n**Guild:** {guild_link}"
),
color: 0x00ED_4245,
fields: vec![
DiscordField {
name: "Guild ID".to_string(),
value: format!("`{}`", crash.guild_id),
inline: true,
},
DiscordField {
name: "Crash ID".to_string(),
value: format!("`{}`", crash.id),
inline: true,
},
DiscordField {
name: "Stacktrace".to_string(),
value: format!("```\n{stacktrace}\n```"),
inline: false,
},
],
timestamp: timestamp.format(&Rfc3339).unwrap_or_default(),
footer: DiscordFooter {
text: "Fluxer Metrics".to_string(),
},
}],
};
let client = reqwest::Client::new();
let response = client.post(webhook_url).json(&payload).send().await?;
if response.status().is_success() {
info!("Discord crash alert sent for guild {}", crash.guild_id);
} else {
let status = response.status();
let body = response.text().await.unwrap_or_default();
anyhow::bail!("Discord webhook failed with status {status}: {body}");
}
Ok(())
}

View File

@@ -0,0 +1,22 @@
/*
* Copyright (C) 2026 Fluxer Contributors
*
* This file is part of Fluxer.
*
* Fluxer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fluxer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
*/
pub mod discord;
pub use discord::*;