Add Windows service host and system tray controller
All checks were successful
CI / test (push) Successful in 7s
All checks were successful
CI / test (push) Successful in 7s
This commit is contained in:
210
screenjob_tray.ps1
Normal file
210
screenjob_tray.ps1
Normal file
@@ -0,0 +1,210 @@
|
||||
param(
|
||||
[string]$ServiceName = "ScreenJobBackend"
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
Add-Type -AssemblyName System.Windows.Forms
|
||||
Add-Type -AssemblyName System.Drawing
|
||||
|
||||
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$controlScript = Join-Path $scriptDir "tray_service_control.ps1"
|
||||
$logsDir = Join-Path $scriptDir "screenjob_runs\service"
|
||||
$defaultHost = "127.0.0.1"
|
||||
$defaultPort = "8787"
|
||||
|
||||
function Read-EnvConfig {
|
||||
param([string]$EnvFilePath)
|
||||
$result = @{}
|
||||
if (-not (Test-Path -LiteralPath $EnvFilePath)) {
|
||||
return $result
|
||||
}
|
||||
|
||||
foreach ($line in Get-Content -Path $EnvFilePath) {
|
||||
$trimmed = $line.Trim()
|
||||
if ($trimmed.Length -eq 0 -or $trimmed.StartsWith("#")) {
|
||||
continue
|
||||
}
|
||||
$parts = $trimmed.Split("=", 2)
|
||||
if ($parts.Count -eq 2) {
|
||||
$result[$parts[0].Trim()] = $parts[1].Trim()
|
||||
}
|
||||
}
|
||||
return $result
|
||||
}
|
||||
|
||||
function Get-ServiceStatusSafe {
|
||||
param([string]$Name)
|
||||
try {
|
||||
$svc = Get-Service -Name $Name -ErrorAction Stop
|
||||
return $svc.Status.ToString()
|
||||
} catch {
|
||||
return "NotInstalled"
|
||||
}
|
||||
}
|
||||
|
||||
function Invoke-ServiceActionElevated {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$Action,
|
||||
[Parameter(Mandatory = $true)][string]$Name
|
||||
)
|
||||
|
||||
if (-not (Test-Path -LiteralPath $controlScript)) {
|
||||
[System.Windows.Forms.MessageBox]::Show(
|
||||
"Missing control script: $controlScript",
|
||||
"ScreenJob Tray",
|
||||
[System.Windows.Forms.MessageBoxButtons]::OK,
|
||||
[System.Windows.Forms.MessageBoxIcon]::Error
|
||||
) | Out-Null
|
||||
return
|
||||
}
|
||||
|
||||
$argList = @(
|
||||
"-NoProfile",
|
||||
"-ExecutionPolicy", "Bypass",
|
||||
"-File", "`"$controlScript`"",
|
||||
"-Action", $Action,
|
||||
"-ServiceName", $Name
|
||||
)
|
||||
|
||||
try {
|
||||
Start-Process -FilePath "powershell.exe" -ArgumentList $argList -Verb RunAs -WindowStyle Hidden | Out-Null
|
||||
} catch {
|
||||
# User canceled UAC prompt or launch failed.
|
||||
}
|
||||
}
|
||||
|
||||
function Get-DashboardUrl {
|
||||
$envFile = Join-Path $scriptDir ".env"
|
||||
$envVars = Read-EnvConfig -EnvFilePath $envFile
|
||||
|
||||
$host = $defaultHost
|
||||
$port = $defaultPort
|
||||
|
||||
if ($envVars.ContainsKey("SCREENJOB_HOST") -and -not [string]::IsNullOrWhiteSpace($envVars["SCREENJOB_HOST"])) {
|
||||
$host = $envVars["SCREENJOB_HOST"]
|
||||
}
|
||||
if ($envVars.ContainsKey("SCREENJOB_PORT") -and -not [string]::IsNullOrWhiteSpace($envVars["SCREENJOB_PORT"])) {
|
||||
$port = $envVars["SCREENJOB_PORT"]
|
||||
}
|
||||
|
||||
return "http://{0}:{1}/" -f $host, $port
|
||||
}
|
||||
|
||||
function Update-TrayState {
|
||||
param(
|
||||
[System.Windows.Forms.NotifyIcon]$NotifyIcon,
|
||||
[System.Windows.Forms.ToolStripMenuItem]$StatusItem,
|
||||
[string]$Name
|
||||
)
|
||||
|
||||
$status = Get-ServiceStatusSafe -Name $Name
|
||||
$StatusItem.Text = "Status: $status"
|
||||
|
||||
switch ($status) {
|
||||
"Running" {
|
||||
$NotifyIcon.Icon = [System.Drawing.SystemIcons]::Information
|
||||
}
|
||||
"Stopped" {
|
||||
$NotifyIcon.Icon = [System.Drawing.SystemIcons]::Warning
|
||||
}
|
||||
default {
|
||||
$NotifyIcon.Icon = [System.Drawing.SystemIcons]::Error
|
||||
}
|
||||
}
|
||||
|
||||
$tooltip = "ScreenJob Backend: $status"
|
||||
if ($tooltip.Length -gt 63) {
|
||||
$tooltip = $tooltip.Substring(0, 63)
|
||||
}
|
||||
$NotifyIcon.Text = $tooltip
|
||||
}
|
||||
|
||||
$appContext = New-Object System.Windows.Forms.ApplicationContext
|
||||
$notifyIcon = New-Object System.Windows.Forms.NotifyIcon
|
||||
$notifyIcon.Visible = $false
|
||||
|
||||
$menu = New-Object System.Windows.Forms.ContextMenuStrip
|
||||
$statusItem = New-Object System.Windows.Forms.ToolStripMenuItem "Status: Unknown"
|
||||
$statusItem.Enabled = $false
|
||||
|
||||
$refreshItem = New-Object System.Windows.Forms.ToolStripMenuItem "Refresh Status"
|
||||
$refreshItem.Add_Click({
|
||||
Update-TrayState -NotifyIcon $notifyIcon -StatusItem $statusItem -Name $ServiceName
|
||||
})
|
||||
|
||||
$startItem = New-Object System.Windows.Forms.ToolStripMenuItem "Start Service (Admin)"
|
||||
$startItem.Add_Click({
|
||||
Invoke-ServiceActionElevated -Action "start" -Name $ServiceName
|
||||
})
|
||||
|
||||
$stopItem = New-Object System.Windows.Forms.ToolStripMenuItem "Stop Service (Admin)"
|
||||
$stopItem.Add_Click({
|
||||
Invoke-ServiceActionElevated -Action "stop" -Name $ServiceName
|
||||
})
|
||||
|
||||
$restartItem = New-Object System.Windows.Forms.ToolStripMenuItem "Restart Service (Admin)"
|
||||
$restartItem.Add_Click({
|
||||
Invoke-ServiceActionElevated -Action "restart" -Name $ServiceName
|
||||
})
|
||||
|
||||
$dashboardItem = New-Object System.Windows.Forms.ToolStripMenuItem "Open Dashboard"
|
||||
$dashboardItem.Add_Click({
|
||||
$url = Get-DashboardUrl
|
||||
Start-Process $url | Out-Null
|
||||
})
|
||||
|
||||
$logsItem = New-Object System.Windows.Forms.ToolStripMenuItem "Open Service Logs"
|
||||
$logsItem.Add_Click({
|
||||
if (-not (Test-Path -LiteralPath $logsDir)) {
|
||||
New-Item -ItemType Directory -Path $logsDir -Force | Out-Null
|
||||
}
|
||||
Start-Process explorer.exe $logsDir | Out-Null
|
||||
})
|
||||
|
||||
$openFolderItem = New-Object System.Windows.Forms.ToolStripMenuItem "Open Project Folder"
|
||||
$openFolderItem.Add_Click({
|
||||
Start-Process explorer.exe $scriptDir | Out-Null
|
||||
})
|
||||
|
||||
$exitItem = New-Object System.Windows.Forms.ToolStripMenuItem "Exit Tray"
|
||||
$exitItem.Add_Click({
|
||||
$refreshTimer.Stop()
|
||||
$notifyIcon.Visible = $false
|
||||
$notifyIcon.Dispose()
|
||||
$menu.Dispose()
|
||||
$appContext.ExitThread()
|
||||
})
|
||||
|
||||
[void]$menu.Items.Add($statusItem)
|
||||
[void]$menu.Items.Add($refreshItem)
|
||||
[void]$menu.Items.Add((New-Object System.Windows.Forms.ToolStripSeparator))
|
||||
[void]$menu.Items.Add($startItem)
|
||||
[void]$menu.Items.Add($stopItem)
|
||||
[void]$menu.Items.Add($restartItem)
|
||||
[void]$menu.Items.Add((New-Object System.Windows.Forms.ToolStripSeparator))
|
||||
[void]$menu.Items.Add($dashboardItem)
|
||||
[void]$menu.Items.Add($logsItem)
|
||||
[void]$menu.Items.Add($openFolderItem)
|
||||
[void]$menu.Items.Add((New-Object System.Windows.Forms.ToolStripSeparator))
|
||||
[void]$menu.Items.Add($exitItem)
|
||||
|
||||
$notifyIcon.ContextMenuStrip = $menu
|
||||
$notifyIcon.Visible = $true
|
||||
|
||||
$notifyIcon.Add_DoubleClick({
|
||||
$url = Get-DashboardUrl
|
||||
Start-Process $url | Out-Null
|
||||
})
|
||||
|
||||
$refreshTimer = New-Object System.Windows.Forms.Timer
|
||||
$refreshTimer.Interval = 5000
|
||||
$refreshTimer.Add_Tick({
|
||||
Update-TrayState -NotifyIcon $notifyIcon -StatusItem $statusItem -Name $ServiceName
|
||||
})
|
||||
|
||||
Update-TrayState -NotifyIcon $notifyIcon -StatusItem $statusItem -Name $ServiceName
|
||||
$refreshTimer.Start()
|
||||
|
||||
[System.Windows.Forms.Application]::Run($appContext)
|
||||
Reference in New Issue
Block a user