Files
geutebruck/geutebruck-api/VSS_AND_SDK_FINDINGS.md
Administrator 14893e62a5 feat: Geutebruck GeViScope/GeViSoft Action Mapping System - MVP
This MVP release provides a complete full-stack solution for managing action mappings
in Geutebruck's GeViScope and GeViSoft video surveillance systems.

## Features

### Flutter Web Application (Port 8081)
- Modern, responsive UI for managing action mappings
- Action picker dialog with full parameter configuration
- Support for both GSC (GeViScope) and G-Core server actions
- Consistent UI for input and output actions with edit/delete capabilities
- Real-time action mapping creation, editing, and deletion
- Server categorization (GSC: prefix for GeViScope, G-Core: prefix for G-Core servers)

### FastAPI REST Backend (Port 8000)
- RESTful API for action mapping CRUD operations
- Action template service with comprehensive action catalog (247 actions)
- Server management (G-Core and GeViScope servers)
- Configuration tree reading and writing
- JWT authentication with role-based access control
- PostgreSQL database integration

### C# SDK Bridge (gRPC, Port 50051)
- Native integration with GeViSoft SDK (GeViProcAPINET_4_0.dll)
- Action mapping creation with correct binary format
- Support for GSC and G-Core action types
- Proper Camera parameter inclusion in action strings (fixes CrossSwitch bug)
- Action ID lookup table with server-specific action IDs
- Configuration reading/writing via SetupClient

## Bug Fixes
- **CrossSwitch Bug**: GSC and G-Core actions now correctly display camera/PTZ head parameters in GeViSet
- Action strings now include Camera parameter: `@ PanLeft (Comment: "", Camera: 101028)`
- Proper filter flags and VideoInput=0 for action mappings
- Correct action ID assignment (4198 for GSC, 9294 for G-Core PanLeft)

## Technical Stack
- **Frontend**: Flutter Web, Dart, Dio HTTP client
- **Backend**: Python FastAPI, PostgreSQL, Redis
- **SDK Bridge**: C# .NET 8.0, gRPC, GeViSoft SDK
- **Authentication**: JWT tokens
- **Configuration**: GeViSoft .set files (binary format)

## Credentials
- GeViSoft/GeViScope: username=sysadmin, password=masterkey
- Default admin: username=admin, password=admin123

## Deployment
All services run on localhost:
- Flutter Web: http://localhost:8081
- FastAPI: http://localhost:8000
- SDK Bridge gRPC: localhost:50051
- GeViServer: localhost (default port)

