| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- package main
- import (
- _ "embed"
- "fmt"
- "os"
- "os/exec"
- "strings"
- "time"
- "github.com/getlantern/systray"
- )
- //go:embed icon.ico
- var iconData []byte
- func runTray(cfg *Config, log *Logger) {
- sup := NewSupervisor(cfg, log)
- systray.Run(func() {
- systray.SetIcon(iconData)
- systray.SetTooltip("DeepSeek Tray - dsh web 守护")
- trayReady(sup, cfg, log)
- }, func() {
- log.Printf("托盘退出,停止服务")
- sup.Stop()
- })
- }
- func trayReady(sup *Supervisor, cfg *Config, log *Logger) {
- mStatus := systray.AddMenuItem("状态:初始化…", "当前服务状态")
- mURL := systray.AddMenuItem("打开 Web 界面", cfgURL(cfg))
- systray.AddSeparator()
- mStart := systray.AddMenuItem("启动服务", "启动 dsh web")
- mStop := systray.AddMenuItem("停止服务", "停止 dsh web")
- mRestart := systray.AddMenuItem("重启服务", "重启 dsh web")
- systray.AddSeparator()
- mAutoStart := systray.AddMenuItemCheckbox("开机自启", "登录 Windows 时自动启动托盘并守护服务", isAutoStartEnabled())
- mAutoUpdate := systray.AddMenuItemCheckbox("定期自动更新", "按间隔检查并更新 dsh", cfg.AutoUpdate)
- mUpdateNow := systray.AddMenuItem("立即更新 DSH", "npm install -g @deepseek-ai/dsh@latest")
- systray.AddSeparator()
- mVersion := systray.AddMenuItem("版本:查询中…", "已安装的 DSH 版本")
- mLogs := systray.AddMenuItem("查看日志", "打开日志目录")
- mConfig := systray.AddMenuItem("打开配置文件", "打开 config.json")
- systray.AddSeparator()
- mQuit := systray.AddMenuItem("退出", "停止服务并退出托盘")
- mStop.Disable()
- // 状态刷新(3 秒)
- go func() {
- ticker := time.NewTicker(3 * time.Second)
- defer ticker.Stop()
- for range ticker.C {
- st := sup.Status()
- switch {
- case st.Updating:
- mStatus.SetTitle("状态:正在更新…")
- case st.Running:
- mStatus.SetTitle(fmt.Sprintf("状态:运行中 (PID %d)", st.PID))
- default:
- mStatus.SetTitle("状态:已停止")
- }
- if st.Restarts > 0 {
- mStatus.SetTooltip(fmt.Sprintf("自动重启次数:%d;最近错误:%s", st.Restarts, st.LastError))
- } else {
- mStatus.SetTooltip("服务运行正常")
- }
- mURL.SetTitle("打开 Web 界面:" + shortURL(st.URL))
- if st.Running {
- mStart.Disable()
- mStop.Enable()
- } else {
- mStart.Enable()
- mStop.Disable()
- }
- }
- }()
- // 版本刷新(启动一次 + 每 10 分钟)
- go func() {
- for {
- v := sup.installedVersion()
- if v == "" {
- v = "未知"
- }
- mVersion.SetTitle("版本:" + v)
- time.Sleep(10 * time.Minute)
- }
- }()
- // 菜单事件
- go func() {
- for {
- select {
- case <-mStart.ClickedCh:
- log.Printf("菜单:启动服务")
- sup.Start()
- case <-mStop.ClickedCh:
- log.Printf("菜单:停止服务")
- sup.Stop()
- case <-mRestart.ClickedCh:
- log.Printf("菜单:重启服务")
- sup.Restart()
- case <-mURL.ClickedCh:
- status := sup.Status()
- log.Printf("菜单:打开 Web %s", status.URL)
- openURL(status.URL)
- case <-mAutoStart.ClickedCh:
- next := !mAutoStart.Checked()
- if err := setAutoStart(next); err != nil {
- log.Printf("设置开机自启失败: %v", err)
- continue
- }
- if next {
- mAutoStart.Check()
- } else {
- mAutoStart.Uncheck()
- }
- cfg.AutoStart = next
- _ = saveConfig(cfg)
- log.Printf("开机自启 = %v", next)
- case <-mAutoUpdate.ClickedCh:
- next := !mAutoUpdate.Checked()
- if next {
- mAutoUpdate.Check()
- } else {
- mAutoUpdate.Uncheck()
- }
- cfg.AutoUpdate = next
- _ = saveConfig(cfg)
- log.Printf("定期自动更新 = %v(间隔 %d 小时)", next, cfg.UpdateIntervalH)
- if next {
- sup.startAutoUpdate()
- }
- case <-mUpdateNow.ClickedCh:
- go func() {
- log.Printf("菜单:立即更新")
- if _, err := sup.Update(); err != nil {
- log.Printf("更新失败: %v", err)
- return
- }
- log.Printf("更新完成,重启服务")
- sup.Restart()
- mVersion.SetTitle("版本:" + sup.installedVersion())
- }()
- case <-mLogs.ClickedCh:
- openURL(appDataDir() + string(os.PathSeparator) + "logs")
- case <-mConfig.ClickedCh:
- openURL(configPath())
- case <-mQuit.ClickedCh:
- log.Printf("菜单:退出")
- systray.Quit()
- return
- }
- }
- }()
- sup.Start()
- if cfg.AutoUpdate {
- sup.startAutoUpdate()
- }
- }
- func cfgURL(cfg *Config) string {
- host := cfg.WebHost
- if host == "" {
- host = "127.0.0.1"
- }
- return fmt.Sprintf("打开 Web 界面:http://%s:%d", host, cfg.WebPort)
- }
- // shortURL 菜单标题只显示 origin,避免 token 撑爆标题。
- func shortURL(u string) string {
- if i := strings.Index(u, "?"); i > 0 {
- return u[:i]
- }
- return u
- }
- // openURL 用系统默认程序打开 URL 或路径(隐藏窗口)。
- func openURL(target string) {
- cmd := exec.Command("cmd", "/c", "start", "", target)
- hideWindow(cmd)
- _ = cmd.Start()
- }
|