e-app 0.2.8

MII - Machine Internal Inspection
Documentation
use std::{env, path::PathBuf};

use e_utils::system::cmd;

use crate::{
  drive::DriveNodeInfo,
  input::Opts,
  share::{default_cmd_res, CmdRes, SYSTEM_WIN32},
};

use super::{DriveInfo, DriveStatus, DriveStatusType};

/// 加载内存
pub const EDRIVE_EXE: &[u8] = include_bytes!("../../dist/windows/devcon.exe");

pub const EDRIVE_NAME: &'static str = "e-drive.exe";
/// 获取驱动目录
pub fn get_drive_path() -> PathBuf {
  env::temp_dir().to_path_buf()
}

/// 解析drivernodes数据
pub fn devcon_parse_driver_nodes(info: DriveInfo, node_data: &str) -> Vec<DriveNodeInfo> {
  let mut drive_info_list = Vec::new();
  let mut info = DriveNodeInfo::from(info);
  for _line in node_data.lines() {
    let line = _line.trim_start_matches('\x20');
    if let Some(value) = line.strip_prefix("Name: ") {
      info.name = value.to_string();
    } else if let Some(value) = line.strip_prefix("Driver node #") {
      info.drive_node = value.to_string();
    } else if let Some(value) = line.strip_prefix("Inf file is ") {
      info.inf_file = value.to_string();
    } else if let Some(value) = line.strip_prefix("Inf section is ") {
      info.inf_section = value.to_string();
    } else if let Some(value) = line.strip_prefix("Manufacturer name is ") {
      info.manufacturer_name = value.to_string();
    } else if let Some(value) = line.strip_prefix("Provider name is ") {
      info.provider_name = value.to_string();
    } else if let Some(value) = line.strip_prefix("Driver date is ") {
      info.driver_date = value.to_string();
    } else if let Some(value) = line.strip_prefix("Driver version is ") {
      info.driver_version = value.to_string();
    } else if let Some(value) = line.strip_prefix("Driver node rank is ") {
      info.driver_node_rank = value.to_string();
    } else if let Some(value) = line.strip_prefix("Driver node flags are ") {
      info.driver_node_flags = value.to_string();
      info.signed = line.contains("digitally signed");
      drive_info_list.push(info.clone());
    }
  }
  drive_info_list
}

/// # DevCon 数据处理 Vec<DriveInfo >
pub fn devcon_parse_driver_class(output: &str) -> Vec<DriveInfo> {
  let mut nline = vec![];
  for line in output.lines() {
    if line.contains(':') {
      if let Some((k, v)) = line.split_once(':') {
        let id = k.trim().to_string();
        let driver_descript = v.trim().to_string();
        nline.push(DriveInfo {
          id,
          driver_descript,
        });
      }
    }
  }
  nline
}

/// # DevCon
/// # Example sh
/// devcon findall {* | ID [ID ...] | =class [ID [ID ...]]}
/// ```sh
/// cargo run -- --api Drive --init -- findall *
/// ```
pub fn devcon(command: Vec<&str>) -> CmdRes {
  let mut outres = default_cmd_res();
  let args = command;
  // 执行查询任务
  match cmd(EDRIVE_NAME, args, Some(get_drive_path()), false, true) {
    Ok(output) => {
      let output = output.stdout;
      outres.content = output;
      outres.status = true;
    }
    Err(e) => outres.content = e.to_string(),
  }
  outres
}

