@trillboards/edge-sdk 0.2.14 → 0.2.16
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/deploy/windows/README.md +7 -0
- package/deploy/windows/build-windows.ps1 +4 -0
- package/deploy/windows/ensure-sensing.ps1 +58 -0
- package/deploy/windows/install-update.ps1 +32 -6
- package/deploy/windows/stop-existing.ps1 +51 -1
- package/deploy/windows/trillboards-edge.cmd +8 -2
- package/deploy/windows/trillboards-hidden-run.vbs +47 -0
- package/deploy/windows/trillboards-setup.ps1 +25 -0
- package/dist/AudienceAnalyzeClient.d.ts +48 -4
- package/dist/AudienceAnalyzeClient.d.ts.map +1 -1
- package/dist/AudienceAnalyzeClient.js +33 -2
- package/dist/AudienceAnalyzeClient.js.map +1 -1
- package/dist/CloudSensingManager.d.ts +157 -7
- package/dist/CloudSensingManager.d.ts.map +1 -1
- package/dist/CloudSensingManager.js +392 -23
- package/dist/CloudSensingManager.js.map +1 -1
- package/dist/EdgeAgent.js +1 -1
- package/dist/SceneChangeDetector.d.ts +39 -3
- package/dist/SceneChangeDetector.d.ts.map +1 -1
- package/dist/SceneChangeDetector.js +84 -16
- package/dist/SceneChangeDetector.js.map +1 -1
- package/dist/VlmAdmissionGate.d.ts +14 -0
- package/dist/VlmAdmissionGate.d.ts.map +1 -1
- package/dist/VlmAdmissionGate.js +14 -0
- package/dist/VlmAdmissionGate.js.map +1 -1
- package/dist/VlmCandidateBuffer.d.ts +247 -0
- package/dist/VlmCandidateBuffer.d.ts.map +1 -0
- package/dist/VlmCandidateBuffer.js +349 -0
- package/dist/VlmCandidateBuffer.js.map +1 -0
- package/dist/config.d.ts +46 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/diagnose.d.ts +1 -1
- package/dist/diagnose.js +1 -1
- package/dist/discovery.d.ts +15 -0
- package/dist/discovery.d.ts.map +1 -1
- package/dist/discovery.js +65 -0
- package/dist/discovery.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/localSensing.d.ts +2 -2
- package/dist/localSensing.d.ts.map +1 -1
- package/dist/localSensing.js +16 -0
- package/dist/localSensing.js.map +1 -1
- package/dist/recorderRanking.d.ts +71 -0
- package/dist/recorderRanking.d.ts.map +1 -0
- package/dist/recorderRanking.js +230 -0
- package/dist/recorderRanking.js.map +1 -0
- package/dist/sensingRunMode.d.ts.map +1 -1
- package/dist/sensingRunMode.js +40 -0
- package/dist/sensingRunMode.js.map +1 -1
- package/dist/setupMode.d.ts +9 -0
- package/dist/setupMode.d.ts.map +1 -1
- package/dist/setupMode.js +23 -1
- package/dist/setupMode.js.map +1 -1
- package/package.json +1 -1
package/deploy/windows/README.md
CHANGED
|
@@ -16,7 +16,14 @@ bin\trillboards-edge.cmd launcher (PATH=bin first; node lib\...\cli.js)
|
|
|
16
16
|
bin\trillboards-setup.vbs no-console launcher for the customer setup app
|
|
17
17
|
bin\trillboards-setup.ps1 native Windows Forms customer setup window
|
|
18
18
|
bin\trillboards-pair.cmd hidden setup engine used by the setup window
|
|
19
|
+
bin\trillboards-hidden-run.vbs runs a helper with NO console (never use cmd's
|
|
20
|
+
`start`: it allocates a visible console before the
|
|
21
|
+
child can hide itself)
|
|
19
22
|
bin\register-task.ps1 registers the logon Scheduled Task
|
|
23
|
+
bin\stop-existing.ps1 DISABLES the task, stops this install's processes,
|
|
24
|
+
and proves bin\node.exe is unlocked before a swap
|
|
25
|
+
bin\ensure-sensing.ps1 re-arms the task (register/enable/start) — closing
|
|
26
|
+
the setup window must never stop sensing
|
|
20
27
|
lib\edge-sdk\dist\cli.js the connector CLI
|
|
21
28
|
lib\node_modules\... runtime subset (NO onnxruntime/sharp/sqlite; LiteRT-LM
|
|
22
29
|
provides the on-device VLM outside Node)
|
|
@@ -173,6 +173,10 @@ Copy-Item -Force "$Here\trillboards-pair.cmd" "$Payload\bin\trillboards-pair.cmd
|
|
|
173
173
|
Copy-Item -Force "$Here\trillboards-setup.ps1" "$Payload\bin\trillboards-setup.ps1"
|
|
174
174
|
Copy-Item -Force "$Here\trillboards-setup.vbs" "$Payload\bin\trillboards-setup.vbs"
|
|
175
175
|
Copy-Item -Force "$Here\trillboards-edge-task.vbs" "$Payload\bin\trillboards-edge-task.vbs"
|
|
176
|
+
# Hidden fire-and-forget host: the launcher's local-AI repair goes through this
|
|
177
|
+
# instead of cmd's `start`, which would allocate a visible console.
|
|
178
|
+
Copy-Item -Force "$Here\trillboards-hidden-run.vbs" "$Payload\bin\trillboards-hidden-run.vbs"
|
|
179
|
+
Copy-Item -Force "$Here\ensure-sensing.ps1" "$Payload\bin\ensure-sensing.ps1"
|
|
176
180
|
Copy-Item -Force "$Here\run-connector.ps1" "$Payload\bin\run-connector.ps1"
|
|
177
181
|
Copy-Item -Force "$Here\register-task.ps1" "$Payload\bin\register-task.ps1"
|
|
178
182
|
Copy-Item -Force "$Here\stop-existing.ps1" "$Payload\bin\stop-existing.ps1"
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<#
|
|
2
|
+
ensure-sensing.ps1 -- make the background connector registered, ENABLED and
|
|
3
|
+
running. Idempotent, windowless, and safe to call at any moment.
|
|
4
|
+
|
|
5
|
+
This exists because of one field rule: a customer closing something they CAN
|
|
6
|
+
see must never be what stops sensing. The setup wizard is the only visible
|
|
7
|
+
Trillboards window, and closing it taskkill /T /F's the pairing helper tree --
|
|
8
|
+
which may be sitting between "config written" and "scheduled task started".
|
|
9
|
+
It is also the recovery for a disabled task: stop-existing.ps1 disables
|
|
10
|
+
TrillboardsEdge during an upgrade, and a DISABLED task suppresses the AtLogOn
|
|
11
|
+
trigger, so a reboot would not bring sensing back on its own.
|
|
12
|
+
#>
|
|
13
|
+
[CmdletBinding()]
|
|
14
|
+
param(
|
|
15
|
+
[Parameter(Mandatory = $true)][string]$InstallDir
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
$ErrorActionPreference = "Stop"
|
|
19
|
+
$TaskName = "TrillboardsEdge"
|
|
20
|
+
|
|
21
|
+
# Before pairing there is nothing to run: starting the task without a config
|
|
22
|
+
# just crash-loops it against the RestartCount budget.
|
|
23
|
+
if (-not (Test-Path (Join-Path $InstallDir "trillboards.config.json"))) {
|
|
24
|
+
Write-Host "No paired configuration yet - nothing to resume."
|
|
25
|
+
exit 0
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
$task = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
|
|
29
|
+
if (-not $task) {
|
|
30
|
+
$register = Join-Path $InstallDir "bin\register-task.ps1"
|
|
31
|
+
if (-not (Test-Path $register)) {
|
|
32
|
+
Write-Error "Cannot resume sensing: $register is missing."
|
|
33
|
+
exit 1
|
|
34
|
+
}
|
|
35
|
+
& $register -InstallDir $InstallDir | Out-Null
|
|
36
|
+
$task = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
|
|
37
|
+
if (-not $task) {
|
|
38
|
+
Write-Error "Cannot resume sensing: scheduled task '$TaskName' did not register."
|
|
39
|
+
exit 1
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if ($task.State -eq 'Disabled') {
|
|
44
|
+
Enable-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue | Out-Null
|
|
45
|
+
$task = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if ($task -and $task.State -ne 'Running') {
|
|
49
|
+
Start-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
$final = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
|
|
53
|
+
if (-not $final -or $final.State -eq 'Disabled') {
|
|
54
|
+
Write-Error "Scheduled task '$TaskName' is not runnable after resume."
|
|
55
|
+
exit 1
|
|
56
|
+
}
|
|
57
|
+
Write-Host "Background sensing is registered, enabled and scheduled (state: $($final.State))."
|
|
58
|
+
exit 0
|
|
@@ -43,6 +43,31 @@ function Register-Connector([string]$Root) {
|
|
|
43
43
|
if ($LASTEXITCODE -ne 0) { throw "Scheduled-task registration failed." }
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
function Assert-ConnectorScheduled {
|
|
47
|
+
# stop-existing.ps1 DISABLES the task so restart-on-failure cannot relaunch
|
|
48
|
+
# node.exe mid-swap. A disabled task suppresses the AtLogOn trigger too, so
|
|
49
|
+
# leaving it disabled would mean sensing never comes back - not even after a
|
|
50
|
+
# reboot. Re-registration should have re-enabled it; verify rather than trust.
|
|
51
|
+
$task = Get-ScheduledTask -TaskName "TrillboardsEdge" -ErrorAction SilentlyContinue
|
|
52
|
+
if (-not $task) { throw "Scheduled task 'TrillboardsEdge' is missing after registration." }
|
|
53
|
+
if ($task.State -eq 'Disabled') {
|
|
54
|
+
Enable-ScheduledTask -TaskName "TrillboardsEdge" -ErrorAction SilentlyContinue | Out-Null
|
|
55
|
+
$task = Get-ScheduledTask -TaskName "TrillboardsEdge" -ErrorAction SilentlyContinue
|
|
56
|
+
if (-not $task -or $task.State -eq 'Disabled') {
|
|
57
|
+
throw "Scheduled task 'TrillboardsEdge' stayed disabled - sensing would not restart at logon."
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function Restore-ConnectorSchedule {
|
|
63
|
+
# Failure path. Whatever went wrong, the customer must NOT be left with a
|
|
64
|
+
# permanently disabled connector: that is a silent, reboot-proof outage.
|
|
65
|
+
Enable-ScheduledTask -TaskName "TrillboardsEdge" -ErrorAction SilentlyContinue | Out-Null
|
|
66
|
+
if (Test-Path (Join-Path $InstallDir "trillboards.config.json")) {
|
|
67
|
+
Start-ScheduledTask -TaskName "TrillboardsEdge" -ErrorAction SilentlyContinue
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
46
71
|
try {
|
|
47
72
|
Assert-ConnectorVersion $StagingDir
|
|
48
73
|
& (Join-Path $StagingDir "bin\stop-existing.ps1") -InstallDir $InstallDir
|
|
@@ -66,6 +91,7 @@ try {
|
|
|
66
91
|
|
|
67
92
|
Assert-ConnectorVersion $InstallDir
|
|
68
93
|
Register-Connector $InstallDir
|
|
94
|
+
Assert-ConnectorScheduled
|
|
69
95
|
if (Test-Path (Join-Path $InstallDir "trillboards.config.json")) {
|
|
70
96
|
Start-ScheduledTask -TaskName "TrillboardsEdge" -ErrorAction Stop
|
|
71
97
|
}
|
|
@@ -90,12 +116,12 @@ try {
|
|
|
90
116
|
}
|
|
91
117
|
}
|
|
92
118
|
if ($movedPrevious.Count -gt 0) {
|
|
93
|
-
try {
|
|
94
|
-
Register-Connector $InstallDir
|
|
95
|
-
if (Test-Path (Join-Path $InstallDir "trillboards.config.json")) {
|
|
96
|
-
Start-ScheduledTask -TaskName "TrillboardsEdge" -ErrorAction SilentlyContinue
|
|
97
|
-
}
|
|
98
|
-
} catch {}
|
|
119
|
+
try { Register-Connector $InstallDir } catch {}
|
|
99
120
|
}
|
|
121
|
+
# UNCONDITIONAL. When the failure happened before anything moved there is no
|
|
122
|
+
# re-registration to re-enable the task, and stop-existing.ps1 already
|
|
123
|
+
# disabled it - so this is the only thing standing between a failed upgrade
|
|
124
|
+
# and a connector that never runs again.
|
|
125
|
+
try { Restore-ConnectorSchedule } catch {}
|
|
100
126
|
throw "Trillboards Edge update failed and the previous version was restored: $($failure.Exception.Message)"
|
|
101
127
|
}
|
|
@@ -12,16 +12,32 @@ $ErrorActionPreference = "Stop"
|
|
|
12
12
|
$root = [IO.Path]::GetFullPath($InstallDir).TrimEnd('\')
|
|
13
13
|
$rootPrefix = $root + '\'
|
|
14
14
|
|
|
15
|
+
# DISABLE BEFORE STOP. register-task.ps1 registers the task with
|
|
16
|
+
# `-RestartCount 99 -RestartInterval 1 minute`, so Stop-ScheduledTask ends the
|
|
17
|
+
# instance as a FAILURE and Task Scheduler relaunches node.exe about a minute
|
|
18
|
+
# later — right inside the installer's bin\ + lib\ move. That is the "reinstall
|
|
19
|
+
# hit a locked node.exe" the field test saw. Disabling suppresses the restart
|
|
20
|
+
# AND the AtLogOn trigger for the whole swap window; install-update.ps1 owns
|
|
21
|
+
# re-enabling it on every exit path, and the uninstaller deletes the task.
|
|
22
|
+
Disable-ScheduledTask -TaskName "TrillboardsEdge" -ErrorAction SilentlyContinue | Out-Null
|
|
15
23
|
Stop-ScheduledTask -TaskName "TrillboardsEdge" -ErrorAction SilentlyContinue
|
|
16
24
|
Start-Sleep -Milliseconds 750
|
|
17
25
|
|
|
18
26
|
function Get-TrillboardsEdgeProcesses {
|
|
27
|
+
# The process that actually holds bin\node.exe open is node.exe itself, and
|
|
28
|
+
# its command line names NONE of these scripts — it names the cli.js entry.
|
|
29
|
+
# Win32_Process.ExecutablePath is empty across a 32/64-bit boundary, and then
|
|
30
|
+
# the marker list is the only matcher left, so it has to cover the runtime.
|
|
19
31
|
$markers = @(
|
|
20
32
|
'trillboards-edge-task.vbs',
|
|
33
|
+
'trillboards-hidden-run.vbs',
|
|
21
34
|
'run-connector.ps1',
|
|
22
35
|
'trillboards-edge.cmd',
|
|
23
36
|
'trillboards-setup.ps1',
|
|
24
|
-
'trillboards-pair.cmd'
|
|
37
|
+
'trillboards-pair.cmd',
|
|
38
|
+
'setup-litertlm.ps1',
|
|
39
|
+
'cli.js',
|
|
40
|
+
'ffmpeg.exe'
|
|
25
41
|
)
|
|
26
42
|
|
|
27
43
|
@(Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
|
|
@@ -69,4 +85,38 @@ if ($remaining.Count -gt 0) {
|
|
|
69
85
|
throw "Could not stop the existing Trillboards connector processes: $ids"
|
|
70
86
|
}
|
|
71
87
|
|
|
88
|
+
function Assert-BinariesUnlocked {
|
|
89
|
+
# "No matching process" is NOT "the file is writable". A handle held by an
|
|
90
|
+
# AV scanner, an Explorer preview, or a process we could not attribute keeps
|
|
91
|
+
# bin\node.exe locked, and install-update.ps1 would then fail HALFWAY through
|
|
92
|
+
# moving bin\ and lib\. Prove writability before the installer commits.
|
|
93
|
+
param([string]$Root, [int]$TimeoutSeconds = 15)
|
|
94
|
+
|
|
95
|
+
$targets = @(
|
|
96
|
+
(Join-Path $Root 'bin\node.exe'),
|
|
97
|
+
(Join-Path $Root 'bin\ffmpeg.exe')
|
|
98
|
+
) | Where-Object { Test-Path -LiteralPath $_ }
|
|
99
|
+
if ($targets.Count -eq 0) { return }
|
|
100
|
+
|
|
101
|
+
$deadline = [DateTime]::UtcNow.AddSeconds($TimeoutSeconds)
|
|
102
|
+
foreach ($target in $targets) {
|
|
103
|
+
while ($true) {
|
|
104
|
+
$stream = $null
|
|
105
|
+
try {
|
|
106
|
+
$stream = [IO.File]::Open($target, [IO.FileMode]::Open, [IO.FileAccess]::ReadWrite, [IO.FileShare]::None)
|
|
107
|
+
break
|
|
108
|
+
} catch {
|
|
109
|
+
if ([DateTime]::UtcNow -ge $deadline) {
|
|
110
|
+
throw "A Trillboards connector binary is still locked by another process: $target"
|
|
111
|
+
}
|
|
112
|
+
Start-Sleep -Milliseconds 300
|
|
113
|
+
} finally {
|
|
114
|
+
if ($null -ne $stream) { $stream.Dispose() }
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
Assert-BinariesUnlocked -Root $root
|
|
121
|
+
|
|
72
122
|
Write-Host "Stopped existing Trillboards Edge processes."
|
|
@@ -19,12 +19,18 @@ if /I "%~1"=="auto-sense" (
|
|
|
19
19
|
if errorlevel 1 set "NEEDS_LOCAL_AI=1"
|
|
20
20
|
curl.exe --fail --silent --max-time 2 http://127.0.0.1:9379/v1/models >nul 2>&1
|
|
21
21
|
if errorlevel 1 set "NEEDS_LOCAL_AI=1"
|
|
22
|
+
REM Launch the repair through the wscript host, NOT `start`. cmd's `start`
|
|
23
|
+
REM allocates a NEW console for the child before PowerShell can hide itself,
|
|
24
|
+
REM so the customer saw a black window on exactly the reboot that needs a
|
|
25
|
+
REM repair. wscript.exe is GUI-subsystem and Run(...,0,False) creates the
|
|
26
|
+
REM process hidden from its first instruction.
|
|
22
27
|
if "!NEEDS_LOCAL_AI!"=="1" if exist "%BIN%setup-litertlm.ps1" (
|
|
23
28
|
set "SETUP_PROGRESS=%LOCALAPPDATA%\Trillboards\setup-progress.json"
|
|
29
|
+
set "HIDDEN_RUN=%WINDIR%\System32\wscript.exe"
|
|
24
30
|
if exist "!SETUP_PROGRESS!" (
|
|
25
|
-
|
|
31
|
+
"!HIDDEN_RUN!" "%BIN%trillboards-hidden-run.vbs" "powershell.exe" "-NoProfile" "-ExecutionPolicy" "Bypass" "-WindowStyle" "Hidden" "-File" "%BIN%setup-litertlm.ps1" "-RequireBundledModel" "-ProgressPath" "!SETUP_PROGRESS!"
|
|
26
32
|
) else (
|
|
27
|
-
|
|
33
|
+
"!HIDDEN_RUN!" "%BIN%trillboards-hidden-run.vbs" "powershell.exe" "-NoProfile" "-ExecutionPolicy" "Bypass" "-WindowStyle" "Hidden" "-File" "%BIN%setup-litertlm.ps1" "-RequireBundledModel"
|
|
28
34
|
)
|
|
29
35
|
)
|
|
30
36
|
)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
Option Explicit
|
|
2
|
+
|
|
3
|
+
' trillboards-hidden-run.vbs — run a command with NO console window, ever.
|
|
4
|
+
'
|
|
5
|
+
' cmd's `start "" prog.exe` allocates a NEW console (conhost) for the child
|
|
6
|
+
' BEFORE the child can hide itself, so `powershell.exe -WindowStyle Hidden`
|
|
7
|
+
' still flashes — and on a slow logon it is a black window the customer sees
|
|
8
|
+
' and closes. wscript.exe is a GUI-subsystem host: WScript.Shell.Run with
|
|
9
|
+
' window style 0 (SW_HIDE) creates the process with a hidden console from the
|
|
10
|
+
' very first instruction. This is the same mechanism trillboards-edge-task.vbs
|
|
11
|
+
' uses for the connector supervisor; this host is the fire-and-forget variant
|
|
12
|
+
' for helpers launched from a .cmd.
|
|
13
|
+
'
|
|
14
|
+
' Usage:
|
|
15
|
+
' wscript.exe "trillboards-hidden-run.vbs" <exe> [arg]...
|
|
16
|
+
' Every argument after <exe> is forwarded verbatim; arguments containing
|
|
17
|
+
' whitespace are re-quoted so paths like %LOCALAPPDATA%\Trillboards survive.
|
|
18
|
+
|
|
19
|
+
Dim shell, index, command, argument
|
|
20
|
+
|
|
21
|
+
If WScript.Arguments.Count < 1 Then
|
|
22
|
+
' Nothing to run. Exit quietly — a hidden helper must never pop a dialog.
|
|
23
|
+
WScript.Quit 2
|
|
24
|
+
End If
|
|
25
|
+
|
|
26
|
+
Set shell = CreateObject("WScript.Shell")
|
|
27
|
+
|
|
28
|
+
command = ""
|
|
29
|
+
For index = 0 To WScript.Arguments.Count - 1
|
|
30
|
+
argument = WScript.Arguments(index)
|
|
31
|
+
' Re-quote anything that is empty or contains whitespace. Arguments that are
|
|
32
|
+
' already quoted are left alone so callers can pass pre-quoted values.
|
|
33
|
+
If Len(argument) = 0 Then
|
|
34
|
+
argument = Chr(34) & Chr(34)
|
|
35
|
+
ElseIf InStr(argument, " ") > 0 Or InStr(argument, vbTab) > 0 Then
|
|
36
|
+
If Not (Left(argument, 1) = Chr(34) And Right(argument, 1) = Chr(34)) Then
|
|
37
|
+
argument = Chr(34) & argument & Chr(34)
|
|
38
|
+
End If
|
|
39
|
+
End If
|
|
40
|
+
If Len(command) > 0 Then command = command & " "
|
|
41
|
+
command = command & argument
|
|
42
|
+
Next
|
|
43
|
+
|
|
44
|
+
' Style 0 == SW_HIDE. False == do not wait: a local-AI repair must never hold
|
|
45
|
+
' up the connector's own startup.
|
|
46
|
+
shell.Run command, 0, False
|
|
47
|
+
WScript.Quit 0
|
|
@@ -287,6 +287,30 @@ function Stop-SetupProcess {
|
|
|
287
287
|
}
|
|
288
288
|
}
|
|
289
289
|
|
|
290
|
+
function Resume-BackgroundSensing {
|
|
291
|
+
# The wizard is the ONE window a customer can see, and closing it
|
|
292
|
+
# taskkill /T /F's the whole pairing tree. If that happens between "config
|
|
293
|
+
# written" and "scheduled task started" — or during an upgrade, while
|
|
294
|
+
# stop-existing.ps1 has the task disabled — sensing would stay down with
|
|
295
|
+
# nothing to retry it. Closing a window must never be what stops sensing.
|
|
296
|
+
$installDir = Split-Path -Parent $BinDir
|
|
297
|
+
$ensure = Join-Path $BinDir 'ensure-sensing.ps1'
|
|
298
|
+
if (-not (Test-Path $ensure)) { return }
|
|
299
|
+
if (-not (Test-Path (Join-Path $installDir 'trillboards.config.json'))) { return }
|
|
300
|
+
|
|
301
|
+
$startInfo = New-Object System.Diagnostics.ProcessStartInfo
|
|
302
|
+
$startInfo.FileName = 'powershell.exe'
|
|
303
|
+
$startInfo.Arguments = ('-NoProfile -NonInteractive -ExecutionPolicy Bypass -WindowStyle Hidden -File "{0}" -InstallDir "{1}"' -f $ensure, $installDir)
|
|
304
|
+
$startInfo.UseShellExecute = $false
|
|
305
|
+
$startInfo.CreateNoWindow = $true
|
|
306
|
+
$startInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden
|
|
307
|
+
try {
|
|
308
|
+
[void][System.Diagnostics.Process]::Start($startInfo)
|
|
309
|
+
} catch {
|
|
310
|
+
# Best-effort: the logon trigger is still the primary recovery path.
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
290
314
|
function Render-State($State) {
|
|
291
315
|
$stage = [string](Get-StateValue $State 'stage')
|
|
292
316
|
if (-not $stage) { return }
|
|
@@ -380,6 +404,7 @@ $Action.Add_Click({
|
|
|
380
404
|
|
|
381
405
|
$Form.Add_FormClosing({
|
|
382
406
|
Stop-SetupProcess
|
|
407
|
+
Resume-BackgroundSensing
|
|
383
408
|
if ($null -ne $script:SetupMutex) {
|
|
384
409
|
try { $script:SetupMutex.ReleaseMutex() } catch { }
|
|
385
410
|
$script:SetupMutex.Dispose()
|
|
@@ -33,7 +33,30 @@ export interface AudienceAnalyzeClientOptions {
|
|
|
33
33
|
/** Image height sent in the body metadata. Optional. */
|
|
34
34
|
imageHeight?: number;
|
|
35
35
|
}
|
|
36
|
-
|
|
36
|
+
/**
|
|
37
|
+
* The frame's OWN pixel dimensions, per request.
|
|
38
|
+
*
|
|
39
|
+
* The constructor's `imageWidth`/`imageHeight` are a per-FEED config value fixed
|
|
40
|
+
* at startup, so they cannot describe a feed that renegotiates resolution and
|
|
41
|
+
* they are simply ABSENT on multi-channel DVR/NVR feeds (which carry no
|
|
42
|
+
* top-level `camera.width`/`height` — see `ResolvedFeed.width?`). That made the
|
|
43
|
+
* one number the enterprise topology needed the one number it never sent.
|
|
44
|
+
*
|
|
45
|
+
* These override the constructor value for a single call, so a caller that has
|
|
46
|
+
* measured the decoded frame — `CloudSensingManager` already calls
|
|
47
|
+
* `safeGetResolution(camera)` on every capture to drive the JPEG encoder — can
|
|
48
|
+
* report what the camera actually delivered instead of what it was configured
|
|
49
|
+
* for. Omitted ⇒ the constructor value is used ⇒ single-camera feeds are
|
|
50
|
+
* unchanged. Neither present ⇒ the field is absent from the body and the server
|
|
51
|
+
* stores NULL, which means "not reported" and never 0.
|
|
52
|
+
*/
|
|
53
|
+
export interface FrameDimensions {
|
|
54
|
+
/** Decoded pixel width of the frame being sent. */
|
|
55
|
+
imageWidth?: number;
|
|
56
|
+
/** Decoded pixel height of the frame being sent. */
|
|
57
|
+
imageHeight?: number;
|
|
58
|
+
}
|
|
59
|
+
export interface AudienceAnalyzeRequest extends FrameDimensions {
|
|
37
60
|
/** Raw JPEG bytes for this frame. */
|
|
38
61
|
jpeg: Buffer;
|
|
39
62
|
/** Capture timestamp (epoch ms). Default: Date.now(). */
|
|
@@ -64,8 +87,22 @@ export interface CameraHealthReport {
|
|
|
64
87
|
lastFailureMessage?: string;
|
|
65
88
|
/** AI/inference state, deliberately separate from RTSP/video health. */
|
|
66
89
|
sensingState?: CameraSensingState;
|
|
67
|
-
/**
|
|
68
|
-
|
|
90
|
+
/**
|
|
91
|
+
* What the connector actually PROVED, locally, without uploading the image.
|
|
92
|
+
* Two different facts, never interchangeable:
|
|
93
|
+
*
|
|
94
|
+
* `stream_open` — the RTSP handshake completed: the RECORDER IS REACHABLE.
|
|
95
|
+
* Says nothing about video. Carries NO `lastFrameAtMs`.
|
|
96
|
+
* `decoded_frame` — ffmpeg decoded a real frame off this feed: VIDEO IS
|
|
97
|
+
* HEALTHY. Always accompanied by `lastFrameAtMs`.
|
|
98
|
+
*
|
|
99
|
+
* Collapsing these is how a camera that answers RTSP and delivers nothing
|
|
100
|
+
* rendered as "Live — connected and sending video": a bare handshake claimed
|
|
101
|
+
* `decoded_frame`, and every reconnect refreshed the frame clock, so the feed
|
|
102
|
+
* could never age into "waiting for video". Reachability is the WEAKER claim
|
|
103
|
+
* and must never be able to mint a frame timestamp.
|
|
104
|
+
*/
|
|
105
|
+
captureProof?: 'decoded_frame' | 'stream_open';
|
|
69
106
|
}
|
|
70
107
|
/** Minimal injectable HTTP transport — lets tests stub the network entirely. */
|
|
71
108
|
export interface HttpPoster {
|
|
@@ -90,6 +127,13 @@ export declare class AudienceAnalyzeClient {
|
|
|
90
127
|
constructor(options: AudienceAnalyzeClientOptions, poster?: HttpPoster);
|
|
91
128
|
/** The resolved POST URL (exposed for assertions / logging). */
|
|
92
129
|
getEndpoint(): string;
|
|
130
|
+
/**
|
|
131
|
+
* Resolve this call's frame dimensions: what the caller MEASURED for this
|
|
132
|
+
* frame, else what the feed was CONFIGURED with. One rule, so `analyze` and
|
|
133
|
+
* `analyzePreAnalyzed` cannot drift into reporting different resolutions for
|
|
134
|
+
* the same camera.
|
|
135
|
+
*/
|
|
136
|
+
private resolveFrameDimensions;
|
|
93
137
|
private authHeaders;
|
|
94
138
|
/**
|
|
95
139
|
* POST a JPEG frame for cloud audience analysis. Returns the parsed response.
|
|
@@ -112,7 +156,7 @@ export declare class AudienceAnalyzeClient {
|
|
|
112
156
|
* is passed, NO `imageBase64` is sent (results-only, privacy-preserving
|
|
113
157
|
* default for empty/uninteresting scenes).
|
|
114
158
|
*/
|
|
115
|
-
analyzePreAnalyzed(preAnalyzed: Record<string, unknown>, request?: {
|
|
159
|
+
analyzePreAnalyzed(preAnalyzed: Record<string, unknown>, request?: FrameDimensions & {
|
|
116
160
|
capturedAt?: number;
|
|
117
161
|
captureMode?: string;
|
|
118
162
|
extra?: Record<string, unknown>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AudienceAnalyzeClient.d.ts","sourceRoot":"","sources":["../src/AudienceAnalyzeClient.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,WAAW,4BAA4B;IAC3C,6EAA6E;IAC7E,UAAU,EAAE,MAAM,CAAC;IACnB,8DAA8D;IAC9D,WAAW,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"AudienceAnalyzeClient.d.ts","sourceRoot":"","sources":["../src/AudienceAnalyzeClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -60,6 +60,18 @@ class AudienceAnalyzeClient {
|
|
|
60
60
|
getEndpoint() {
|
|
61
61
|
return this.endpoint;
|
|
62
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Resolve this call's frame dimensions: what the caller MEASURED for this
|
|
65
|
+
* frame, else what the feed was CONFIGURED with. One rule, so `analyze` and
|
|
66
|
+
* `analyzePreAnalyzed` cannot drift into reporting different resolutions for
|
|
67
|
+
* the same camera.
|
|
68
|
+
*/
|
|
69
|
+
resolveFrameDimensions(dims) {
|
|
70
|
+
return {
|
|
71
|
+
imageWidth: dims.imageWidth ?? this.imageWidth,
|
|
72
|
+
imageHeight: dims.imageHeight ?? this.imageHeight,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
63
75
|
authHeaders() {
|
|
64
76
|
return {
|
|
65
77
|
'Content-Type': 'application/json',
|
|
@@ -80,14 +92,23 @@ class AudienceAnalyzeClient {
|
|
|
80
92
|
}
|
|
81
93
|
const capturedAt = request.capturedAt ?? Date.now();
|
|
82
94
|
const imageBase64 = request.jpeg.toString('base64');
|
|
95
|
+
// Per-frame measurement wins over the per-feed constructor config; see
|
|
96
|
+
// FrameDimensions. `??` and not `||` so a caller may not be surprised by 0 —
|
|
97
|
+
// though 0 is not a resolution and the server rejects it either way.
|
|
98
|
+
const { imageWidth, imageHeight } = this.resolveFrameDimensions(request);
|
|
83
99
|
const payload = {
|
|
84
100
|
imageBase64,
|
|
85
101
|
capturedAt,
|
|
86
102
|
...(this.screenId ? { screenId: this.screenId } : {}),
|
|
87
103
|
...(this.fingerprint ? { fingerprint: this.fingerprint } : {}),
|
|
88
|
-
...(
|
|
89
|
-
...(
|
|
104
|
+
...(imageWidth ? { imageWidth } : {}),
|
|
105
|
+
...(imageHeight ? { imageHeight } : {}),
|
|
90
106
|
...(request.captureMode ? { captureMode: request.captureMode } : {}),
|
|
107
|
+
// DELIBERATELY LAST, and deliberately able to override every key above,
|
|
108
|
+
// including imageWidth/imageHeight. This is long-standing behaviour that
|
|
109
|
+
// callers rely on to send fields this interface does not name; narrowing
|
|
110
|
+
// it would be a silent breaking change to the wire contract. Pinned by
|
|
111
|
+
// test so nobody "fixes" the ordering.
|
|
91
112
|
...(request.extra || {}),
|
|
92
113
|
};
|
|
93
114
|
const body = JSON.stringify(payload);
|
|
@@ -139,13 +160,23 @@ class AudienceAnalyzeClient {
|
|
|
139
160
|
else if (typeof request.imageBase64 === 'string' && request.imageBase64.length > 0) {
|
|
140
161
|
imageBase64 = request.imageBase64;
|
|
141
162
|
}
|
|
163
|
+
// The resolution the ON-DEVICE model actually saw. Reported here too — an
|
|
164
|
+
// observation from the local-inference path is still an observation derived
|
|
165
|
+
// from a frame, and it is the path where the resolution question is most
|
|
166
|
+
// pointed, since the connector is exactly the multi-channel DVR/NVR product.
|
|
167
|
+
// Note this method previously sent NO dimensions at all, not even the
|
|
168
|
+
// constructor's.
|
|
169
|
+
const { imageWidth, imageHeight } = this.resolveFrameDimensions(request);
|
|
142
170
|
const payload = {
|
|
143
171
|
preAnalyzed,
|
|
144
172
|
capturedAt,
|
|
145
173
|
...(imageBase64 ? { imageBase64 } : {}),
|
|
146
174
|
...(this.screenId ? { screenId: this.screenId } : {}),
|
|
147
175
|
...(this.fingerprint ? { fingerprint: this.fingerprint } : {}),
|
|
176
|
+
...(imageWidth ? { imageWidth } : {}),
|
|
177
|
+
...(imageHeight ? { imageHeight } : {}),
|
|
148
178
|
...(request.captureMode ? { captureMode: request.captureMode } : {}),
|
|
179
|
+
// Same last-spread override semantics as analyze(); see the note there.
|
|
149
180
|
...(request.extra || {}),
|
|
150
181
|
};
|
|
151
182
|
const result = await this.poster(this.endpoint, { method: 'POST', headers: this.authHeaders(), timeoutMs: this.timeoutMs }, JSON.stringify(payload));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AudienceAnalyzeClient.js","sourceRoot":"","sources":["../src/AudienceAnalyzeClient.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAA6B;AAC7B,6CAA+B;AAC/B,6BAA0B;AAC1B,mCAAoC;
|
|
1
|
+
{"version":3,"file":"AudienceAnalyzeClient.js","sourceRoot":"","sources":["../src/AudienceAnalyzeClient.ts"],"names":[],"mappings":"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"}
|