implement /wol

This commit is contained in:
2026-03-20 23:12:52 +03:00
parent 87b4fd3087
commit 39b51da956

View File

@@ -1,12 +1,13 @@
use std::{collections::HashSet, sync::Arc};
use anyhow::Result as AnyhowResult;
use anyhow::{Context as _, Result as AnyhowResult};
use deltachat::{
chat::{self, ChatId},
contact::ContactId,
context::Context,
message::Message,
};
use eui48::MacAddress;
use tokio::sync::Mutex;
use crate::config::BotConfig;
@@ -90,7 +91,83 @@ pub async fn wol_command(
return Ok(());
}
// TODO
let mac = match args.first() {
None => {
match ctx_lock.config.machines.values().find(|m| m.is_default) {
Some(machine) => machine.mac,
None => {
let usage = wol_usage(&ctx_lock.config);
chat::send_text_msg(&dchat_ctx_lock, chat_id, usage).await?;
return Ok(());
}
}
}
Some(arg) => {
if let Some(machine) = ctx_lock.config.machines.get(*arg) {
machine.mac
} else if let Ok(mac) = MacAddress::parse_str(arg) {
mac
} else {
let usage = wol_usage(&ctx_lock.config);
chat::send_text_msg(&dchat_ctx_lock, chat_id, usage).await?;
return Ok(());
}
}
};
let reply = match send_magic_packet(mac).await {
Ok(()) => format!("Magic packet sent to {}.", mac_to_string(mac)),
Err(e) => format!("Failed to send magic packet: {e:#}"),
};
chat::send_text_msg(&dchat_ctx_lock, chat_id, reply).await?;
Ok(())
}
fn wol_usage(config: &BotConfig) -> String {
let mut forms: Vec<String> = Vec::new();
if config.machines.values().any(|m| m.is_default) {
forms.push("/wol".to_owned());
}
let mut names: Vec<&str> = config.machines.keys().map(String::as_str).collect();
names.sort();
if !names.is_empty() {
forms.push(format!("/wol <{}>", names.join("|")));
}
forms.push("/wol <XX:XX:XX:XX:XX:XX>".to_owned());
format!("Usage: {}", forms.join(" OR "))
}
fn mac_to_string(mac: MacAddress) -> String {
let b = mac.as_bytes();
format!(
"{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
b[0], b[1], b[2], b[3], b[4], b[5]
)
}
async fn send_magic_packet(mac: MacAddress) -> AnyhowResult<()> {
let mut packet = [0u8; 102];
packet[..6].fill(0xFF);
let mac_bytes = mac.as_bytes();
for i in 0..16 {
packet[6 + i * 6..6 + (i + 1) * 6].copy_from_slice(mac_bytes);
}
let socket = tokio::net::UdpSocket::bind("0.0.0.0:0")
.await
.context("Failed to bind UDP socket for WoL")?;
socket
.set_broadcast(true)
.context("Failed to enable broadcast on UDP socket")?;
socket
.send_to(&packet, "255.255.255.255:9")
.await
.context("Failed to send magic packet")?;
Ok(())
}
@@ -111,7 +188,7 @@ pub async fn ssh_unlock_disk_command(
return Ok(());
}
// TODO
chat::send_text_msg(&dchat_ctx_lock, chat_id, format!("*ssh unlock disk* {:?}", args)).await?;
Ok(())
}