/// # PnPUtil
/// # Example sh
/// ```
/// PNPUTIL [/add-driver <...> | /delete-driver <...> |
/// /export-driver <...> | /enum-drivers |
/// /enum-devices [<...>] | /enum-devicetree [<...>] |
/// /disable-device <...> | /enable-device <...> |
/// /restart-device <...> | /remove-device <...> |
/// /scan-devices [<...>] | /enum-classes [<...>] |
/// /enum-interfaces [<...>] | /enum-containers [<...>] |
/// /?]
/// ```
pub fn pnputil(command: Vec<&str>) -> CmdRes {
  let mut outres = default_cmd_res();
  let args = command;
  // 执行查询任务
  match cmd("PNPUTIL", args, Some(SYSTEM_WIN32.into()), false, true) {
    Ok(output) => {
      let output = output.stdout;
      outres.content = output;
      outres.status = true;
    }
    Err(e) => outres.content = e.to_string(),
  }
  outres
}
/// #/enable-device 启用系统上的设备。 从 Windows 10 版本 2004 开始提供命令
/// ```
/// 从 Windows 10 版本 2004 开始可用的标志:
/// /reboot - 如果需要完成操作,请重新启动系统
/// 从 Windows 11 版本 21H2 开始可用的标志:
/// /deviceid <device ID> - 启用具有匹配设备 ID 的所有设备
/// 从 Windows 11 版本 22H2 开始可用的标志:
/// /class <name | GUID> - 按设备类名称或 GUID 进行筛选
/// /bus <name | GUID> - 按总线枚举器名称或总线类型 GUID 进行筛选
/// ```
pub fn pnputil_enable(commands: Vec<&str>) -> CmdRes {
  let mut args = vec!["/enable-device"];
  args.extend(commands);
  pnputil(args)
}
/// #/disable-device 禁用系统上的设备。 从 Windows 10 版本 2004 开始提供命令
/// ```
/// 从 Windows 10 版本 2004 开始可用的标志:
/// /reboot - 如果需要完成操作,请重新启动系统
/// 从 Windows 11 版本 21H2 开始可用的标志:
/// /deviceid <device ID> - 禁用具有匹配设备 ID 的所有设备
/// 从 Windows 11 版本 22H2 开始可用的标志:
/// /class <name | GUID> - 按设备类名称或 GUID 进行筛选
/// /bus <name | GUID> - 按总线枚举器名称或总线类型 GUID 进行筛选
/// /force - 即使设备提供关键系统功能,也禁用
/// ```
pub fn pnputil_disable(commands: Vec<&str>) -> CmdRes {
  let mut args = vec!["/disable-device"];
  args.extend(commands);
  pnputil(args)
}
/// #/remove-device 尝试从系统中删除设备。 从 Windows 10 版本 2004 开始提供命令。
/// ```
/// 从 Windows 10 版本 2004 开始可用的标志:
/// /subtree - 删除整个设备子树,包括任何子设备
/// /reboot - 如果需要完成操作,请重新启动系统
/// 从 Windows 11 版本 21H2 开始可用的标志:
/// /deviceid <device ID> - 删除具有匹配设备 ID 的所有设备
/// 从 Windows 11 版本 22H2 开始可用的标志:
/// /class <name | GUID> - 按设备类名称或 GUID 进行筛选
/// /bus <name | GUID> - 按总线枚举器名称或总线类型 GUID 进行筛选
/// /force - 即使设备提供关键系统功能,也会删除
/// ```
pub fn pnputil_remove(commands: Vec<&str>) -> CmdRes {
  let mut args = vec!["/remove-device"];
  args.extend(commands);
  pnputil(args)
}
/// #/restart-device 尝试从系统中删除设备。 从 Windows 10 版本 2004 开始提供命令。
/// ```
///从 Windows 10 版本 2004 开始可用的标志:
/// /reboot - 如果需要完成操作,请重新启动系统
/// 从 Windows 11 版本 21H2 开始可用的标志:
/// /deviceid <device ID> - 重启具有匹配设备 ID 的所有设备
/// 从 Windows 11 版本 22H2 开始可用的标志:
/// /class <name | GUID> - 按设备类名称或 GUID 进行筛选
/// /bus <name | GUID> - 按总线枚举器名称或总线类型 GUID 进行筛选。
/// ```
pub fn pnputil_restart(commands: Vec<&str>) -> CmdRes {
  let mut args = vec!["/restart-device"];
  args.extend(commands);
  pnputil(args)
}
/// #/add-driver 添加驱动程序包
/// ```
/// pnputil /add-driver c:\oem\*.inf /install
/// pnputil /add-driver x:\driver.inf /install
/// pnputil /add-driver device.inf /install
/// ```
pub fn pnputil_add_driver(commands: Vec<&str>) -> CmdRes {
  let mut args = vec!["/add-driver"];
  args.extend(commands);
  pnputil(args)
}
/// 判断状态
pub fn devcon_status(id: &str) -> DriveStatus {
  let res = devcon(vec!["status", &format!("@{id}")]);
  let mut status = DriveStatus::default();
  status.id = id.to_string();
  let status_f = |v: &str| -> DriveStatusType {
    if v.contains("disable") {
      DriveStatusType::Disabled
    } else if v.contains("running") {
      DriveStatusType::Runing
    } else {
      DriveStatusType::None
    }
  };
  if res.content.contains("matching device(s) found") {
    for _line in res.content.lines() {
      let line = _line.trim();
      if let Some(value) = line.strip_prefix("Name: ") {
        status.name = value.to_string();
      } else if let Some(value) = line.strip_prefix("Driver is ") {
        status.status = status_f(value);
        break;
      } else if let Some(value) = line.strip_prefix("Device is ") {
        status.status = status_f(value);
        break;
      }
    }
  }
  status.content = res.content;
  status
}

