@xevy/heny-connect 0.2.0 → 0.3.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/README.md +44 -34
- package/bin/heny-connect.mjs +61 -54
- package/lib/browser-controller.mjs +242 -0
- package/lib/cdp.mjs +95 -0
- package/lib/network-policy.mjs +102 -0
- package/lib/state.mjs +54 -0
- package/lib/validating-proxy.mjs +70 -0
- package/lib/worker.mjs +241 -0
- package/package.json +4 -3
- package/windows/heny-connect-tray.ps1 +112 -154
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
param(
|
|
2
|
-
[Parameter(Mandatory = $true)]
|
|
3
|
-
[string] $
|
|
4
|
-
|
|
5
|
-
[Parameter(Mandatory = $true)]
|
|
6
|
-
[string] $CliPath,
|
|
7
|
-
|
|
2
|
+
[Parameter(Mandatory = $true)][string] $NodePath,
|
|
3
|
+
[Parameter(Mandatory = $true)][string] $CliPath,
|
|
4
|
+
[Parameter(Mandatory = $true)][string] $HomePath,
|
|
8
5
|
[string] $IconPath,
|
|
9
6
|
[switch] $Install,
|
|
10
7
|
[switch] $Uninstall
|
|
@@ -13,21 +10,23 @@ param(
|
|
|
13
10
|
$ErrorActionPreference = "Stop"
|
|
14
11
|
$taskName = "HenyConnect"
|
|
15
12
|
$powershellPath = Join-Path $env:SystemRoot "System32\WindowsPowerShell\v1.0\powershell.exe"
|
|
13
|
+
$statusPath = Join-Path $HomePath "worker-status.json"
|
|
14
|
+
$trayStatusPath = Join-Path $HomePath "tray-status.json"
|
|
15
|
+
$pausePath = Join-Path $HomePath "paused"
|
|
16
|
+
$stopPath = Join-Path $HomePath "stopping"
|
|
16
17
|
if (-not $IconPath) { $IconPath = Join-Path $PSScriptRoot "heny.ico" }
|
|
17
18
|
|
|
18
19
|
function Get-TaskArguments {
|
|
19
|
-
return "-NoLogo -NoProfile -STA -ExecutionPolicy Bypass -WindowStyle Hidden -File `"$PSCommandPath`" -NodePath `"$NodePath`" -CliPath `"$CliPath`" -IconPath `"$IconPath`""
|
|
20
|
+
return "-NoLogo -NoProfile -STA -ExecutionPolicy Bypass -WindowStyle Hidden -File `"$PSCommandPath`" -NodePath `"$NodePath`" -CliPath `"$CliPath`" -HomePath `"$HomePath`" -IconPath `"$IconPath`""
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
function Install-HenyTask {
|
|
23
24
|
param([bool] $StartNow)
|
|
24
|
-
|
|
25
25
|
$existing = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue
|
|
26
26
|
if ($existing) {
|
|
27
27
|
Stop-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue
|
|
28
28
|
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false
|
|
29
29
|
}
|
|
30
|
-
|
|
31
30
|
$currentUser = [Security.Principal.WindowsIdentity]::GetCurrent().Name
|
|
32
31
|
$action = New-ScheduledTaskAction -Execute $powershellPath -Argument (Get-TaskArguments)
|
|
33
32
|
$trigger = New-ScheduledTaskTrigger -AtLogOn -User $currentUser
|
|
@@ -55,10 +54,7 @@ if ($Install) {
|
|
|
55
54
|
|
|
56
55
|
$createdNew = $false
|
|
57
56
|
$mutex = [Threading.Mutex]::new($true, "Local\HenyConnectTray", [ref] $createdNew)
|
|
58
|
-
if (-not $createdNew) {
|
|
59
|
-
$mutex.Dispose()
|
|
60
|
-
exit 0
|
|
61
|
-
}
|
|
57
|
+
if (-not $createdNew) { $mutex.Dispose(); exit 0 }
|
|
62
58
|
|
|
63
59
|
Add-Type -AssemblyName System.Windows.Forms
|
|
64
60
|
Add-Type -AssemblyName System.Drawing
|
|
@@ -69,212 +65,161 @@ $iconPaused = [Drawing.Icon]::new((Join-Path $PSScriptRoot "heny-paused.ico"))
|
|
|
69
65
|
$iconError = [Drawing.Icon]::new((Join-Path $PSScriptRoot "heny-error.ico"))
|
|
70
66
|
$notifyIcon = [Windows.Forms.NotifyIcon]::new()
|
|
71
67
|
$notifyIcon.Icon = $iconPaused
|
|
72
|
-
$notifyIcon.Text = "Heny Connect -
|
|
68
|
+
$notifyIcon.Text = "Heny Connect - Browser starting"
|
|
73
69
|
$notifyIcon.Visible = $true
|
|
74
70
|
|
|
75
71
|
$menu = [Windows.Forms.ContextMenuStrip]::new()
|
|
76
72
|
$titleItem = [Windows.Forms.ToolStripMenuItem]::new("Heny Connect")
|
|
77
73
|
$titleItem.Enabled = $false
|
|
78
74
|
$titleItem.Font = [Drawing.Font]::new($titleItem.Font, [Drawing.FontStyle]::Bold)
|
|
79
|
-
$statusItem = [Windows.Forms.ToolStripMenuItem]::new("Status:
|
|
75
|
+
$statusItem = [Windows.Forms.ToolStripMenuItem]::new("Status: Browser starting")
|
|
80
76
|
$statusItem.Enabled = $false
|
|
77
|
+
$actionItem = [Windows.Forms.ToolStripMenuItem]::new("Current action: None")
|
|
78
|
+
$actionItem.Enabled = $false
|
|
81
79
|
$openItem = [Windows.Forms.ToolStripMenuItem]::new("Open Heny")
|
|
82
80
|
$pauseItem = [Windows.Forms.ToolStripMenuItem]::new("Pause")
|
|
83
81
|
$reconnectItem = [Windows.Forms.ToolStripMenuItem]::new("Reconnect now")
|
|
84
82
|
$startItem = [Windows.Forms.ToolStripMenuItem]::new("Start at sign-in")
|
|
85
|
-
$startItem.CheckOnClick = $false
|
|
86
83
|
$startItem.Checked = [bool] (Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue)
|
|
87
84
|
$quitItem = [Windows.Forms.ToolStripMenuItem]::new("Quit")
|
|
88
|
-
|
|
89
|
-
$null = $menu.Items.Add($titleItem)
|
|
90
|
-
$null = $menu.Items.Add($statusItem)
|
|
91
|
-
$null = $menu.Items.Add([Windows.Forms.ToolStripSeparator]::new())
|
|
92
|
-
$null = $menu.Items.Add($openItem)
|
|
93
|
-
$null = $menu.Items.Add($pauseItem)
|
|
94
|
-
$null = $menu.Items.Add($reconnectItem)
|
|
95
|
-
$null = $menu.Items.Add($startItem)
|
|
96
|
-
$null = $menu.Items.Add([Windows.Forms.ToolStripSeparator]::new())
|
|
97
|
-
$null = $menu.Items.Add($quitItem)
|
|
85
|
+
foreach ($item in @($titleItem, $statusItem, $actionItem, [Windows.Forms.ToolStripSeparator]::new(), $openItem, $pauseItem, $reconnectItem, $startItem, [Windows.Forms.ToolStripSeparator]::new(), $quitItem)) { $null = $menu.Items.Add($item) }
|
|
98
86
|
$notifyIcon.ContextMenuStrip = $menu
|
|
99
87
|
|
|
100
|
-
$script:
|
|
101
|
-
$script:
|
|
102
|
-
$script:
|
|
103
|
-
$script:nextHeartbeat = Get-Date
|
|
104
|
-
$script:lastStatus = "connecting"
|
|
88
|
+
$script:workerProcess = $null
|
|
89
|
+
$script:nextStart = Get-Date
|
|
90
|
+
$script:paused = Test-Path -LiteralPath $pausePath
|
|
105
91
|
$script:exiting = $false
|
|
106
92
|
|
|
107
93
|
function Set-HenyStatus {
|
|
108
|
-
param(
|
|
109
|
-
[ValidateSet("available", "paused", "connecting", "error")]
|
|
110
|
-
[string] $State,
|
|
111
|
-
[string] $Detail
|
|
112
|
-
)
|
|
113
|
-
|
|
94
|
+
param([string] $State, [string] $Action)
|
|
114
95
|
$label = switch ($State) {
|
|
115
96
|
"available" { "Available" }
|
|
97
|
+
"working" { "Working" }
|
|
116
98
|
"paused" { "Paused" }
|
|
117
|
-
"
|
|
118
|
-
"
|
|
99
|
+
"pausing" { "Pausing" }
|
|
100
|
+
"browser_starting" { "Browser starting" }
|
|
101
|
+
"error" { "Error" }
|
|
102
|
+
"offline" { "Offline" }
|
|
103
|
+
default { "Connecting" }
|
|
119
104
|
}
|
|
120
105
|
$statusItem.Text = "Status: $label"
|
|
121
|
-
if ($
|
|
106
|
+
$actionItem.Text = if ($Action) { "Current action: $Action" } else { "Current action: None" }
|
|
122
107
|
$notifyIcon.Text = "Heny Connect - $label"
|
|
123
|
-
$notifyIcon.Icon =
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
$
|
|
108
|
+
$notifyIcon.Icon = if ($State -in @("available", "working")) { $iconAvailable } elseif ($State -eq "error") { $iconError } else { $iconPaused }
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function Write-TrayStatus {
|
|
112
|
+
param([string] $State, [int] $ExitCode = 0, [string] $Detail = "")
|
|
113
|
+
@{ state = $State; exitCode = $ExitCode; detail = $Detail.Substring(0, [Math]::Min(200, $Detail.Length)); updatedAt = [DateTime]::UtcNow.ToString("o") } | ConvertTo-Json -Compress | Set-Content -LiteralPath $trayStatusPath -Encoding UTF8
|
|
129
114
|
}
|
|
130
115
|
|
|
131
116
|
function Get-HenyUrl {
|
|
132
117
|
try {
|
|
133
|
-
$
|
|
134
|
-
$statePath = Join-Path $homePath ".heny-connect.json"
|
|
135
|
-
$state = Get-Content -LiteralPath $statePath -Raw | ConvertFrom-Json
|
|
118
|
+
$state = Get-Content -LiteralPath (Join-Path $HomePath ".heny-connect.json") -Raw | ConvertFrom-Json
|
|
136
119
|
return ([string] $state.server).TrimEnd("/") + "/desktop"
|
|
137
|
-
} catch {
|
|
138
|
-
return "https://heny.vyte.dev/desktop"
|
|
139
|
-
}
|
|
120
|
+
} catch { return "https://heny.vyte.dev/desktop" }
|
|
140
121
|
}
|
|
141
122
|
|
|
142
|
-
function Stop-
|
|
143
|
-
if (-not $script:
|
|
123
|
+
function Stop-Worker {
|
|
124
|
+
if (-not $script:workerProcess) { return }
|
|
144
125
|
try {
|
|
145
|
-
if (-not $script:
|
|
146
|
-
$
|
|
147
|
-
$
|
|
126
|
+
if (-not $script:workerProcess.HasExited) {
|
|
127
|
+
New-Item -ItemType Directory -Path $HomePath -Force | Out-Null
|
|
128
|
+
Set-Content -LiteralPath $pausePath -Value "paused" -NoNewline
|
|
129
|
+
Set-Content -LiteralPath $stopPath -Value "stop" -NoNewline
|
|
130
|
+
$limit = (Get-Date).AddSeconds(5)
|
|
131
|
+
while (-not $script:workerProcess.HasExited -and (Get-Date) -lt $limit) {
|
|
132
|
+
try {
|
|
133
|
+
$state = Get-Content -LiteralPath $statusPath -Raw | ConvertFrom-Json
|
|
134
|
+
if ($state.state -eq "paused") { break }
|
|
135
|
+
} catch {}
|
|
136
|
+
Start-Sleep -Milliseconds 200
|
|
137
|
+
}
|
|
138
|
+
if (-not $script:workerProcess.HasExited) {
|
|
139
|
+
& taskkill.exe /PID ([string] $script:workerProcess.Id) /T /F 2>$null | Out-Null
|
|
140
|
+
$script:workerProcess.WaitForExit(2000) | Out-Null
|
|
141
|
+
}
|
|
148
142
|
}
|
|
149
|
-
$script:
|
|
143
|
+
$script:workerProcess.Dispose()
|
|
150
144
|
} catch {}
|
|
151
|
-
$script:
|
|
152
|
-
$script:heartbeatState = $null
|
|
145
|
+
$script:workerProcess = $null
|
|
153
146
|
}
|
|
154
147
|
|
|
155
|
-
function Start-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
[string] $State = "available"
|
|
159
|
-
)
|
|
160
|
-
|
|
161
|
-
if ($script:heartbeatProcess) { return }
|
|
162
|
-
$detail = if ($State -eq "offline") { "$env:COMPUTERNAME`: paused in tray" } else { "$env:COMPUTERNAME`: browser ready" }
|
|
148
|
+
function Start-Worker {
|
|
149
|
+
if ($script:workerProcess -or $script:paused -or $script:exiting) { return }
|
|
150
|
+
Remove-Item -LiteralPath $stopPath -Force -ErrorAction SilentlyContinue
|
|
163
151
|
$startInfo = [Diagnostics.ProcessStartInfo]::new()
|
|
164
152
|
$startInfo.FileName = $NodePath
|
|
165
|
-
$startInfo.Arguments = "`"$CliPath`"
|
|
153
|
+
$startInfo.Arguments = "`"$CliPath`" run"
|
|
166
154
|
$startInfo.UseShellExecute = $false
|
|
167
155
|
$startInfo.CreateNoWindow = $true
|
|
168
156
|
$startInfo.WindowStyle = [Diagnostics.ProcessWindowStyle]::Hidden
|
|
169
|
-
$startInfo.
|
|
170
|
-
$startInfo.RedirectStandardError = $true
|
|
157
|
+
$startInfo.EnvironmentVariables["HENY_CONNECT_HOME"] = $HomePath
|
|
171
158
|
$process = [Diagnostics.Process]::new()
|
|
172
159
|
$process.StartInfo = $startInfo
|
|
173
160
|
try {
|
|
174
|
-
if (-not $process.Start()) { throw "The
|
|
175
|
-
$script:
|
|
176
|
-
|
|
177
|
-
|
|
161
|
+
if (-not $process.Start()) { throw "The worker did not start." }
|
|
162
|
+
$script:workerProcess = $process
|
|
163
|
+
Write-TrayStatus -State "worker_started"
|
|
164
|
+
Set-HenyStatus -State "browser_starting"
|
|
178
165
|
} catch {
|
|
179
166
|
$process.Dispose()
|
|
180
|
-
|
|
181
|
-
|
|
167
|
+
Write-TrayStatus -State "worker_start_failed" -ExitCode -1 -Detail $_.Exception.Message
|
|
168
|
+
Set-HenyStatus -State "error"
|
|
169
|
+
$script:nextStart = (Get-Date).AddSeconds(15)
|
|
182
170
|
}
|
|
183
171
|
}
|
|
184
172
|
|
|
185
|
-
function
|
|
186
|
-
|
|
187
|
-
$
|
|
188
|
-
$
|
|
189
|
-
$
|
|
190
|
-
|
|
191
|
-
$exitCode = $process.ExitCode
|
|
192
|
-
$process.Dispose()
|
|
193
|
-
$script:heartbeatProcess = $null
|
|
194
|
-
$script:heartbeatState = $null
|
|
195
|
-
$script:nextHeartbeat = (Get-Date).AddSeconds(30)
|
|
196
|
-
|
|
197
|
-
if ($exitCode -eq 0) {
|
|
198
|
-
if ($state -eq "offline" -or $script:paused) {
|
|
199
|
-
Set-HenyStatus -State "paused" -Detail "Paused on this computer"
|
|
200
|
-
} else {
|
|
201
|
-
Set-HenyStatus -State "available" -Detail "Connected to Heny"
|
|
202
|
-
}
|
|
203
|
-
return
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
$detail = if ($stderr) { $stderr } elseif ($stdout) { $stdout } else { "Heartbeat exited with code $exitCode" }
|
|
207
|
-
$previousStatus = $script:lastStatus
|
|
208
|
-
Set-HenyStatus -State "error" -Detail $detail
|
|
209
|
-
if ($previousStatus -ne "error") {
|
|
210
|
-
$notifyIcon.ShowBalloonTip(4000, "Heny Connect", $detail, [Windows.Forms.ToolTipIcon]::Warning)
|
|
211
|
-
}
|
|
173
|
+
function Request-Pause {
|
|
174
|
+
New-Item -ItemType Directory -Path $HomePath -Force | Out-Null
|
|
175
|
+
Set-Content -LiteralPath $pausePath -Value "paused" -NoNewline
|
|
176
|
+
$script:paused = $true
|
|
177
|
+
$pauseItem.Text = "Resume"
|
|
178
|
+
Set-HenyStatus -State "pausing"
|
|
212
179
|
}
|
|
213
180
|
|
|
214
|
-
function
|
|
215
|
-
|
|
216
|
-
$
|
|
217
|
-
$
|
|
218
|
-
$
|
|
219
|
-
$
|
|
220
|
-
|
|
221
|
-
$startInfo.WindowStyle = [Diagnostics.ProcessWindowStyle]::Hidden
|
|
222
|
-
$process = [Diagnostics.Process]::Start($startInfo)
|
|
223
|
-
if ($process) {
|
|
224
|
-
$process.WaitForExit(10000) | Out-Null
|
|
225
|
-
if (-not $process.HasExited) { $process.Kill() }
|
|
226
|
-
$process.Dispose()
|
|
227
|
-
}
|
|
181
|
+
function Request-Resume {
|
|
182
|
+
Remove-Item -LiteralPath $pausePath -Force -ErrorAction SilentlyContinue
|
|
183
|
+
Remove-Item -LiteralPath $stopPath -Force -ErrorAction SilentlyContinue
|
|
184
|
+
$script:paused = $false
|
|
185
|
+
$pauseItem.Text = "Pause"
|
|
186
|
+
$script:nextStart = Get-Date
|
|
187
|
+
Set-HenyStatus -State "browser_starting"
|
|
228
188
|
}
|
|
229
189
|
|
|
230
|
-
$openHeny = {
|
|
231
|
-
Start-Process (Get-HenyUrl)
|
|
232
|
-
}
|
|
190
|
+
$openHeny = { Start-Process (Get-HenyUrl) }
|
|
233
191
|
$openItem.Add_Click($openHeny)
|
|
234
192
|
$notifyIcon.Add_DoubleClick($openHeny)
|
|
235
|
-
|
|
236
|
-
$
|
|
237
|
-
if ($script:paused) {
|
|
238
|
-
$script:paused = $false
|
|
239
|
-
$pauseItem.Text = "Pause"
|
|
240
|
-
$script:nextHeartbeat = Get-Date
|
|
241
|
-
Set-HenyStatus -State "connecting" -Detail "Resuming"
|
|
242
|
-
} else {
|
|
243
|
-
$script:paused = $true
|
|
244
|
-
$pauseItem.Text = "Resume"
|
|
245
|
-
Stop-HeartbeatProcess
|
|
246
|
-
Start-Heartbeat -State "offline"
|
|
247
|
-
}
|
|
248
|
-
})
|
|
249
|
-
|
|
250
|
-
$reconnectItem.Add_Click({
|
|
251
|
-
$script:paused = $false
|
|
252
|
-
$pauseItem.Text = "Pause"
|
|
253
|
-
Stop-HeartbeatProcess
|
|
254
|
-
$script:nextHeartbeat = Get-Date
|
|
255
|
-
Set-HenyStatus -State "connecting" -Detail "Reconnecting"
|
|
256
|
-
})
|
|
193
|
+
$pauseItem.Add_Click({ if ($script:paused) { Request-Resume } else { Request-Pause } })
|
|
194
|
+
$reconnectItem.Add_Click({ Request-Pause; Stop-Worker; Request-Resume })
|
|
257
195
|
|
|
258
196
|
$startItem.Add_Click({
|
|
259
197
|
try {
|
|
260
198
|
if ($startItem.Checked) {
|
|
261
199
|
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue
|
|
262
200
|
$startItem.Checked = $false
|
|
263
|
-
$notifyIcon.ShowBalloonTip(2500, "Heny Connect", "Start at sign-in is off.", [Windows.Forms.ToolTipIcon]::Info)
|
|
264
201
|
} else {
|
|
265
202
|
Install-HenyTask -StartNow $false
|
|
266
203
|
$startItem.Checked = $true
|
|
267
|
-
$notifyIcon.ShowBalloonTip(2500, "Heny Connect", "Start at sign-in is on.", [Windows.Forms.ToolTipIcon]::Info)
|
|
268
204
|
}
|
|
269
|
-
} catch {
|
|
270
|
-
Set-HenyStatus -State "error" -Detail $_.Exception.Message
|
|
271
|
-
}
|
|
205
|
+
} catch { Set-HenyStatus -State "error" }
|
|
272
206
|
})
|
|
273
207
|
|
|
274
208
|
$quitItem.Add_Click({
|
|
275
209
|
$script:exiting = $true
|
|
276
210
|
$timer.Stop()
|
|
277
|
-
|
|
211
|
+
Request-Pause
|
|
212
|
+
$limit = (Get-Date).AddSeconds(5)
|
|
213
|
+
while ((Get-Date) -lt $limit) {
|
|
214
|
+
try {
|
|
215
|
+
$state = Get-Content -LiteralPath $statusPath -Raw | ConvertFrom-Json
|
|
216
|
+
if ($state.state -eq "paused") { break }
|
|
217
|
+
} catch {}
|
|
218
|
+
Start-Sleep -Milliseconds 200
|
|
219
|
+
}
|
|
220
|
+
Stop-Worker
|
|
221
|
+
Remove-Item -LiteralPath $pausePath -Force -ErrorAction SilentlyContinue
|
|
222
|
+
Remove-Item -LiteralPath $stopPath -Force -ErrorAction SilentlyContinue
|
|
278
223
|
$notifyIcon.Visible = $false
|
|
279
224
|
[Windows.Forms.Application]::ExitThread()
|
|
280
225
|
})
|
|
@@ -282,19 +227,32 @@ $quitItem.Add_Click({
|
|
|
282
227
|
$timer = [Windows.Forms.Timer]::new()
|
|
283
228
|
$timer.Interval = 1000
|
|
284
229
|
$timer.Add_Tick({
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
230
|
+
if ($script:workerProcess -and $script:workerProcess.HasExited) {
|
|
231
|
+
$code = $script:workerProcess.ExitCode
|
|
232
|
+
Write-TrayStatus -State "worker_exited" -ExitCode $code
|
|
233
|
+
$script:workerProcess.Dispose()
|
|
234
|
+
$script:workerProcess = $null
|
|
235
|
+
if (-not $script:paused) {
|
|
236
|
+
Set-HenyStatus -State "error"
|
|
237
|
+
$script:nextStart = if ($code -in @(2, 3)) { [DateTime]::MaxValue } else { (Get-Date).AddSeconds(15) }
|
|
238
|
+
}
|
|
288
239
|
}
|
|
240
|
+
if ($script:workerProcess) {
|
|
241
|
+
try {
|
|
242
|
+
$state = Get-Content -LiteralPath $statusPath -Raw | ConvertFrom-Json
|
|
243
|
+
if ($script:paused -and $state.state -ne "paused") { Set-HenyStatus -State "pausing" } else { Set-HenyStatus -State ([string] $state.state) -Action ([string] $state.currentAction) }
|
|
244
|
+
} catch {}
|
|
245
|
+
} elseif ($script:paused) { Set-HenyStatus -State "paused" }
|
|
246
|
+
if (-not $script:paused -and -not $script:workerProcess -and (Get-Date) -ge $script:nextStart) { Start-Worker }
|
|
289
247
|
})
|
|
290
248
|
$timer.Start()
|
|
291
|
-
|
|
249
|
+
if ($script:paused) { Set-HenyStatus -State "paused"; $pauseItem.Text = "Resume" } else { Start-Worker }
|
|
292
250
|
|
|
293
251
|
try {
|
|
294
252
|
[Windows.Forms.Application]::Run()
|
|
295
253
|
} finally {
|
|
296
254
|
$timer.Stop()
|
|
297
|
-
Stop-
|
|
255
|
+
Stop-Worker
|
|
298
256
|
$notifyIcon.Visible = $false
|
|
299
257
|
$notifyIcon.Dispose()
|
|
300
258
|
$menu.Dispose()
|