main.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "strings"
  6. )
  7. const appVersion = "2.1.0"
  8. // 会话级命名互斥体(Local 前缀无需特权;Global 前缀普通用户常创建失败,会导致单实例失效)
  9. const mutexName = "Local\\DeepSeekTraySingleton"
  10. func main() {
  11. args := os.Args[1:]
  12. cfg := loadConfig()
  13. log := NewLogger()
  14. defer log.Close()
  15. log.Printf("=== deepseek-tray %s args=%v ===", appVersion, args)
  16. if len(args) > 0 {
  17. switch strings.ToLower(strings.TrimLeft(args[0], "-/")) {
  18. case "version":
  19. attachConsole()
  20. fmt.Println(appVersion)
  21. return
  22. case "status":
  23. attachConsole()
  24. printStatus(cfg, log)
  25. return
  26. case "autostart":
  27. attachConsole()
  28. runAutoStartCommand(args, log)
  29. return
  30. case "daemon":
  31. // 无 UI 守护模式(可注册为 Windows 服务):不弹终端、不打开浏览器
  32. runDaemon(cfg, log)
  33. return
  34. case "silent":
  35. // 静默启动(开机自启使用):等同托盘模式,全程无窗口、不打开浏览器
  36. }
  37. }
  38. inst, ok := acquireSingleInstance(mutexName)
  39. if !ok {
  40. attachConsole()
  41. fmt.Println("deepseek-tray 已在运行(托盘或守护进程)")
  42. return
  43. }
  44. defer inst.release()
  45. runTray(cfg, log)
  46. }
  47. // runDaemon 无 UI 守护模式(适合 NSSM 注册为 Windows 服务)。
  48. func runDaemon(cfg *Config, log *Logger) {
  49. log.Printf("以守护模式启动(无托盘)")
  50. inst, ok := acquireSingleInstance(mutexName)
  51. if !ok {
  52. log.Printf("已有实例在运行,退出")
  53. return
  54. }
  55. defer inst.release()
  56. sup := NewSupervisor(cfg, log)
  57. sup.Start()
  58. if cfg.AutoUpdate {
  59. sup.startAutoUpdate()
  60. }
  61. select {}
  62. }
  63. // printStatus 命令行状态查询(同时写日志,便于无控制台场景回溯)。
  64. func printStatus(cfg *Config, log *Logger) {
  65. sup := NewSupervisor(cfg, log)
  66. version := sup.installedVersion()
  67. if version == "" {
  68. version = "未知(未找到 dsh)"
  69. }
  70. lines := []string{
  71. fmt.Sprintf("deepseek-tray %s", appVersion),
  72. fmt.Sprintf("DSH 版本 : %s", version),
  73. fmt.Sprintf("Web 地址 : http://%s:%d", cfg.WebHost, cfg.WebPort),
  74. fmt.Sprintf("端口监听 : %v", isPortOpen(cfg.WebHost, cfg.WebPort)),
  75. fmt.Sprintf("开机自启 : %v", isAutoStartEnabled()),
  76. fmt.Sprintf("定期自动更新: %v(间隔 %d 小时)", cfg.AutoUpdate, cfg.UpdateIntervalH),
  77. fmt.Sprintf("配置文件 : %s", configPath()),
  78. fmt.Sprintf("日志目录 : %s", logDir()),
  79. }
  80. for _, line := range lines {
  81. fmt.Println(line)
  82. log.Printf("status | %s", line)
  83. }
  84. }
  85. // runAutoStartCommand 处理 autostart [on|off] 子命令(无 UI 场景配置自启)。
  86. func runAutoStartCommand(args []string, log *Logger) {
  87. sub := ""
  88. if len(args) > 1 {
  89. sub = strings.ToLower(args[1])
  90. }
  91. switch sub {
  92. case "on":
  93. if err := setAutoStart(true); err != nil {
  94. fmt.Println("设置开机自启失败:", err)
  95. log.Printf("autostart on 失败: %v", err)
  96. return
  97. }
  98. fmt.Println("开机自启:已开启(静默启动,无窗口、不打开浏览器)")
  99. log.Printf("autostart on")
  100. case "off":
  101. if err := setAutoStart(false); err != nil {
  102. fmt.Println("取消开机自启失败:", err)
  103. log.Printf("autostart off 失败: %v", err)
  104. return
  105. }
  106. fmt.Println("开机自启:已关闭")
  107. log.Printf("autostart off")
  108. default:
  109. fmt.Printf("开机自启:%v\n", isAutoStartEnabled())
  110. fmt.Println("用法: deepseek-tray.exe autostart [on|off]")
  111. log.Printf("autostart status: %v", isAutoStartEnabled())
  112. }
  113. }