Skip to content

Commit 591e174

Browse files
committed
feat: AppStatus is more unified, with added information.
1 parent 7207cb7 commit 591e174

5 files changed

Lines changed: 110 additions & 51 deletions

File tree

core/main.go

Lines changed: 46 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,12 @@ import (
2929
)
3030

3131
var configPath = "config.yaml" // 全局可用
32-
var appStatus = "未启动"
3332
var extraArgs []string
3433
var lastFoundArgs []string // 仅记录 FindProcessByPath 找到的参数(不含exe路径)
3534
var currentAppPid int
3635

36+
var appStatus = internal.NewAppStatus(internal.AppNotStarted, 0, 0, "初始状态")
37+
3738
var (
3839
idleTimer *time.Timer
3940
idleTimerC <-chan time.Time
@@ -72,14 +73,6 @@ func internalGetConfig() (*internal.Config, error) {
7273
return cfg, nil
7374
}
7475

75-
func internalGetAppStatus() string {
76-
// 用 FindProcessByPath 判断真实运行状态
77-
// if pid, _, found := internal.FindProcessByPath(app.Path); found && pid != 0 {
78-
// return internal.AppRunning.String()
79-
// }
80-
return fmt.Sprintf("%s", appStatus)
81-
}
82-
8376
func internalGetActivate() string {
8477
cfg, err := internalGetConfig()
8578
if err != nil {
@@ -148,10 +141,10 @@ func internalKillCurrentApp() error {
148141
}
149142
err := internal.KillProcessTreeAndWait(currentAppPid)
150143
if err == nil {
151-
appStatus = "已终止 (PID=" + fmt.Sprint(currentAppPid) + ")"
144+
appStatus = internal.NewAppStatus(internal.AppExited, currentAppPid, 0, "已终止")
152145
setCurrentAppPid(0)
153146
} else {
154-
appStatus = "终止失败 (PID=" + fmt.Sprint(currentAppPid) + ")"
147+
appStatus = internal.NewAppStatus(internal.AppExited, currentAppPid, 0, "终止失败")
155148
}
156149
return err
157150
}
@@ -187,34 +180,54 @@ func runAppProxy(args []string) {
187180
fmt.Printf("[DEBUG] finalArgs: %v\n", finalArgs)
188181

189182
_, err = internal.StartAppProcess(app.Path, finalArgs, func(status string, pid int, exitErr error) {
183+
exitCode := 0
184+
if exitErr != nil {
185+
if c, ok := internal.ExtractExitCode(exitErr); ok {
186+
exitCode = c
187+
}
188+
}
189+
190190
switch status {
191+
case "start_failed":
192+
appStatus = internal.NewAppStatus(internal.AppExited, 0, exitCode, "启动失败")
193+
fmt.Printf("启动应用失败: %v\n", exitErr)
191194
case "running":
192-
appStatus = fmt.Sprintf("运行中 (PID=%d)", pid)
193195
setCurrentAppPid(pid)
196+
appStatus = internal.NewAppStatus(internal.AppRunning, pid, 0, "运行中")
194197
fmt.Printf("已启动应用: %s (PID=%d)\n", app.Path, pid)
195198
case "exited":
196-
appStatus = fmt.Sprintf("已退出 (PID=%d)", pid)
197-
fmt.Println("应用已正常退出")
198199
setCurrentAppPid(0)
200+
appStatus = internal.NewAppStatus(internal.AppExited, pid, exitCode, "已退出")
201+
fmt.Println("应用已正常退出")
199202
case "exit_failed":
200-
appStatus = fmt.Sprintf("异常退出 (PID=%d)", pid)
201-
fmt.Printf("应用异常退出,返回码非0: %v\n", exitErr)
202203
setCurrentAppPid(0)
204+
code := 1
205+
if exitCode != 0 {
206+
code = exitCode
207+
}
208+
appStatus = internal.NewAppStatus(internal.AppExited, pid, code, "异常退出")
209+
fmt.Printf("应用异常退出,返回码非0: %v\n", exitErr)
203210
case "killed":
204-
appStatus = fmt.Sprintf("被终止 (PID=%d)", pid)
205-
fmt.Printf("应用被信号终止: %v\n", exitErr)
206211
setCurrentAppPid(0)
212+
code := 1
213+
if exitCode != 0 {
214+
code = exitCode
215+
}
216+
appStatus = internal.NewAppStatus(internal.AppExited, pid, code, "被终止")
217+
fmt.Printf("应用被信号终止: %v\n", exitErr)
207218
case "crashed":
208-
appStatus = fmt.Sprintf("已崩溃 (PID=%d)", pid)
209-
fmt.Printf("应用崩溃: %v\n", exitErr)
210219
setCurrentAppPid(0)
211-
case "start_failed":
212-
appStatus = "启动失败"
213-
fmt.Printf("启动应用失败: %v\n", exitErr)
220+
code := 1
221+
if exitCode != 0 {
222+
code = exitCode
223+
}
224+
appStatus = internal.NewAppStatus(internal.AppCrashed, pid, code, "已崩溃")
225+
fmt.Printf("应用崩溃: %v\n", exitErr)
214226
}
215227
})
228+
216229
if err != nil {
217-
appStatus = "启动失败"
230+
appStatus = internal.NewAppStatus(internal.AppExited, 0, 0, "启动失败")
218231
fmt.Printf("启动应用失败: %v\n", err)
219232
return
220233
}
@@ -263,7 +276,14 @@ func handleConsoleConn(conn net.Conn, configPath string) {
263276
case "activate":
264277
conn.Write([]byte(internalGetActivate()))
265278
case "status":
266-
conn.Write([]byte(internalGetAppStatus()))
279+
conn.Write(
280+
// 返回详细状态字符串
281+
fmt.Appendf(nil, "%s | PID=%d | ExitCode=%d",
282+
appStatus.Main.String(),
283+
appStatus.Pid,
284+
appStatus.ExitCode,
285+
),
286+
)
267287
case "list":
268288
cfg, err := internalGetConfig()
269289
if err != nil {
@@ -378,7 +398,7 @@ func main() {
378398
// 通过进程路径查找是否有已运行实例
379399
if pid, args, found := internal.FindProcessByPath(appPath); found {
380400
shouldStart = false
381-
appStatus = fmt.Sprintf("运行中 (PID=%d)", pid)
401+
appStatus = internal.NewAppStatus(internal.AppRunning, pid, 0, "运行中")
382402
fmt.Printf("[DEBUG] FindProcessByPath 原始args: %v\n", args)
383403
if len(args) > 1 {
384404
fmt.Printf("[DEBUG] FindProcessByPath 参数部分: %v\n", args[1:])

internal/apps.go

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,48 +3,69 @@ package internal
33
import (
44
"fmt"
55
"strings"
6+
"time"
67
)
78

89
// AppStatus 表示应用运行状态,用于托盘菜单、主程序等统一判断
9-
type AppStatus int
10+
type AppMainStatus int
1011

1112
const (
12-
AppUnknown AppStatus = iota
13-
AppRunning
14-
AppStopped
15-
AppExited
16-
AppCrashed
13+
AppNotStarted AppMainStatus = iota // 未启动
14+
AppRunning // 运行中
15+
AppExited // 已退出
16+
AppCrashed // 已崩溃
17+
AppUnknown // 未知
1718
)
1819

19-
func (a AppStatus) String() string {
20-
// 与 ParseAppStatus 的判定顺序保持一致
21-
switch a {
20+
func (s AppMainStatus) String() string {
21+
switch s {
22+
case AppNotStarted:
23+
return "未启动"
2224
case AppRunning:
2325
return "运行中"
24-
case AppStopped:
25-
return "未启动"
2626
case AppExited:
2727
return "已退出"
2828
case AppCrashed:
2929
return "已崩溃"
3030
case AppUnknown:
31-
fallthrough
31+
return "未知"
3232
default:
3333
return "未知"
3434
}
3535
}
3636

37-
// ParseAppStatus 从描述字符串解析为 AppStatus 枚举
38-
func ParseAppStatus(status string) AppStatus {
37+
type AppStatus struct {
38+
Main AppMainStatus // 主状态
39+
Pid int // 进程PID
40+
ExitCode int // 退出码
41+
Detail string // 详细描述
42+
Timestamp time.Time // 状态变更时间
43+
}
44+
45+
// NewAppStatus 构建带当前时间戳的 AppStatus
46+
func NewAppStatus(main AppMainStatus, pid, exitCode int, detail string) AppStatus {
47+
return AppStatus{
48+
Main: main,
49+
Pid: pid,
50+
ExitCode: exitCode,
51+
Detail: detail,
52+
Timestamp: time.Now(),
53+
}
54+
}
55+
56+
// ParseAppStatus 从描述字符串解析为 AppMainStatus 枚举
57+
func ParseAppStatus(status string) AppMainStatus {
3958
switch {
4059
case strings.Contains(status, "未启动"):
41-
return AppStopped
60+
return AppNotStarted
4261
case strings.Contains(status, "已退出"):
4362
return AppExited
4463
case strings.Contains(status, "已崩溃"):
4564
return AppCrashed
4665
case strings.Contains(status, "运行中"):
4766
return AppRunning
67+
case strings.Contains(status, "未知"):
68+
return AppUnknown
4869
default:
4970
return AppUnknown
5071
}

internal/process.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,24 @@ import (
1313
"github.com/StackExchange/wmi"
1414
)
1515

16+
// ExtractExitCode 提取 error 中的退出码(如有),否则返回 false
17+
func ExtractExitCode(err error) (int, bool) {
18+
if err == nil {
19+
return 0, false
20+
}
21+
if exitErr, ok := err.(*exec.ExitError); ok {
22+
// 优先使用 Go1.12+ ExitCode()
23+
if code := exitErr.ExitCode(); code != -1 {
24+
return code, true
25+
}
26+
// 尝试 syscall.WaitStatus
27+
if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
28+
return status.ExitStatus(), true
29+
}
30+
}
31+
return 0, false
32+
}
33+
1634
// 检查进程是否存活(windows 适用)
1735
func IsProcessAlive(pid int) bool {
1836
if pid == 0 {

launcher/command/command.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,12 @@ func GetActivate() string {
7272
}
7373

7474
// GetAppStatus returns AppStatus from "status".
75-
func GetAppStatus() internal.AppStatus {
75+
func GetAppStatus() string {
7676
resp, err := SendCommand("status")
7777
if err != nil {
78-
return internal.AppUnknown
78+
return internal.AppUnknown.String()
7979
}
80-
return internal.ParseAppStatus(resp)
80+
return resp
8181
}
8282

8383
// GetAppInfo 获取应用信息,name 为空则为当前激活 app,否则为指定 app。

launcher/main.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,19 +46,19 @@ func trayOnReady() {
4646
},
4747
},
4848
{
49-
Title: "应用: ",
50-
Tooltip: "当前运行的应用",
49+
Title: "状态:",
50+
Tooltip: "应用运行状态",
5151
Disable: true,
5252
OnRefresh: func(item *systray.MenuItem) {
53-
item.SetTitle("应用: " + command.GetActivate())
53+
item.SetTitle("状态: " + command.GetAppStatus())
5454
},
5555
},
5656
{
57-
Title: "状态:",
58-
Tooltip: "应用运行状态",
57+
Title: "应用: ",
58+
Tooltip: "当前运行的应用",
5959
Disable: true,
6060
OnRefresh: func(item *systray.MenuItem) {
61-
item.SetTitle("状态: " + command.GetAppStatus().String())
61+
item.SetTitle("应用: " + command.GetActivate())
6262
},
6363
},
6464
{
@@ -99,7 +99,7 @@ func trayOnReady() {
9999
Title: "启动 / 重启",
100100
Tooltip: "运行或重启当前激活的应用",
101101
OnClick: func(item *systray.MenuItem) {
102-
status := command.GetAppStatus()
102+
status := internal.ParseAppStatus(command.GetAppStatus())
103103
if status == internal.AppRunning {
104104
command.RestartApp()
105105
} else {

0 commit comments

Comments
 (0)