use std::{collections::HashMap, fmt::Display, ops::Deref, path::Path};
use tokio::process::Command;
use windows::{Devices::WiFi::WiFiAdapter, core::*};
use crate::{BandWidth, BandWidthArg, Impl, Interface, Mode, WiFiError, WiFiResult};
#[repr(transparent)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ID(GUID);
impl Display for ID {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.0)
}
}
impl Deref for ID {
type Target = GUID;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<GUID> for ID {
fn from(guid: GUID) -> Self {
Self(guid)
}
}
pub struct OS;
impl Impl for OS {
async fn check_environment() -> WiFiResult {
let root = std::env::var("SYSTEMROOT").unwrap();
let path = Path::new(&root).join("System32").join("Npcap");
if !path.exists() {
return Err(WiFiError::new_system(
"Npcap not installed, see https://crates.io/crates/pcap",
));
}
Ok(())
}
async fn interface_list() -> std::result::Result<Vec<Interface>, crate::WiFiError> {
let id_list = interface_id_list().await?;
let mut out = Vec::new();
for id in id_list.into_iter() {
let support_mode = interface_support_modes(&id).await?;
out.push(Interface { id, support_mode });
}
Ok(out)
}
async fn set_mode(id: &ID, mode: Mode) -> WiFiResult {
run_wlan_helper_command(id, &["mode", mode.cmd()]).await
}
async fn set_channel(id: &ID, channel: usize, _band_width: Option<BandWidthArg>) -> WiFiResult {
run_wlan_helper_command(id, &["channel", &channel.to_string()]).await
}
async fn ifup(_id: &ID) -> WiFiResult {
Ok(())
}
async fn ifdown(_id: &ID) -> WiFiResult {
Ok(())
}
async fn freq_max_bandwidth(
_id: &ID,
) -> WiFiResult<std::collections::HashMap<usize, BandWidth>> {
Ok(HashMap::new())
}
}
impl From<windows::core::Error> for WiFiError {
fn from(value: windows::core::Error) -> Self {
WiFiError::System(value.to_string())
}
}
fn wlan_helper() -> WiFiResult<Command> {
let root = std::env::var("SYSTEMROOT").unwrap();
let path = Path::new(&root).join("System32").join("Npcap");
if !path.exists() {
Err(WiFiError::new_system(
"Npcap not installed, see https://crates.io/crates/pcap",
))?;
}
let mut cmd = Command::new("WlanHelper.exe");
cmd.env("PATH", format!("{};%PATH%", path.display()));
Ok(cmd)
}
async fn run_wlan_helper_command(id: &ID, args: &[&str]) -> WiFiResult {
let mut cmd = wlan_helper()?;
cmd.arg(id.to_string());
for arg in args {
cmd.arg(arg);
}
let output = cmd.output().await?;
if !output.status.success() {
let out = String::from_utf8_lossy(&output.stdout);
return Err(WiFiError::new_system(out.to_string()));
}
Ok(())
}
async fn interface_support_modes(id: &ID) -> WiFiResult<Vec<Mode>> {
let mut cmd = wlan_helper()?;
let out = cmd.arg(format!("{id:?}")).arg("modes").output().await?;
let stdout = String::from_utf8_lossy(&out.stdout);
let modes = stdout
.trim()
.split(',')
.filter_map(|o| o.try_into().ok())
.collect();
Ok(modes)
}
async fn interface_id_list() -> Result<Vec<ID>> {
let adapters = WiFiAdapter::FindAllAdaptersAsync()?.get()?;
let mut adapter_names = Vec::new();
for adapter in adapters {
if let Ok(adapter) = adapter.NetworkAdapter() {
let id = adapter.NetworkAdapterId()?;
adapter_names.push(id.into());
}
}
Ok(adapter_names)
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_get_wifi_adapter_names() {
match OS::interface_list().await {
Ok(adapters) => {
println!("找到以下WiFi适配器:");
for (i, name) in adapters.iter().enumerate() {
println!("{}. {:?}", i + 1, name);
}
}
Err(e) => println!("获取WiFi适配器失败: {:?}", e),
}
}
#[tokio::test]
async fn test_wlan_helper() {
let mut wlan_helper = wlan_helper().unwrap();
let out = wlan_helper.arg("-h").output().await.unwrap();
println!("{}", String::from_utf8_lossy(&out.stdout));
}
#[tokio::test]
async fn test_wlan_helper_mode() {}
}