power_shutdown.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. // ============================================================================
  2. // power_shutdown.go — 延时关机(工具页)
  3. //
  4. // 用户在工具页输入「多少分钟后关机」,调用 ShutdownDelay 下发系统关机倒计时。
  5. // 复用 pccontrol.go 的系统命令构造(shutdown /s /t N /f),交给 Windows 系统计时,
  6. // 即使本程序退出,倒计时仍由系统执行。返回计划执行时间供前端展示。
  7. // ============================================================================
  8. package main
  9. import (
  10. "fmt"
  11. "strings"
  12. "time"
  13. )
  14. // ShutdownDelay 在指定分钟后执行关机。
  15. // minutes 必须 > 0;返回计划执行时间(HH:MM:SS)与提示信息。
  16. func (s *SettingsService) ShutdownDelay(minutes int) (string, error) {
  17. if minutes <= 0 {
  18. return "", fmt.Errorf("关机分钟数必须大于 0")
  19. }
  20. if minutes > 24*60 {
  21. return "", fmt.Errorf("关机分钟数过大(最多 24 小时)")
  22. }
  23. delaySec := minutes * 60
  24. cmd := pcSystemCommand(pcPoweroff, delaySec)
  25. if cmd == nil {
  26. return "", fmt.Errorf("当前系统不支持 shutdown 命令")
  27. }
  28. // 标记为待执行(与 API 路由共用状态,便于「主机」页取消)
  29. pcMu.Lock()
  30. if pcPending {
  31. remaining := time.Until(pcExecuteAt).Round(time.Second)
  32. pcMu.Unlock()
  33. return "", fmt.Errorf("已有待执行的电源命令,剩余 %v", remaining)
  34. }
  35. pcPending = true
  36. pcPendingCmd = pcPoweroff
  37. pcExecuteAt = time.Now().Add(time.Duration(delaySec) * time.Second)
  38. pcSystemTimer = true
  39. pcLastCmd = pcPoweroff
  40. pcLastTime = time.Now()
  41. pcRequested = true
  42. pcMu.Unlock()
  43. if output, err := cmd.CombinedOutput(); err != nil {
  44. pcMu.Lock()
  45. pcPending = false
  46. pcPendingCmd = ""
  47. pcExecuteAt = time.Time{}
  48. pcSystemTimer = false
  49. pcMu.Unlock()
  50. return "", fmt.Errorf("关机命令下发失败: %v | %s", err, strings.TrimSpace(string(output)))
  51. }
  52. execAt := pcExecuteAt.Format("15:04:05")
  53. fmt.Fprintf(apiLogRing, "[SYS] 工具页延时关机 | %d 分钟后(%s)\n", minutes, execAt)
  54. return execAt, nil
  55. }
  56. // CancelShutdown 取消延时关机(工具页「取消」按钮调用)。
  57. func (s *SettingsService) CancelShutdown() error {
  58. pcMu.Lock()
  59. if !pcPending || pcPendingCmd != pcPoweroff {
  60. pcMu.Unlock()
  61. return fmt.Errorf("当前没有待执行的关机命令")
  62. }
  63. pcPending = false
  64. pcPendingCmd = ""
  65. pcExecuteAt = time.Time{}
  66. pcSystemTimer = false
  67. pcMu.Unlock()
  68. pcAbortShutdown()
  69. fmt.Fprintln(apiLogRing, "[SYS] 工具页取消延时关机")
  70. return nil
  71. }