/// #/scan-devices 扫描系统是否有任何设备硬件更改。 从 Windows 10 版本 2004 开始提供命令。
/// ```
/// /scan-devices [/instanceid <instance ID>] [/async]
/// 从 Windows 10 版本 2004 开始可用的标志:
/// /instanceid <instance ID> - 扫描设备子树中的更改
/// /async - 异步扫描更改
/// ```
pub fn pnputil_scan() -> CmdRes {
  pnputil(vec!["/scan-devices"])
}
/// #/delete-device 删除驱动程序包
/// ```
/// 删除驱动程序包
/// ```
pub fn pnputil_delete_driver(commands: Vec<&str>) -> CmdRes {
  let mut args = vec!["/delete-driver"];
  args.extend(commands);
  pnputil(args)
}

/// #/export-driver 导出驱动
/// ```
/// pnputil /export-driver oem6.inf .
/// pnputil /export-driver * c:\backup
/// ```
pub fn pnputil_export_driver(commands: Vec<&str>) -> CmdRes {
  let mut args = vec!["/export-driver"];
  args.extend(commands);
  pnputil(args)
}

pub fn find_with_run<F>(opts: &Opts, f: F) -> Vec<DriveStatus>
where
  F: Fn(Vec<&str>) -> CmdRes,
{
  let commands = opts
    .command
    .iter()
    .map(|x| x.as_ref())
    .collect::<Vec<&str>>();
  let devcon_node_list = findnodes(opts, commands);
  let args_src: Vec<&str> = opts.args.iter().map(|x| x.as_ref()).collect();
  let mut res_list = vec![];
  for devcon_node in &devcon_node_list {
    let mut args = args_src.clone();
    args.insert(0, &devcon_node.id);
    let _fres = f(args);
    let status = devcon_status(&devcon_node.id);
    res_list.push(status);
  }
  res_list
}

pub fn findnodes(opts: &Opts, commands: Vec<&str>) -> Vec<DriveNodeInfo> {
  let mut args = vec!["findall"];
  args.extend(commands);
  let res = devcon(args);
  let devcon_class = devcon_parse_driver_class(&res.content);
  let mut devcon_node_list = vec![];
  if opts.full {
    for dclass in &devcon_class {
      // 过滤为空的时,不过滤
      if is_filter(&dclass.driver_descript, &opts.filter) {
        let devcon_node = devcon_drive_node(dclass.clone());
        if devcon_node.len() > 0 {
          devcon_node_list.extend(devcon_node);
        } else {
          devcon_node_list.push(DriveNodeInfo::from(dclass.clone()));
        }
      }
    }
  } else {
    devcon_node_list = devcon_class
      .into_iter()
      .map(|x| DriveNodeInfo::from(x))
      .collect();
  }
  devcon_node_list
}
/// 请求node
pub fn devcon_drive_node(info: DriveInfo) -> Vec<DriveNodeInfo> {
  let node_res = devcon(vec!["drivernodes", &format!("@{}", info.id)]);
  let devcon_node = devcon_parse_driver_nodes(info, &node_res.content);
  devcon_node
}
/// 过滤
pub fn is_filter(data: &str, filters: &Vec<String>) -> bool {
  if filters.len() == 0 {
    return true;
  }
  for f in filters {
    if data.contains(f) {
      return true;
    }
  }
  false
}