refactor(notif): Use discord_client crate
- Moved code into a new Rust crate `node-notifier` - Create new crate discord client - node_notifier use now discord client
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,2 +1,2 @@
|
|||||||
/target
|
target
|
||||||
.env
|
.env
|
||||||
1741
discord_client/Cargo.lock
generated
Normal file
1741
discord_client/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
12
discord_client/Cargo.toml
Normal file
12
discord_client/Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "discord_client"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
reqwest = { version = "0.12.22", features = ["blocking", "json"] }
|
||||||
|
serde = "1.0.219"
|
||||||
|
serde_json = "1.0.140"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
mockito = "1.7.0"
|
||||||
68
discord_client/src/lib.rs
Normal file
68
discord_client/src/lib.rs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
pub struct DiscordNotifier {
|
||||||
|
webhook_url: String,
|
||||||
|
username: String,
|
||||||
|
avatar_url: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DiscordNotifier {
|
||||||
|
pub fn new(webhook_url: String, username: String, avatar_url: String) -> DiscordNotifier {
|
||||||
|
DiscordNotifier {
|
||||||
|
webhook_url,
|
||||||
|
username,
|
||||||
|
avatar_url,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_notification(&self, message: &str) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let client = reqwest::blocking::Client::new();
|
||||||
|
let payload = serde_json::json!({
|
||||||
|
"content": message,
|
||||||
|
"username": self.username,
|
||||||
|
"avatar_url": self.avatar_url
|
||||||
|
});
|
||||||
|
|
||||||
|
client
|
||||||
|
.post(&self.webhook_url)
|
||||||
|
.json(&payload)
|
||||||
|
.send()
|
||||||
|
.map(|_| ())
|
||||||
|
.map_err(|e| Box::new(e) as Box<dyn std::error::Error>)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_send_notification() {
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
|
const USERNAME: &str = "TEST_USER";
|
||||||
|
const AVATAR_URL: &str = "https://example.com/avatar.png";
|
||||||
|
const MESSAGE: &str = "Test message";
|
||||||
|
|
||||||
|
let mut server = mockito::Server::new();
|
||||||
|
|
||||||
|
let mock = server
|
||||||
|
.mock("POST", "/")
|
||||||
|
.with_status(204)
|
||||||
|
.match_header("content-type", "application/json")
|
||||||
|
.match_body(mockito::Matcher::Json(json!({
|
||||||
|
"content": MESSAGE,
|
||||||
|
"username": USERNAME,
|
||||||
|
"avatar_url": AVATAR_URL
|
||||||
|
})))
|
||||||
|
.create();
|
||||||
|
|
||||||
|
let webhook_url = server.url();
|
||||||
|
|
||||||
|
let notifier = DiscordNotifier::new(
|
||||||
|
webhook_url.clone(),
|
||||||
|
USERNAME.to_string(),
|
||||||
|
AVATAR_URL.to_string(),
|
||||||
|
);
|
||||||
|
let result = notifier.send_notification(MESSAGE);
|
||||||
|
assert!(
|
||||||
|
result.is_ok(),
|
||||||
|
"{}",
|
||||||
|
format!("Failed to send notification: {:?}", result.err())
|
||||||
|
);
|
||||||
|
mock.assert();
|
||||||
|
}
|
||||||
10
Cargo.lock → node_notifier/Cargo.lock
generated
10
Cargo.lock → node_notifier/Cargo.lock
generated
@@ -93,6 +93,15 @@ version = "0.8.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "discord_client"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"reqwest",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "displaydoc"
|
name = "displaydoc"
|
||||||
version = "0.2.5"
|
version = "0.2.5"
|
||||||
@@ -630,6 +639,7 @@ dependencies = [
|
|||||||
name = "node-notifier"
|
name = "node-notifier"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"discord_client",
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -9,3 +9,4 @@ reqwest = { version = "0.12.22", features = ["blocking", "json"] }
|
|||||||
serde = "1.0.219"
|
serde = "1.0.219"
|
||||||
serde_json = "1.0.140"
|
serde_json = "1.0.140"
|
||||||
sysinfo = "0.35.2"
|
sysinfo = "0.35.2"
|
||||||
|
discord_client = { path = "../discord_client" }
|
||||||
106
node_notifier/src/main.rs
Normal file
106
node_notifier/src/main.rs
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
use discord_client::DiscordNotifier;
|
||||||
|
use dotenvy::dotenv;
|
||||||
|
use sysinfo::{Disks, System};
|
||||||
|
|
||||||
|
fn get_cpu_usage(sys: &System) -> f32 {
|
||||||
|
sys.global_cpu_usage()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_memory_usage(sys: &System) -> f32 {
|
||||||
|
let total_memory = sys.total_memory() as f32;
|
||||||
|
let used_memory = sys.used_memory() as f32;
|
||||||
|
|
||||||
|
used_memory / total_memory * 100.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_swap_usage(sys: &System) -> f32 {
|
||||||
|
let total_swap = sys.total_swap() as f32;
|
||||||
|
let used_swap = sys.used_swap() as f32;
|
||||||
|
|
||||||
|
used_swap / total_swap * 100.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_disk_usage(disks: &Disks) -> f32 {
|
||||||
|
let mut total_used_space = 0.0;
|
||||||
|
let mut total_space = 0.0;
|
||||||
|
|
||||||
|
for disk in disks {
|
||||||
|
if let Some(mount_point) = disk.mount_point().to_str() {
|
||||||
|
if mount_point == "/" || mount_point == "/home" {
|
||||||
|
total_used_space += disk.total_space() as f32 - disk.available_space() as f32;
|
||||||
|
total_space += disk.total_space() as f32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if total_space == 0.0 {
|
||||||
|
return 0.0; // Avoid division by zero
|
||||||
|
}
|
||||||
|
|
||||||
|
(total_used_space / total_space) * 100.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
dotenv().ok();
|
||||||
|
|
||||||
|
let notifier = DiscordNotifier::new(
|
||||||
|
std::env::var("DISCORD_WEBHOOK").expect("DISCORD_WEBHOOK environment variable not set"),
|
||||||
|
"System Monitor".to_string(),
|
||||||
|
"https://cdn.shopify.com/s/files/1/0262/1423/6212/files/Lord_of_the_Rings_eye_of_Sauron_-_Ghtic.com_-_Blog.png?v=1579680018".to_string(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut sys = System::new_all();
|
||||||
|
let mut disks: Disks = Disks::new_with_refreshed_list();
|
||||||
|
sys.refresh_all();
|
||||||
|
disks.refresh(true);
|
||||||
|
|
||||||
|
let cpu_usage = get_cpu_usage(&sys);
|
||||||
|
if cpu_usage > 80.0 {
|
||||||
|
notifier
|
||||||
|
.send_notification(&format!("High CPU usage detected: {cpu_usage:.2}%"))
|
||||||
|
.expect("Failed to send notification for high CPU usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
let memory_usage = get_memory_usage(&sys);
|
||||||
|
if memory_usage > 80.0 {
|
||||||
|
notifier
|
||||||
|
.send_notification(&format!("High memory usage detected: {memory_usage:.2}%"))
|
||||||
|
.expect("Failed to send notification for high memory usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
let swap_usage = get_swap_usage(&sys);
|
||||||
|
if swap_usage > 80.0 {
|
||||||
|
notifier
|
||||||
|
.send_notification(&format!("High swap usage detected: {swap_usage:.2}%"))
|
||||||
|
.expect("Failed to send notification for high swap usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
let disk_usage = get_disk_usage(&disks);
|
||||||
|
if disk_usage > 80.0 {
|
||||||
|
notifier
|
||||||
|
.send_notification(&format!("High disk usage detected: {disk_usage:.2}%"))
|
||||||
|
.expect("Failed to send notification for high disk usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("System Information:");
|
||||||
|
println!("CPU usage: {cpu_usage:.2}%");
|
||||||
|
println!("Memory usage: {memory_usage:.2}%");
|
||||||
|
println!("Swap usage: {swap_usage:.2}%");
|
||||||
|
println!("Disk usage: {disk_usage:.2}%");
|
||||||
|
|
||||||
|
// Send a final notification with all system information
|
||||||
|
let final_message = format!(
|
||||||
|
concat!(
|
||||||
|
"System Information:\n",
|
||||||
|
"CPU usage: {:.2}%\n",
|
||||||
|
"Memory usage: {:.2}%\n",
|
||||||
|
"Swap usage: {:.2}%\n",
|
||||||
|
"Disk usage: {:.2}%"
|
||||||
|
),
|
||||||
|
cpu_usage, memory_usage, swap_usage, disk_usage
|
||||||
|
);
|
||||||
|
|
||||||
|
notifier
|
||||||
|
.send_notification(&final_message)
|
||||||
|
.expect("Failed to send final notification");
|
||||||
|
}
|
||||||
115
src/main.rs
115
src/main.rs
@@ -1,115 +0,0 @@
|
|||||||
use dotenvy::dotenv;
|
|
||||||
use sysinfo::{Disks, System};
|
|
||||||
|
|
||||||
fn get_cpu_usage(sys: &System) -> f32 {
|
|
||||||
sys.global_cpu_usage()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_memory_usage(sys: &System) -> f32 {
|
|
||||||
let total_memory = sys.total_memory() as f32;
|
|
||||||
let used_memory = sys.used_memory() as f32;
|
|
||||||
|
|
||||||
used_memory / total_memory * 100.0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_swap_usage(sys: &System) -> f32 {
|
|
||||||
let total_swap = sys.total_swap() as f32;
|
|
||||||
let used_swap = sys.used_swap() as f32;
|
|
||||||
|
|
||||||
used_swap / total_swap * 100.0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_disk_usage(disks : &Disks) -> f32 {
|
|
||||||
let mut total_used_space = 0.0;
|
|
||||||
let mut total_space = 0.0;
|
|
||||||
|
|
||||||
for disk in disks {
|
|
||||||
if let Some(mount_point) = disk.mount_point().to_str() {
|
|
||||||
if mount_point == "/" || mount_point == "/home" {
|
|
||||||
total_used_space += disk.total_space() as f32 - disk.available_space() as f32;
|
|
||||||
total_space += disk.total_space() as f32;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if total_space == 0.0 {
|
|
||||||
return 0.0; // Avoid division by zero
|
|
||||||
}
|
|
||||||
|
|
||||||
(total_used_space / total_space) * 100.0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn send_notification(webhook_url: &str, message: &str) {
|
|
||||||
let client = reqwest::blocking::Client::new();
|
|
||||||
let payload = serde_json::json!({
|
|
||||||
"content": message,
|
|
||||||
"username": "System Monitor",
|
|
||||||
"avatar_url": "https://cdn.shopify.com/s/files/1/0262/1423/6212/files/Lord_of_the_Rings_eye_of_Sauron_-_Ghtic.com_-_Blog.png?v=1579680018"
|
|
||||||
});
|
|
||||||
|
|
||||||
match client.post(webhook_url).json(&payload).send() {
|
|
||||||
Ok(response) => {
|
|
||||||
if response.status().is_success() {
|
|
||||||
println!("Notification sent successfully.");
|
|
||||||
} else {
|
|
||||||
eprintln!("Failed to send notification: {}", response.status());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => eprintln!("Error sending notification: {}", e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
dotenv().ok();
|
|
||||||
|
|
||||||
let discord_webhook =
|
|
||||||
std::env::var("DISCORD_WEBHOOK").expect("DISCORD_WEBHOOK environment variable not set");
|
|
||||||
|
|
||||||
let mut sys = System::new_all();
|
|
||||||
let mut disks: Disks = Disks::new_with_refreshed_list();
|
|
||||||
sys.refresh_all();
|
|
||||||
disks.refresh(true);
|
|
||||||
|
|
||||||
let cpu_usage = get_cpu_usage(&sys);
|
|
||||||
if cpu_usage > 80.0 {
|
|
||||||
let message = format!("High CPU usage detected: {:.2}%", cpu_usage);
|
|
||||||
send_notification(&discord_webhook, &message);
|
|
||||||
}
|
|
||||||
|
|
||||||
let memory_usage = get_memory_usage(&sys);
|
|
||||||
if memory_usage > 80.0 {
|
|
||||||
let message = format!("High memory usage detected: {:.2}%", memory_usage);
|
|
||||||
send_notification(&discord_webhook, &message);
|
|
||||||
}
|
|
||||||
|
|
||||||
let swap_usage = get_swap_usage(&sys);
|
|
||||||
if swap_usage > 80.0 {
|
|
||||||
let message = format!("High swap usage detected: {:.2}%", swap_usage);
|
|
||||||
send_notification(&discord_webhook, &message);
|
|
||||||
}
|
|
||||||
|
|
||||||
let disk_usage = get_disk_usage(&disks);
|
|
||||||
if disk_usage > 80.0 {
|
|
||||||
let message = format!("High disk usage detected: {:.2}%", disk_usage);
|
|
||||||
send_notification(&discord_webhook, &message);
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("System Information:");
|
|
||||||
println!("CPU usage: {:.2}%", cpu_usage);
|
|
||||||
println!("Memory usage: {:.2}%", memory_usage);
|
|
||||||
println!("Swap usage: {:.2}%", swap_usage);
|
|
||||||
println!("Disk usage: {:.2}%", disk_usage);
|
|
||||||
|
|
||||||
// Send a final notification with all system information
|
|
||||||
let final_message = format!(
|
|
||||||
concat!(
|
|
||||||
"System Information:\n",
|
|
||||||
"CPU usage: {:.2}%\n",
|
|
||||||
"Memory usage: {:.2}%\n",
|
|
||||||
"Swap usage: {:.2}%\n",
|
|
||||||
"Disk usage: {:.2}%"
|
|
||||||
),
|
|
||||||
cpu_usage, memory_usage, swap_usage, disk_usage
|
|
||||||
);
|
|
||||||
send_notification(&discord_webhook, &final_message);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user