Files
COPILOT/Docs/legacy-architecture/appserver.md
klas 40143734fc Initial commit: COPILOT D6 Flutter keyboard controller
Flutter web app replacing legacy WPF CCTV surveillance keyboard controller.
Includes wall overview, section view with monitor grid, camera input,
PTZ control, alarm/lock/sequence BLoCs, and legacy-matching UI styling.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 14:57:38 +01:00

191 lines
5.2 KiB
Markdown

---
title: "AppServer"
description: "ASP.NET Core coordination server - SignalR hub, REST API, database, admin UI"
---
# AppServer (Copilot.AppServer)
The AppServer is a centralized coordination service that runs as an ASP.NET Core application (Windows Service capable). It does NOT handle video — only coordination between keyboards.
## Architecture
```mermaid
graph TB
subgraph "Copilot.AppServer.exe"
subgraph "SignalR Hub"
CamLock["Camera Lock<br/>Management"]
SeqMgr["Sequence<br/>Scheduler"]
CfgSync["Configuration<br/>Sync"]
ViewState["Viewer State<br/>Broadcasting"]
AlarmQ["Alarm Query<br/>Proxy"]
end
subgraph "REST API (v1)"
Updates["GET /api/v1/updates/{name}<br/>Auto-update manifest"]
CfgAPI["Configuration endpoints"]
end
subgraph "Blazor Admin UI"
AdminWWW["Web-based admin panel<br/>Configuration management"]
end
subgraph "Database"
SQLite["SQLite (copilot.db)<br/>• Camera locks<br/>• Lock history<br/>• Alarm cache"]
end
subgraph "External Integrations"
CameaClient["Camea API Client<br/>http://localhost:8081<br/>Alarm data source"]
end
end
K1["Keyboard 1"] -->|WSS| CamLock
K2["Keyboard 2"] -->|WSS| SeqMgr
K3["Keyboard 3"] -->|WSS| CfgSync
CamLock --> SQLite
AlarmQ --> CameaClient
AdminWWW --> CfgSync
```
## SignalR Hub Interface
The hub exposes methods grouped by function:
### Camera Locks
```
TryLockCamera(cameraId, copilotName, priority) → CameraLockResult
UnlockCamera(cameraId, copilotName)
RequestCameraLock(cameraId, copilotName, priority)
CameraLockConfirmTakeOver(cameraId, copilotName, confirm)
ResetCameraLockExpiration(cameraId, copilotName)
GetLockedCameraIds(copilotName) → IEnumerable<int>
```
### Camera Lock Notifications (Server → Client)
```
CameraLockNotify(notification) where notification has:
- NotificationType: Acquired | TakenOver | ConfirmTakeOver | Confirmed | Rejected | ExpireSoon | Unlocked
- CameraId: int
- CopilotName: string
```
### Sequences
```
Start(viewerId, sequenceId)
Stop(viewerId)
GetSequences(categoryId) → IEnumerable<SequenceMessage>
GetSequenceCategories() → IEnumerable<SequenceCategoryMessage>
GetRunningSequences() → IEnumerable<ViewerSequenceState>
```
### Sequence Notifications (Server → Client)
```
ViewerSequenceStateChanged(ViewerSequenceState)
```
### Configuration
```
GetConfigurationFile(filename) → ConfigurationFile
```
### Configuration Notifications (Server → Client)
```
ConfigurationFileChanged(ConfigurationFile)
```
### Alarms
```
GetCamerasWithAlarms() → HashSet<int>
GetAlarmsForCamera(cameraId, from, to) → IReadOnlyList<CameraAlarm>
```
## Database Schema (SQLite)
Managed via Entity Framework Core with code-first migrations:
```mermaid
erDiagram
CameraLock {
int CameraId PK
string OwnerName
string Priority
datetime ExpiresAt
datetime CreatedAt
}
CameraLockHistory {
int Id PK
int CameraId
string OwnerName
string Action
datetime Timestamp
}
AlarmCache {
int Id PK
int CameraId
int AlarmTypeId
string Name
datetime StartTime
datetime EndTime
}
```
## Lock Expiration System
```mermaid
graph TD
Lock["Lock Created<br/>(ExpiresAt = now + 5min)"] --> Timer["Expiration Timer"]
Timer -->|"T+4min<br/>(1min before expiry)"| Warn["Send ExpireSoon<br/>notification"]
Warn --> Reset{"PTZ Action?"}
Reset -->|Yes| ExtendLock["Reset ExpiresAt = now + 5min"]
ExtendLock --> Timer
Reset -->|No timeout| Expire["Send Unlocked<br/>notification"]
Expire --> Remove["Remove lock from DB"]
```
## Auto-Update System
The AppServer serves firmware and application updates:
```
GET /api/v1/updates/{copilotName}
→ Returns JSON array of available updates:
[
{
"Version": "1.0.706",
"Url": "https://copilot.test.d6.colsys.cz/updates/Copilot-1.0.706.zip",
"Changelog": "https://...",
"Mandatory": { "Value": true, "MinVersion": "1.0.700" },
"CheckSum": { "Value": "abc123...", "HashingAlgorithm": "SHA256" }
}
]
```
The WPF app uses `AutoUpdater.NET` to check on startup and apply updates.
## Deployment
```
Copilot.AppServer.exe
├── appsettings.json (main config)
├── configs/
│ ├── appsettings-copilot.json
│ ├── appsettings-camera-servers.json
│ ├── appsettings-monitor-wall.json
│ ├── appsettings-function-buttons.json
│ ├── appsettings-prepositions.json
│ ├── appsettings-sequences.json
│ └── appsettings-sequence-categories.json
├── copilot.db (SQLite database)
├── wwwroot/ (Blazor admin UI assets)
├── logs/
│ ├── copilot-appserver-YYYYMMDD.log
│ └── buffer/ (Elasticsearch buffer)
└── web.config (IIS hosting, if used)
```
Runs as:
- Windows Service (`Microsoft.Extensions.Hosting.WindowsServices`)
- Or standalone Kestrel server on HTTPS port 443
- Uses machine certificate store for TLS