Generated with Claude Code (https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-31 18:10:54 +01:00

259 lines
7.3 KiB
Markdown

# Volume Shadow Copy & SDK Database Query Research
## Key Discoveries
### 1. **GeViDB.mdb is Proprietary "MDB1" Format**
**Evidence:**
- File header: `4D 44 42 31 00 10 00 00...` ("MDB1")
- NOT Microsoft Access format (which would start with "Standard Jet DB" or "Standard ACE DB")
- **Cannot be accessed via OLEDB** (Microsoft.ACE.OLEDB or Jet providers)
**Impact:**
Direct database file access is IMPOSSIBLE. Must use Geute brück SDK queries.
---
### 2. **Volume Shadow Copy (VSS) Successfully Copies Locked Database**
**Result:** ✅ VSS CAN copy the file while GeViServer is running
**Script:** `tools\Read-LockedDatabase.ps1`
**Process:**
1. Creates Windows shadow copy of C: drive
2. Creates symbolic link to shadow copy
3. Uses .NET FileStream to copy database (64 MB copied successfully)
4. **BUT:** The copied file is still in MDB1 format (proprietary)
**Conclusion:** VSS works for copying, but doesn't solve the format problem. We still can't read the proprietary database.
---
### 3. **Correct Approach: SDK Database Queries**
**Found example:** `C:\GEVISOFT\Examples\VS2010NET\CS_SimpleDatabaseClient`
**SDK Query Pattern:**
```csharp
// 1. Create query (returns handle)
GeViMessage dbAnswer;
myDB.SendQuery(new GeViDBQ_CreateAlarmQuery(), out dbAnswer);
GeViDBA_QueryHandle handle = (GeViDBA_QueryHandle)dbAnswer;
// 2. Get first record
myDB.SendQuery(new GeViDBQ_GetFirst(handle.sHandle), out dbAnswer);
// 3. Iterate through results
while (dbAnswer is GeViDBA_AlarmEntry alarmEntry) {
// Process alarm
string name = alarmEntry.sAlarmTypeName;
long pk = alarmEntry.sPK;
// Get next
myDB.SendQuery(new GeViDBQ_GetNext(handle.sHandle, pk), out dbAnswer);
}
// 4. Close query
myDB.SendQuery(new GeViDBQ_CloseQuery(handle.sHandle), out _);
```
**For Actions:**
```csharp
// Query all actions (0 = all, or specific alarm GlobalID)
myDB.SendQuery(new GeViDBQ_CreateActionQuery(0), out dbAnswer);
// ... same iteration pattern
```
---
## Implementation Status
### ✅ **Completed**
1. **C# SDK Database Query Implementation**
- File: `SDK/AlarmQueryService.cs`
- Methods:
- `QueryAllAlarmsAsync()` - Gets all alarms via SDK
- `QueryAllActionsAsync()` - Gets all actions via SDK
- `GetAllActionMappingsAsync()` - Matches alarms with actions
- **Compiles successfully** ✅
- **Services running** ✅
2. **VSS Research**
- Script created: `tools\Read-LockedDatabase.ps1`
- Tested successfully - can copy locked database
- Identified proprietary format issue
3. **MDB1 Format Investigation**
- Identified as Geutebruck proprietary format
- Confirmed SDK is the ONLY way to query it
### ⚠️ **Remaining Gap: Python API Not Calling SDK Bridge**
**Problem:** Python API service queries PostgreSQL (test data), NOT the SDK Bridge.
**Current Flow:**
```
API Request → Python FastAPI → PostgreSQL (test data) → Response
```
**Needed Flow:**
```
API Request → Python FastAPI → gRPC → C# SDK Bridge → GeViServer SDK → Response
```
**Missing Components:**
1. **Protobuf definition** for ActionMappings service (`.proto` file)
2. **gRPC service** implementation in C# SDK Bridge
3. **gRPC client** call in Python service
4. **Stub initialization** in `sdk_bridge_client.py`
---
## Files Modified/Created
**SDK Bridge (C#):**
-`SDK/AlarmQueryService.cs` - SDK database queries (COMPLETE)
-`SDK/ActionMappingHandler.cs` - Uses AlarmQueryService (COMPLETE)
- ⏸️ `Services/ActionMappingGrpcService.cs` - **NOT YET CREATED**
**Python API:**
- ⏸️ `services/action_mapping_service.py` - **Still using PostgreSQL**
- ⏸️ `clients/sdk_bridge_client.py` - **No action mappings stub**
**Protobuf:**
- ⏸️ `Protos/action_mapping.proto` - **NOT YET CREATED**
**Tools:**
-`tools/Read-LockedDatabase.ps1` - VSS script (COMPLETE)
-`tools/Check-DatabaseHeader.ps1` - Format checker (COMPLETE)
---
## Next Steps to Complete Integration
### Step 1: Create Protobuf Definition
**File:** `src/sdk-bridge/Protos/action_mapping.proto`
```protobuf
syntax = "proto3";
package action_mapping;
service ActionMappingService {
rpc GetActionMappings(GetActionMappingsRequest) returns (GetActionMappingsResponse);
}
message GetActionMappingsRequest {
bool enabled_only = 1;
}
message ActionMapping {
string id = 1;
string name = 2;
string description = 3;
string input_action = 4;
repeated string output_actions = 5;
bool enabled = 6;
}
message GetActionMappingsResponse {
repeated ActionMapping mappings = 1;
int32 total_count = 2;
int32 enabled_count = 3;
int32 disabled_count = 4;
}
```
### Step 2: Generate gRPC Code
```bash
# Build project (triggers proto code generation)
dotnet build GeViScopeBridge.csproj
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. action_mapping.proto
```
### Step 3: Implement gRPC Service (C#)
**File:** `Services/ActionMappingGrpcService.cs`
```csharp
public class ActionMappingGrpcService : ActionMappingService.ActionMappingServiceBase
{
private readonly ActionMappingHandler _handler;
public override async Task<GetActionMappingsResponse> GetActionMappings(
GetActionMappingsRequest request, ServerCallContext context)
{
var mappings = await _handler.EnumerateActionMappingsAsync(request.EnabledOnly);
return new GetActionMappingsResponse
{
Mappings = { mappings.Select(m => new ActionMapping
{
Id = m.Id,
Name = m.Name,
Description = m.Description,
InputAction = m.InputAction,
OutputActions = { m.OutputActions },
Enabled = m.Enabled
})},
TotalCount = mappings.Count,
EnabledCount = mappings.Count(m => m.Enabled),
DisabledCount = mappings.Count(m => !m.Enabled)
};
}
}
```
### Step 4: Update Python Service
**File:** `services/action_mapping_service.py`
```python
async def list_action_mappings(self, enabled_only=False, ...):
# Call SDK Bridge via gRPC instead of PostgreSQL
response = await sdk_bridge_client.get_action_mappings(enabled_only=enabled_only)
return ActionMappingListResponse(
mappings=[ActionMappingResponse(**m) for m in response.mappings],
total_count=response.total_count,
enabled_count=response.enabled_count,
disabled_count=response.disabled_count
)
```
---
## Testing the Solution
Once integration is complete:
```powershell
# 1. Restart services
.\restart-services.ps1
# 2. Test API endpoint
.\test-action-mappings.ps1
```
**Expected Result:** Live data from GeViServer database (not test data)
---
## Summary
| Component | Status | Notes |
|-----------|--------|-------|
| MDB1 Format Investigation | ✅ Complete | Proprietary format, SDK required |
| VSS Script | ✅ Complete | Works but doesn't solve format issue |
| C# SDK Queries | ✅ Complete | AlarmQueryService implemented |
| gRPC Protobuf | ⏸️ Pending | Need to create .proto file |
| C# gRPC Service | ⏸️ Pending | Need to expose SDK queries via gRPC |
| Python gRPC Client | ⏸️ Pending | Need to call SDK Bridge |
| End-to-End Test | ⏸️ Pending | Waiting for gRPC integration |
**Bottom Line:** The SDK database query approach is CORRECT and IMPLEMENTED in C#. We just need to expose it via gRPC so the Python API can call it instead of using PostgreSQL test data.