panrouter 1.8.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli.mjs +7 -6
- package/package.json +1 -1
- package/tray-daemon.ps1 +76 -67
package/cli.mjs
CHANGED
|
@@ -150,8 +150,8 @@ function startTray() {
|
|
|
150
150
|
|
|
151
151
|
log("..", "正在以托盘模式启动 Pan Router...", "yellow");
|
|
152
152
|
|
|
153
|
-
//
|
|
154
|
-
const child = spawn("
|
|
153
|
+
// 直接调用 wscript,去掉多余的 cmd.exe 嵌套层级,更稳定
|
|
154
|
+
const child = spawn("wscript.exe", ["//B", "//NoLogo", vbsPath], {
|
|
155
155
|
cwd: __dirname,
|
|
156
156
|
stdio: "ignore",
|
|
157
157
|
windowsHide: true,
|
|
@@ -161,7 +161,7 @@ function startTray() {
|
|
|
161
161
|
child.unref();
|
|
162
162
|
|
|
163
163
|
log("OK", "Pan Router 托盘已启动", "green");
|
|
164
|
-
console.log(" 图标在右下角,
|
|
164
|
+
console.log(" 图标在右下角, 右键可进行管理");
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
// ─── 主流程 ──────────────────────────────────────────────────────────────
|
|
@@ -192,9 +192,10 @@ async function main() {
|
|
|
192
192
|
|
|
193
193
|
\x1b[33m托盘模式:\x1b[0m
|
|
194
194
|
在系统通知区(右下角)显示图标,右键菜单:
|
|
195
|
-
-
|
|
196
|
-
-
|
|
197
|
-
|
|
195
|
+
- 启动/重启服务
|
|
196
|
+
- 开关开机自启动
|
|
197
|
+
- 退出关闭服务器和托盘
|
|
198
|
+
左键点击图标显示菜单
|
|
198
199
|
|
|
199
200
|
\x1b[33m配置:\x1b[0m
|
|
200
201
|
代理运行在 http://127.0.0.1:50816
|
package/package.json
CHANGED
package/tray-daemon.ps1
CHANGED
|
@@ -1,45 +1,44 @@
|
|
|
1
1
|
<#
|
|
2
2
|
.SYNOPSIS
|
|
3
|
-
Pan Router
|
|
4
|
-
|
|
3
|
+
Pan Router 托盘守护脚本
|
|
4
|
+
去除了导致 UI 假死的同步网络请求,增加了稳定的重试和容错机制。
|
|
5
5
|
#>
|
|
6
6
|
|
|
7
|
+
Add-Type -AssemblyName System.Windows.Forms
|
|
8
|
+
Add-Type -AssemblyName System.Drawing
|
|
9
|
+
|
|
10
|
+
# 抑制全局报错弹窗,防止后台服务因为意外报错直接死掉
|
|
11
|
+
$ErrorActionPreference = "SilentlyContinue"
|
|
12
|
+
|
|
7
13
|
$scriptPath = $MyInvocation.MyCommand.Path
|
|
8
14
|
$scriptDir = Split-Path $scriptPath -Parent
|
|
9
15
|
$serverPath = Join-Path $scriptDir "server.mjs"
|
|
10
|
-
$
|
|
11
|
-
$now = Get-Date -Format "HH:mm:ss"
|
|
16
|
+
$nodePath = (Get-Command node -ErrorAction SilentlyContinue).Source
|
|
12
17
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"$now serverPath=$serverPath" | Out-File -Append $logFile
|
|
18
|
+
# 如果系统环境没装 Node,直接静默退出
|
|
19
|
+
if (-not $nodePath) { Exit }
|
|
16
20
|
|
|
17
|
-
# ───
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
# ─── 核心功能:杀旧启新 ──────────────────────────────
|
|
22
|
+
function Restart-Server {
|
|
23
|
+
# 强制清理旧的代理进程
|
|
24
|
+
try {
|
|
25
|
+
wmic process where "name='node.exe'" get ProcessId,CommandLine /format:csv 2>$null | ForEach-Object {
|
|
26
|
+
if ($_ -match '(\d+),.*?server\.mjs') {
|
|
27
|
+
Stop-Process -Id $Matches[1] -Force -ErrorAction SilentlyContinue
|
|
28
|
+
}
|
|
24
29
|
}
|
|
25
|
-
}
|
|
26
|
-
} catch {}
|
|
30
|
+
} catch {}
|
|
27
31
|
|
|
28
|
-
#
|
|
29
|
-
try {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
$p = Start-Process -FilePath $nodePath -ArgumentList "`"$serverPath`"" -WorkingDirectory $scriptDir -WindowStyle Hidden -PassThru -NoNewWindow
|
|
33
|
-
if ($p -and $p.Id) { "$now Server started PID=$($p.Id)" | Out-File -Append $logFile }
|
|
34
|
-
} catch {
|
|
35
|
-
"$now Server start FAILED: $_" | Out-File -Append $logFile
|
|
32
|
+
# 无黑框启动新进程
|
|
33
|
+
try {
|
|
34
|
+
Start-Process -FilePath $nodePath -ArgumentList "`"$serverPath`"" -WorkingDirectory $scriptDir -WindowStyle Hidden -PassThru -NoNewWindow | Out-Null
|
|
35
|
+
} catch {}
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
#
|
|
39
|
-
|
|
40
|
-
Add-Type -AssemblyName System.Drawing
|
|
38
|
+
# 启动时立刻执行一次
|
|
39
|
+
Restart-Server
|
|
41
40
|
|
|
42
|
-
# ───
|
|
41
|
+
# ─── 绘制托盘图标 ────────────────────────────────────────
|
|
43
42
|
$bmp = New-Object System.Drawing.Bitmap(16, 16)
|
|
44
43
|
$g = [System.Drawing.Graphics]::FromImage($bmp)
|
|
45
44
|
$g.SmoothingMode = 'HighQuality'
|
|
@@ -49,76 +48,86 @@ $g.FillEllipse($brush, 0, 0, 15, 15)
|
|
|
49
48
|
$font = New-Object System.Drawing.Font("Segoe UI", 8.5, [System.Drawing.FontStyle]::Bold)
|
|
50
49
|
$fg = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::White)
|
|
51
50
|
$g.DrawString("P", $font, $fg, 3, 1.5)
|
|
52
|
-
|
|
51
|
+
|
|
53
52
|
$hIcon = $bmp.GetHicon()
|
|
54
53
|
$icon = [System.Drawing.Icon]::FromHandle($hIcon)
|
|
55
|
-
$bmp.Dispose()
|
|
56
54
|
|
|
57
|
-
# ───
|
|
55
|
+
# ─── 初始化托盘对象 ──────────────────────────────────
|
|
58
56
|
$notifyIcon = New-Object System.Windows.Forms.NotifyIcon
|
|
59
57
|
$notifyIcon.Icon = $icon
|
|
60
|
-
$notifyIcon.Text = "Pan Router
|
|
58
|
+
$notifyIcon.Text = "Pan Router (端口: 50816)"
|
|
61
59
|
|
|
62
|
-
# ─── 菜单 ────────────────────────────────────────
|
|
63
60
|
$menu = New-Object System.Windows.Forms.ContextMenuStrip
|
|
64
|
-
[void]$menu.Items.Add((New-Object System.Windows.Forms.ToolStripMenuItem("Pan Router - :50816") { Enabled = $false; Font = New-Object System.Drawing.Font("Segoe UI", 9, [System.Drawing.FontStyle]::Bold) }))
|
|
65
|
-
[void]$menu.Items.Add((New-Object System.Windows.Forms.ToolStripSeparator))
|
|
66
61
|
|
|
62
|
+
# 标题 (不可点)
|
|
63
|
+
$titleItem = New-Object System.Windows.Forms.ToolStripMenuItem("Pan Router | :50816")
|
|
64
|
+
$titleItem.Enabled = $false
|
|
65
|
+
$titleItem.Font = New-Object System.Drawing.Font("Segoe UI", 9, [System.Drawing.FontStyle]::Bold)
|
|
66
|
+
$menu.Items.Add($titleItem) | Out-Null
|
|
67
|
+
$menu.Items.Add((New-Object System.Windows.Forms.ToolStripSeparator)) | Out-Null
|
|
68
|
+
|
|
69
|
+
# 重启服务选项
|
|
70
|
+
$restartItem = New-Object System.Windows.Forms.ToolStripMenuItem("重启后台服务")
|
|
71
|
+
$restartItem.Add_Click({
|
|
72
|
+
Restart-Server
|
|
73
|
+
$notifyIcon.ShowBalloonTip(2000, "Pan Router", "后台代理服务已重新启动 ✓", [System.Windows.Forms.ToolTipIcon]::Info)
|
|
74
|
+
})
|
|
75
|
+
$menu.Items.Add($restartItem) | Out-Null
|
|
76
|
+
|
|
77
|
+
# 开机自启动选项
|
|
67
78
|
$autoItem = New-Object System.Windows.Forms.ToolStripMenuItem("开机自启动")
|
|
68
|
-
try {
|
|
79
|
+
try {
|
|
80
|
+
$regKey = Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" -Name PanRouter -ErrorAction SilentlyContinue
|
|
81
|
+
$autoItem.Checked = ($regKey -ne $null)
|
|
82
|
+
} catch {}
|
|
83
|
+
|
|
69
84
|
$autoItem.Add_Click({
|
|
70
85
|
if ($autoItem.Checked) {
|
|
71
86
|
reg delete "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /v PanRouter /f 2>&1 | Out-Null
|
|
72
87
|
$autoItem.Checked = $false
|
|
73
|
-
$notifyIcon.ShowBalloonTip(2000, "Pan Router", "开机自启动已关闭", [System.Windows.Forms.ToolTipIcon]::Info)
|
|
74
88
|
} else {
|
|
75
|
-
|
|
89
|
+
$vbsPath = Join-Path $scriptDir "panrouter-tray.vbs"
|
|
90
|
+
$cmd = "wscript.exe //B //NoLogo `"$vbsPath`""
|
|
91
|
+
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /v PanRouter /t REG_SZ /d $cmd /f 2>&1 | Out-Null
|
|
76
92
|
$autoItem.Checked = $true
|
|
77
|
-
$notifyIcon.ShowBalloonTip(2000, "Pan Router", "开机自启动已开启 ✓", [System.Windows.Forms.ToolTipIcon]::Info)
|
|
78
93
|
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
|
|
94
|
+
})
|
|
95
|
+
$menu.Items.Add($autoItem) | Out-Null
|
|
96
|
+
$menu.Items.Add((New-Object System.Windows.Forms.ToolStripSeparator)) | Out-Null
|
|
82
97
|
|
|
98
|
+
# 退出选项
|
|
83
99
|
$exitItem = New-Object System.Windows.Forms.ToolStripMenuItem("退出")
|
|
84
100
|
$exitItem.Add_Click({
|
|
85
101
|
$notifyIcon.Visible = $false
|
|
86
|
-
try {
|
|
102
|
+
try { wmic process where "name='node.exe'" get ProcessId,CommandLine /format:csv 2>$null | ForEach-Object { if ($_ -match '(\d+),.*?server\.mjs') { Stop-Process -Id $Matches[1] -Force -ErrorAction SilentlyContinue } } } catch {}
|
|
87
103
|
[System.Windows.Forms.Application]::Exit()
|
|
88
|
-
}
|
|
89
|
-
|
|
104
|
+
})
|
|
105
|
+
$menu.Items.Add($exitItem) | Out-Null
|
|
90
106
|
|
|
91
107
|
$notifyIcon.ContextMenuStrip = $menu
|
|
92
108
|
|
|
93
|
-
# ───
|
|
109
|
+
# ─── 优化左键操作 ────────────────────────────────────
|
|
94
110
|
$notifyIcon.Add_MouseClick({
|
|
95
111
|
if ($_.Button -eq [System.Windows.Forms.MouseButtons]::Left) {
|
|
96
|
-
|
|
97
|
-
|
|
112
|
+
# 利用反射直接呼出右键菜单,取消容易卡死的网络检查
|
|
113
|
+
$mi = [System.Windows.Forms.NotifyIcon].GetMethod("ShowContextMenu", [System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::Instance)
|
|
114
|
+
$mi.Invoke($notifyIcon, $null)
|
|
98
115
|
}
|
|
99
116
|
})
|
|
100
117
|
|
|
101
|
-
# ───
|
|
102
|
-
$healthTimer = New-Object System.Windows.Forms.Timer
|
|
103
|
-
$healthTimer.Interval = 30000
|
|
104
|
-
$healthTimer.Add_Tick({
|
|
105
|
-
try { $req = [System.Net.WebRequest]::Create("http://127.0.0.1:50816/health"); $req.Timeout = 1500; $resp = $req.GetResponse(); $resp.Close() }
|
|
106
|
-
catch {
|
|
107
|
-
try { $old = wmic process where "name='node.exe'" get ProcessId,CommandLine /format:csv 2>$null; foreach ($line in $old) { if ($line -match '(\d+),.*?server\.mjs') { Stop-Process -Id $Matches[1] -Force -ErrorAction SilentlyContinue } } } catch {}
|
|
108
|
-
try { Start-Process -FilePath (Get-Command node).Source -ArgumentList "`"$serverPath`"" -WorkingDirectory $scriptDir -WindowStyle Hidden -NoNewWindow } catch {}
|
|
109
|
-
}
|
|
110
|
-
})
|
|
111
|
-
$healthTimer.Start()
|
|
112
|
-
"$now Health timer started" | Out-File -Append $logFile
|
|
113
|
-
|
|
114
|
-
# ═══ 进入消息循环 ═══
|
|
118
|
+
# ─── 启动与保持运行 ──────────────────────────────────
|
|
115
119
|
$notifyIcon.Visible = $true
|
|
116
|
-
"$now Icon visible, entering message loop" | Out-File -Append $logFile
|
|
117
|
-
[System.Windows.Forms.Application]::Run()
|
|
118
|
-
"$now Exited message loop" | Out-File -Append $logFile
|
|
119
120
|
|
|
120
|
-
#
|
|
121
|
-
$
|
|
121
|
+
# 使用 ApplicationContext 保持消息循环,防止脚本在执行完后意外释放托盘图标
|
|
122
|
+
$appContext = New-Object System.Windows.Forms.ApplicationContext
|
|
123
|
+
[System.Windows.Forms.Application]::Run($appContext)
|
|
124
|
+
|
|
125
|
+
# 清理资源
|
|
126
|
+
$notifyIcon.Visible = $false
|
|
122
127
|
$notifyIcon.Dispose()
|
|
128
|
+
$font.Dispose()
|
|
129
|
+
$fg.Dispose()
|
|
130
|
+
$brush.Dispose()
|
|
131
|
+
$g.Dispose()
|
|
123
132
|
[System.Runtime.InteropServices.Marshal]::DestroyIcon($hIcon)
|
|
124
133
|
$icon.Dispose()
|