Compare commits
2 Commits
24a11cecdd
...
49b9fdfb81
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49b9fdfb81 | ||
|
|
cda42ebc6e |
204
SERVER_CRUD_IMPLEMENTATION.md
Normal file
204
SERVER_CRUD_IMPLEMENTATION.md
Normal file
@@ -0,0 +1,204 @@
|
||||
# Server CRUD Implementation
|
||||
|
||||
## Overview
|
||||
|
||||
Full CRUD (Create, Read, Update, Delete) implementation for GeViSoft G-Core server management via gRPC SDK Bridge and REST API.
|
||||
|
||||
## Critical Implementation Details
|
||||
|
||||
### Boolean Type Fix
|
||||
|
||||
**Issue**: Initial implementation used `int32` type for boolean fields (Enabled, DeactivateEcho, DeactivateLiveCheck), causing servers to be written but not recognized by GeViSet.
|
||||
|
||||
**Solution**: Changed to proper `bool` type (type code 1) instead of `int32` (type code 4).
|
||||
|
||||
**Affected Files**:
|
||||
- `src/sdk-bridge/GeViScopeBridge/Services/ConfigurationServiceImplementation.cs`
|
||||
- Lines 1062-1078: CreateServer method
|
||||
- Lines 1194-1200: UpdateServer method
|
||||
- Lines 1344-1383: UpdateOrAddChild helper (added bool handling)
|
||||
|
||||
### Field Order Requirements
|
||||
|
||||
Server configuration nodes must have fields in specific order:
|
||||
1. Alias (string)
|
||||
2. DeactivateEcho (bool)
|
||||
3. DeactivateLiveCheck (bool)
|
||||
4. Enabled (bool)
|
||||
5. Host (string)
|
||||
6. Password (string)
|
||||
7. User (string)
|
||||
|
||||
**Reference**: Working implementation in `C:\DEV\COPILOT_codex\geviset_parser.py` lines 389-404
|
||||
|
||||
### Auto-Increment Server IDs
|
||||
|
||||
**Implementation**: `server_manager.py` demonstrates proper ID management:
|
||||
- Reads existing servers from configuration
|
||||
- Finds highest numeric server ID
|
||||
- Increments by 1 for new server ID
|
||||
- Skips non-numeric IDs gracefully
|
||||
|
||||
```python
|
||||
def get_next_server_id(servers):
|
||||
numeric_ids = []
|
||||
for server in servers:
|
||||
try:
|
||||
numeric_ids.append(int(server['id']))
|
||||
except ValueError:
|
||||
pass
|
||||
if not numeric_ids:
|
||||
return "1"
|
||||
return str(max(numeric_ids) + 1)
|
||||
```
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### REST API (FastAPI)
|
||||
|
||||
**Base Path**: `/api/v1/configuration`
|
||||
|
||||
- `GET /servers` - List all G-Core servers
|
||||
- `GET /servers/{server_id}` - Get single server by ID
|
||||
- `POST /servers` - Create new server
|
||||
- `PUT /servers/{server_id}` - Update existing server
|
||||
- `DELETE /servers/{server_id}` - Delete server
|
||||
|
||||
**Implementation**: `src/api/routers/configuration.py` lines 278-460
|
||||
|
||||
### gRPC API
|
||||
|
||||
**Service**: `ConfigurationService`
|
||||
|
||||
Methods:
|
||||
- `CreateServer(CreateServerRequest)` → `ServerOperationResponse`
|
||||
- `UpdateServer(UpdateServerRequest)` → `ServerOperationResponse`
|
||||
- `DeleteServer(DeleteServerRequest)` → `ServerOperationResponse`
|
||||
- `ReadConfigurationTree()` → Configuration tree with all servers
|
||||
|
||||
**Implementation**: `src/sdk-bridge/GeViScopeBridge/Services/ConfigurationServiceImplementation.cs`
|
||||
|
||||
## Server Data Structure
|
||||
|
||||
```protobuf
|
||||
message ServerData {
|
||||
string id = 1; // Server ID (numeric string recommended)
|
||||
string alias = 2; // Display name
|
||||
string host = 3; // IP address or hostname
|
||||
string user = 4; // Username (default: "admin")
|
||||
string password = 5; // Password
|
||||
bool enabled = 6; // Enable/disable server
|
||||
bool deactivate_echo = 7; // Deactivate echo (default: false)
|
||||
bool deactivate_live_check = 8; // Deactivate live check (default: false)
|
||||
}
|
||||
```
|
||||
|
||||
## Test Scripts
|
||||
|
||||
### Production Scripts
|
||||
|
||||
1. **server_manager.py** - Complete server lifecycle management
|
||||
- Lists existing servers
|
||||
- Auto-increments IDs
|
||||
- Creates, deletes servers
|
||||
- Manages action mappings
|
||||
- Cleanup functionality
|
||||
|
||||
2. **cleanup_to_base.py** - Restore configuration to base state
|
||||
- Deletes test servers (2, 3)
|
||||
- Preserves original server (1)
|
||||
- Quick reset for testing
|
||||
|
||||
3. **add_claude_test_data.py** - Add test data with "Claude" prefix
|
||||
- Creates 3 servers: Claude Server Alpha/Beta/Gamma
|
||||
- Creates 2 action mappings
|
||||
- All identifiable by "Claude" prefix
|
||||
|
||||
4. **check_and_add_mapping.py** - Verify and add action mappings
|
||||
- Lists existing Claude mappings
|
||||
- Adds missing mappings
|
||||
- Ensures complete test data
|
||||
|
||||
### Legacy Test Scripts
|
||||
|
||||
- `test_server_creation.py` - Direct gRPC server creation test
|
||||
- `add_server_and_mapping.py` - Combined server and mapping creation
|
||||
|
||||
## Verification Process
|
||||
|
||||
### Testing Workflow
|
||||
|
||||
1. **Start Services**:
|
||||
```bash
|
||||
cd C:\GEVISOFT
|
||||
start GeViServer.exe console
|
||||
|
||||
cd C:\DEV\COPILOT\geutebruck-api\src\sdk-bridge\GeViScopeBridge\bin\Debug\net8.0
|
||||
start GeViScopeBridge.exe
|
||||
```
|
||||
|
||||
2. **Run Test Script**:
|
||||
```bash
|
||||
python server_manager.py
|
||||
```
|
||||
|
||||
3. **Stop Services** (required before GeViSet connection):
|
||||
```powershell
|
||||
Stop-Process -Name GeViScopeBridge -Force
|
||||
Stop-Process -Name python -Force
|
||||
Stop-Process -Name GeViServer -Force
|
||||
```
|
||||
|
||||
4. **Verify in GeViSet**:
|
||||
- Connect to GeViServer
|
||||
- Check Configuration → GeViGCoreServer
|
||||
- Verify servers appear with correct bool values
|
||||
|
||||
### Known Issues & Solutions
|
||||
|
||||
**Issue**: Port 50051 (gRPC) in use
|
||||
- **Solution**: Stop SDK Bridge process
|
||||
|
||||
**Issue**: SetupClient connection refused (Error 307)
|
||||
- **Cause**: GeViSet already connected (only one SetupPort client allowed)
|
||||
- **Solution**: Disconnect GeViSet, retry SetupClient
|
||||
|
||||
**Issue**: Servers created but not visible in GeViSet
|
||||
- **Root Cause**: Using int32 instead of bool type
|
||||
- **Solution**: Use proper bool type as documented above
|
||||
|
||||
## Action Mapping CRUD
|
||||
|
||||
Action mappings can also be managed via the same ConfigurationService.
|
||||
|
||||
**Endpoints**:
|
||||
- `GET /api/v1/configuration/action-mappings` - List all mappings
|
||||
- `GET /api/v1/configuration/action-mappings/{mapping_id}` - Get single mapping
|
||||
- `POST /api/v1/configuration/action-mappings` - Create mapping
|
||||
- `PUT /api/v1/configuration/action-mappings/{mapping_id}` - Update mapping
|
||||
- `DELETE /api/v1/configuration/action-mappings/{mapping_id}` - Delete mapping
|
||||
|
||||
**Note**: Mapping IDs are 1-based ordinal positions in the MappingRules list.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- GeViServer must be running
|
||||
- SDK Bridge requires GeViServer connection
|
||||
- REST API requires SDK Bridge on localhost:50051
|
||||
- GeViSet requires exclusive SetupPort (7703) access
|
||||
|
||||
## Success Metrics
|
||||
|
||||
✅ Servers persist correctly in GeViSoft configuration
|
||||
✅ Servers visible in GeViSet with correct boolean values
|
||||
✅ Auto-increment ID logic prevents conflicts
|
||||
✅ All CRUD operations functional via gRPC and REST
|
||||
✅ Action mappings create, read, update, delete working
|
||||
✅ Configuration changes survive GeViServer restart
|
||||
|
||||
## References
|
||||
|
||||
- Working Python parser: `C:\DEV\COPILOT_codex\geviset_parser.py`
|
||||
- SDK Bridge implementation: `src/sdk-bridge/GeViScopeBridge/Services/ConfigurationServiceImplementation.cs`
|
||||
- REST API: `src/api/routers/configuration.py`
|
||||
- Protocol definitions: `src/api/protos/configuration.proto`
|
||||
@@ -6,10 +6,12 @@ from typing import Optional, List
|
||||
import structlog
|
||||
from config import settings
|
||||
|
||||
# TODO: Import generated protobuf classes after running protoc
|
||||
# from protos import camera_pb2, camera_pb2_grpc
|
||||
# from protos import monitor_pb2, monitor_pb2_grpc
|
||||
# from protos import crossswitch_pb2, crossswitch_pb2_grpc
|
||||
# Import generated protobuf classes
|
||||
from protos import camera_pb2, camera_pb2_grpc
|
||||
from protos import monitor_pb2, monitor_pb2_grpc
|
||||
from protos import crossswitch_pb2, crossswitch_pb2_grpc
|
||||
from protos import action_mapping_pb2, action_mapping_pb2_grpc
|
||||
from protos import configuration_pb2, configuration_pb2_grpc
|
||||
|
||||
logger = structlog.get_logger()
|
||||
|
||||
@@ -18,10 +20,11 @@ class SDKBridgeClient:
|
||||
|
||||
def __init__(self):
|
||||
self._channel: Optional[grpc.aio.Channel] = None
|
||||
# TODO: Initialize stubs after protobuf generation
|
||||
# self._camera_stub = None
|
||||
# self._monitor_stub = None
|
||||
# self._crossswitch_stub = None
|
||||
self._camera_stub = None
|
||||
self._monitor_stub = None
|
||||
self._crossswitch_stub = None
|
||||
self._action_mapping_stub = None
|
||||
self._configuration_stub = None
|
||||
|
||||
async def connect(self):
|
||||
"""Initialize gRPC channel to SDK Bridge"""
|
||||
@@ -39,13 +42,12 @@ class SDKBridgeClient:
|
||||
]
|
||||
)
|
||||
|
||||
# TODO: Initialize service stubs after protobuf generation
|
||||
# self._camera_stub = camera_pb2_grpc.CameraServiceStub(self._channel)
|
||||
# self._monitor_stub = monitor_pb2_grpc.MonitorServiceStub(self._channel)
|
||||
# self._crossswitch_stub = crossswitch_pb2_grpc.CrossSwitchServiceStub(self._channel)
|
||||
|
||||
# Test connection with health check
|
||||
# await self.health_check()
|
||||
# Initialize service stubs
|
||||
self._camera_stub = camera_pb2_grpc.CameraServiceStub(self._channel)
|
||||
self._monitor_stub = monitor_pb2_grpc.MonitorServiceStub(self._channel)
|
||||
self._crossswitch_stub = crossswitch_pb2_grpc.CrossSwitchServiceStub(self._channel)
|
||||
self._action_mapping_stub = action_mapping_pb2_grpc.ActionMappingServiceStub(self._channel)
|
||||
self._configuration_stub = configuration_pb2_grpc.ConfigurationServiceStub(self._channel)
|
||||
|
||||
logger.info("sdk_bridge_connected")
|
||||
except Exception as e:
|
||||
@@ -82,21 +84,20 @@ class SDKBridgeClient:
|
||||
"""List all cameras from GeViServer"""
|
||||
try:
|
||||
logger.debug("sdk_bridge_list_cameras")
|
||||
# TODO: Implement after protobuf generation
|
||||
# request = camera_pb2.ListCamerasRequest()
|
||||
# response = await self._camera_stub.ListCameras(request, timeout=10.0)
|
||||
# return [
|
||||
# {
|
||||
# "id": camera.id,
|
||||
# "name": camera.name,
|
||||
# "description": camera.description,
|
||||
# "has_ptz": camera.has_ptz,
|
||||
# "has_video_sensor": camera.has_video_sensor,
|
||||
# "status": camera.status
|
||||
# }
|
||||
# for camera in response.cameras
|
||||
# ]
|
||||
return [] # Placeholder
|
||||
request = camera_pb2.ListCamerasRequest()
|
||||
response = await self._camera_stub.ListCameras(request, timeout=10.0)
|
||||
return [
|
||||
{
|
||||
"id": camera.id,
|
||||
"name": camera.name,
|
||||
"description": camera.description,
|
||||
"has_ptz": camera.has_ptz,
|
||||
"has_video_sensor": camera.has_video_sensor,
|
||||
"status": camera.status,
|
||||
"last_seen": None # TODO: Convert protobuf timestamp to datetime
|
||||
}
|
||||
for camera in response.cameras
|
||||
]
|
||||
except grpc.RpcError as e:
|
||||
logger.error("sdk_bridge_list_cameras_failed", error=str(e))
|
||||
raise
|
||||
@@ -127,21 +128,19 @@ class SDKBridgeClient:
|
||||
"""List all monitors from GeViServer"""
|
||||
try:
|
||||
logger.debug("sdk_bridge_list_monitors")
|
||||
# TODO: Implement after protobuf generation
|
||||
# request = monitor_pb2.ListMonitorsRequest()
|
||||
# response = await self._monitor_stub.ListMonitors(request, timeout=10.0)
|
||||
# return [
|
||||
# {
|
||||
# "id": monitor.id,
|
||||
# "name": monitor.name,
|
||||
# "description": monitor.description,
|
||||
# "is_active": monitor.is_active,
|
||||
# "current_camera_id": monitor.current_camera_id,
|
||||
# "status": monitor.status
|
||||
# }
|
||||
# for monitor in response.monitors
|
||||
# ]
|
||||
return [] # Placeholder
|
||||
request = monitor_pb2.ListMonitorsRequest()
|
||||
response = await self._monitor_stub.ListMonitors(request, timeout=10.0)
|
||||
return [
|
||||
{
|
||||
"id": monitor.id,
|
||||
"name": monitor.name,
|
||||
"description": monitor.description,
|
||||
"is_active": monitor.is_active,
|
||||
"current_camera_id": monitor.current_camera_id,
|
||||
"status": monitor.status
|
||||
}
|
||||
for monitor in response.monitors
|
||||
]
|
||||
except grpc.RpcError as e:
|
||||
logger.error("sdk_bridge_list_monitors_failed", error=str(e))
|
||||
raise
|
||||
@@ -150,20 +149,18 @@ class SDKBridgeClient:
|
||||
"""Execute cross-switch operation"""
|
||||
try:
|
||||
logger.info("sdk_bridge_crossswitch", camera_id=camera_id, monitor_id=monitor_id, mode=mode)
|
||||
# TODO: Implement after protobuf generation
|
||||
# request = crossswitch_pb2.CrossSwitchRequest(
|
||||
# camera_id=camera_id,
|
||||
# monitor_id=monitor_id,
|
||||
# mode=mode
|
||||
# )
|
||||
# response = await self._crossswitch_stub.ExecuteCrossSwitch(request, timeout=10.0)
|
||||
# return {
|
||||
# "success": response.success,
|
||||
# "message": response.message,
|
||||
# "camera_id": response.camera_id,
|
||||
# "monitor_id": response.monitor_id
|
||||
# }
|
||||
return {"success": True, "message": "Placeholder", "camera_id": camera_id, "monitor_id": monitor_id}
|
||||
request = crossswitch_pb2.CrossSwitchRequest(
|
||||
camera_id=camera_id,
|
||||
monitor_id=monitor_id,
|
||||
mode=mode
|
||||
)
|
||||
response = await self._crossswitch_stub.ExecuteCrossSwitch(request, timeout=10.0)
|
||||
return {
|
||||
"success": response.success,
|
||||
"message": response.message,
|
||||
"camera_id": response.camera_id,
|
||||
"monitor_id": response.monitor_id
|
||||
}
|
||||
except grpc.RpcError as e:
|
||||
logger.error("sdk_bridge_crossswitch_failed", error=str(e))
|
||||
raise
|
||||
@@ -172,15 +169,13 @@ class SDKBridgeClient:
|
||||
"""Clear monitor (stop video)"""
|
||||
try:
|
||||
logger.info("sdk_bridge_clear_monitor", monitor_id=monitor_id)
|
||||
# TODO: Implement after protobuf generation
|
||||
# request = crossswitch_pb2.ClearMonitorRequest(monitor_id=monitor_id)
|
||||
# response = await self._crossswitch_stub.ClearMonitor(request, timeout=10.0)
|
||||
# return {
|
||||
# "success": response.success,
|
||||
# "message": response.message,
|
||||
# "monitor_id": response.monitor_id
|
||||
# }
|
||||
return {"success": True, "message": "Placeholder", "monitor_id": monitor_id}
|
||||
request = crossswitch_pb2.ClearMonitorRequest(monitor_id=monitor_id)
|
||||
response = await self._crossswitch_stub.ClearMonitor(request, timeout=10.0)
|
||||
return {
|
||||
"success": response.success,
|
||||
"message": response.message,
|
||||
"monitor_id": response.monitor_id
|
||||
}
|
||||
except grpc.RpcError as e:
|
||||
logger.error("sdk_bridge_clear_monitor_failed", error=str(e))
|
||||
raise
|
||||
@@ -209,6 +204,451 @@ class SDKBridgeClient:
|
||||
logger.error("sdk_bridge_get_routing_state_failed", error=str(e))
|
||||
raise
|
||||
|
||||
async def get_action_mappings(self, enabled_only: bool = False) -> dict:
|
||||
"""Get action mappings from GeViServer via SDK Bridge"""
|
||||
try:
|
||||
logger.debug("sdk_bridge_get_action_mappings", enabled_only=enabled_only)
|
||||
request = action_mapping_pb2.GetActionMappingsRequest(enabled_only=enabled_only)
|
||||
response = await self._action_mapping_stub.GetActionMappings(request, timeout=30.0)
|
||||
|
||||
return {
|
||||
"mappings": [
|
||||
{
|
||||
"id": mapping.id,
|
||||
"name": mapping.name,
|
||||
"description": mapping.description,
|
||||
"input_action": mapping.input_action,
|
||||
"output_actions": list(mapping.output_actions),
|
||||
"enabled": mapping.enabled,
|
||||
"execution_count": mapping.execution_count,
|
||||
"last_executed": mapping.last_executed if mapping.last_executed else None,
|
||||
"created_at": mapping.created_at,
|
||||
"updated_at": mapping.updated_at
|
||||
}
|
||||
for mapping in response.mappings
|
||||
],
|
||||
"total_count": response.total_count,
|
||||
"enabled_count": response.enabled_count,
|
||||
"disabled_count": response.disabled_count
|
||||
}
|
||||
except grpc.RpcError as e:
|
||||
logger.error("sdk_bridge_get_action_mappings_failed", error=str(e))
|
||||
raise
|
||||
|
||||
async def read_configuration(self) -> dict:
|
||||
"""Read and parse configuration from GeViServer"""
|
||||
try:
|
||||
logger.debug("sdk_bridge_read_configuration")
|
||||
request = configuration_pb2.ReadConfigurationRequest()
|
||||
response = await self._configuration_stub.ReadConfiguration(request, timeout=30.0)
|
||||
|
||||
return {
|
||||
"success": response.success,
|
||||
"error_message": response.error_message if response.error_message else None,
|
||||
"file_size": response.file_size,
|
||||
"header": response.header,
|
||||
"nodes": [
|
||||
{
|
||||
"start_offset": node.start_offset,
|
||||
"end_offset": node.end_offset,
|
||||
"node_type": node.node_type,
|
||||
"name": node.name if node.name else None,
|
||||
"value": node.value if node.value else None,
|
||||
"value_type": node.value_type if node.value_type else None
|
||||
}
|
||||
for node in response.nodes
|
||||
],
|
||||
"statistics": {
|
||||
"total_nodes": response.statistics.total_nodes,
|
||||
"boolean_count": response.statistics.boolean_count,
|
||||
"integer_count": response.statistics.integer_count,
|
||||
"string_count": response.statistics.string_count,
|
||||
"property_count": response.statistics.property_count,
|
||||
"marker_count": response.statistics.marker_count,
|
||||
"rules_section_count": response.statistics.rules_section_count
|
||||
}
|
||||
}
|
||||
except grpc.RpcError as e:
|
||||
logger.error("sdk_bridge_read_configuration_failed", error=str(e))
|
||||
raise
|
||||
|
||||
async def export_configuration_json(self) -> dict:
|
||||
"""Export configuration as JSON"""
|
||||
try:
|
||||
logger.debug("sdk_bridge_export_configuration_json")
|
||||
request = configuration_pb2.ExportJsonRequest()
|
||||
response = await self._configuration_stub.ExportConfigurationJson(request, timeout=30.0)
|
||||
|
||||
return {
|
||||
"success": response.success,
|
||||
"error_message": response.error_message if response.error_message else None,
|
||||
"json_data": response.json_data,
|
||||
"json_size": response.json_size
|
||||
}
|
||||
except grpc.RpcError as e:
|
||||
logger.error("sdk_bridge_export_configuration_json_failed", error=str(e))
|
||||
raise
|
||||
|
||||
async def modify_configuration(self, modifications: List[dict]) -> dict:
|
||||
"""Modify configuration and write back to server"""
|
||||
try:
|
||||
logger.info("sdk_bridge_modify_configuration", count=len(modifications))
|
||||
request = configuration_pb2.ModifyConfigurationRequest()
|
||||
|
||||
for mod in modifications:
|
||||
modification = configuration_pb2.NodeModification(
|
||||
start_offset=mod["start_offset"],
|
||||
node_type=mod["node_type"],
|
||||
new_value=mod["new_value"]
|
||||
)
|
||||
request.modifications.append(modification)
|
||||
|
||||
response = await self._configuration_stub.ModifyConfiguration(request, timeout=60.0)
|
||||
|
||||
return {
|
||||
"success": response.success,
|
||||
"error_message": response.error_message if response.error_message else None,
|
||||
"modifications_applied": response.modifications_applied
|
||||
}
|
||||
except grpc.RpcError as e:
|
||||
logger.error("sdk_bridge_modify_configuration_failed", error=str(e))
|
||||
raise
|
||||
|
||||
async def import_configuration(self, json_data: str) -> dict:
|
||||
"""Import complete configuration from JSON and write to GeViServer"""
|
||||
try:
|
||||
logger.info("sdk_bridge_import_configuration", json_size=len(json_data))
|
||||
request = configuration_pb2.ImportConfigurationRequest(json_data=json_data)
|
||||
response = await self._configuration_stub.ImportConfiguration(request, timeout=60.0)
|
||||
|
||||
return {
|
||||
"success": response.success,
|
||||
"error_message": response.error_message if response.error_message else None,
|
||||
"bytes_written": response.bytes_written,
|
||||
"nodes_imported": response.nodes_imported
|
||||
}
|
||||
except grpc.RpcError as e:
|
||||
logger.error("sdk_bridge_import_configuration_failed", error=str(e))
|
||||
raise
|
||||
|
||||
async def read_action_mappings(self) -> dict:
|
||||
"""
|
||||
Read ONLY action mappings (Rules markers) from GeViServer
|
||||
Much faster than full configuration export - selective parsing
|
||||
Returns structured format with input_actions and output_actions with parameters
|
||||
"""
|
||||
try:
|
||||
logger.info("sdk_bridge_read_action_mappings")
|
||||
request = configuration_pb2.ReadActionMappingsRequest()
|
||||
response = await self._configuration_stub.ReadActionMappings(request, timeout=30.0)
|
||||
|
||||
# Convert protobuf response to dict with structured format
|
||||
mappings = []
|
||||
for mapping in response.mappings:
|
||||
# Convert input actions with parameters
|
||||
input_actions = []
|
||||
for action_def in mapping.input_actions:
|
||||
parameters = {}
|
||||
for param in action_def.parameters:
|
||||
parameters[param.name] = param.value
|
||||
|
||||
input_actions.append({
|
||||
"action": action_def.action,
|
||||
"parameters": parameters
|
||||
})
|
||||
|
||||
# Convert output actions with parameters
|
||||
output_actions = []
|
||||
for action_def in mapping.output_actions:
|
||||
parameters = {}
|
||||
for param in action_def.parameters:
|
||||
parameters[param.name] = param.value
|
||||
|
||||
output_actions.append({
|
||||
"action": action_def.action,
|
||||
"parameters": parameters
|
||||
})
|
||||
|
||||
mappings.append({
|
||||
"name": mapping.name,
|
||||
"input_actions": input_actions,
|
||||
"output_actions": output_actions,
|
||||
"start_offset": mapping.start_offset,
|
||||
"end_offset": mapping.end_offset,
|
||||
# Keep old format for backward compatibility
|
||||
"actions": list(mapping.actions)
|
||||
})
|
||||
|
||||
return {
|
||||
"success": response.success,
|
||||
"error_message": response.error_message if response.error_message else None,
|
||||
"mappings": mappings,
|
||||
"total_count": response.total_count
|
||||
}
|
||||
|
||||
except grpc.RpcError as e:
|
||||
logger.error("sdk_bridge_read_action_mappings_failed", error=str(e))
|
||||
raise
|
||||
|
||||
async def read_specific_markers(self, marker_names: List[str]) -> dict:
|
||||
"""
|
||||
Read specific configuration markers by name
|
||||
Extensible method for reading any configuration type
|
||||
"""
|
||||
try:
|
||||
logger.info("sdk_bridge_read_specific_markers", markers=marker_names)
|
||||
request = configuration_pb2.ReadSpecificMarkersRequest(marker_names=marker_names)
|
||||
response = await self._configuration_stub.ReadSpecificMarkers(request, timeout=30.0)
|
||||
|
||||
# Convert protobuf response to dict
|
||||
nodes = []
|
||||
for node in response.extracted_nodes:
|
||||
nodes.append({
|
||||
"start_offset": node.start_offset,
|
||||
"end_offset": node.end_offset,
|
||||
"node_type": node.node_type,
|
||||
"name": node.name,
|
||||
"value": node.value,
|
||||
"value_type": node.value_type
|
||||
})
|
||||
|
||||
return {
|
||||
"success": response.success,
|
||||
"error_message": response.error_message if response.error_message else None,
|
||||
"file_size": response.file_size,
|
||||
"requested_markers": list(response.requested_markers),
|
||||
"extracted_nodes": nodes,
|
||||
"markers_found": response.markers_found
|
||||
}
|
||||
|
||||
except grpc.RpcError as e:
|
||||
logger.error("sdk_bridge_read_specific_markers_failed", error=str(e))
|
||||
raise
|
||||
|
||||
async def create_action_mapping(self, mapping_data: dict) -> dict:
|
||||
"""
|
||||
Create a new action mapping
|
||||
|
||||
Args:
|
||||
mapping_data: Dict with name, input_actions, output_actions
|
||||
|
||||
Returns:
|
||||
Dict with success status and created mapping
|
||||
"""
|
||||
try:
|
||||
logger.info("sdk_bridge_create_action_mapping", name=mapping_data.get("name"))
|
||||
|
||||
# Build protobuf request
|
||||
mapping_input = configuration_pb2.ActionMappingInput(
|
||||
name=mapping_data.get("name", "")
|
||||
)
|
||||
|
||||
# Add output actions
|
||||
for action_data in mapping_data.get("output_actions", []):
|
||||
action_def = configuration_pb2.ActionDefinition(action=action_data["action"])
|
||||
|
||||
# Add parameters
|
||||
for param_name, param_value in action_data.get("parameters", {}).items():
|
||||
action_def.parameters.add(name=param_name, value=str(param_value))
|
||||
|
||||
mapping_input.output_actions.append(action_def)
|
||||
|
||||
request = configuration_pb2.CreateActionMappingRequest(mapping=mapping_input)
|
||||
response = await self._configuration_stub.CreateActionMapping(request, timeout=60.0)
|
||||
|
||||
# Convert response
|
||||
result = {
|
||||
"success": response.success,
|
||||
"error_message": response.error_message if response.error_message else None,
|
||||
"message": response.message
|
||||
}
|
||||
|
||||
if response.mapping:
|
||||
result["mapping"] = {
|
||||
"id": len([]), # ID will be assigned by the system
|
||||
"name": response.mapping.name,
|
||||
"offset": response.mapping.start_offset,
|
||||
"output_actions": []
|
||||
}
|
||||
|
||||
for action_def in response.mapping.output_actions:
|
||||
result["mapping"]["output_actions"].append({
|
||||
"action": action_def.action,
|
||||
"parameters": {p.name: p.value for p in action_def.parameters}
|
||||
})
|
||||
|
||||
return result
|
||||
|
||||
except grpc.RpcError as e:
|
||||
logger.error("sdk_bridge_create_action_mapping_failed", error=str(e))
|
||||
raise
|
||||
|
||||
async def update_action_mapping(self, mapping_id: int, mapping_data: dict) -> dict:
|
||||
"""
|
||||
Update an existing action mapping
|
||||
|
||||
Args:
|
||||
mapping_id: 1-based ID of mapping to update
|
||||
mapping_data: Dict with updated fields (name, input_actions, output_actions)
|
||||
|
||||
Returns:
|
||||
Dict with success status and updated mapping
|
||||
"""
|
||||
try:
|
||||
logger.info("sdk_bridge_update_action_mapping", mapping_id=mapping_id)
|
||||
|
||||
# Build protobuf request
|
||||
mapping_input = configuration_pb2.ActionMappingInput()
|
||||
|
||||
if "name" in mapping_data:
|
||||
mapping_input.name = mapping_data["name"]
|
||||
|
||||
# Add output actions if provided
|
||||
if "output_actions" in mapping_data:
|
||||
for action_data in mapping_data["output_actions"]:
|
||||
action_def = configuration_pb2.ActionDefinition(action=action_data["action"])
|
||||
|
||||
# Add parameters
|
||||
for param_name, param_value in action_data.get("parameters", {}).items():
|
||||
action_def.parameters.add(name=param_name, value=str(param_value))
|
||||
|
||||
mapping_input.output_actions.append(action_def)
|
||||
|
||||
request = configuration_pb2.UpdateActionMappingRequest(
|
||||
mapping_id=mapping_id,
|
||||
mapping=mapping_input
|
||||
)
|
||||
response = await self._configuration_stub.UpdateActionMapping(request, timeout=60.0)
|
||||
|
||||
# Convert response
|
||||
result = {
|
||||
"success": response.success,
|
||||
"error_message": response.error_message if response.error_message else None,
|
||||
"message": response.message
|
||||
}
|
||||
|
||||
if response.mapping:
|
||||
result["mapping"] = {
|
||||
"id": mapping_id,
|
||||
"name": response.mapping.name,
|
||||
"offset": response.mapping.start_offset,
|
||||
"output_actions": []
|
||||
}
|
||||
|
||||
for action_def in response.mapping.output_actions:
|
||||
result["mapping"]["output_actions"].append({
|
||||
"action": action_def.action,
|
||||
"parameters": {p.name: p.value for p in action_def.parameters}
|
||||
})
|
||||
|
||||
return result
|
||||
|
||||
except grpc.RpcError as e:
|
||||
logger.error("sdk_bridge_update_action_mapping_failed", error=str(e))
|
||||
raise
|
||||
|
||||
async def delete_action_mapping(self, mapping_id: int) -> dict:
|
||||
"""
|
||||
Delete an action mapping by ID
|
||||
|
||||
Args:
|
||||
mapping_id: 1-based ID of mapping to delete
|
||||
|
||||
Returns:
|
||||
Dict with success status and message
|
||||
"""
|
||||
try:
|
||||
logger.info("sdk_bridge_delete_action_mapping", mapping_id=mapping_id)
|
||||
|
||||
request = configuration_pb2.DeleteActionMappingRequest(mapping_id=mapping_id)
|
||||
response = await self._configuration_stub.DeleteActionMapping(request, timeout=60.0)
|
||||
|
||||
return {
|
||||
"success": response.success,
|
||||
"error_message": response.error_message if response.error_message else None,
|
||||
"message": response.message
|
||||
}
|
||||
|
||||
except grpc.RpcError as e:
|
||||
logger.error("sdk_bridge_delete_action_mapping_failed", error=str(e))
|
||||
raise
|
||||
|
||||
async def read_configuration_tree(self) -> dict:
|
||||
"""
|
||||
Read configuration as hierarchical folder tree (RECOMMENDED)
|
||||
|
||||
Returns:
|
||||
Dict with tree structure
|
||||
"""
|
||||
try:
|
||||
logger.info("sdk_bridge_read_configuration_tree")
|
||||
|
||||
request = configuration_pb2.ReadConfigurationTreeRequest()
|
||||
response = await self._configuration_stub.ReadConfigurationTree(request, timeout=30.0)
|
||||
|
||||
if not response.success:
|
||||
return {
|
||||
"success": False,
|
||||
"error_message": response.error_message
|
||||
}
|
||||
|
||||
# Convert protobuf TreeNode to dict
|
||||
def convert_tree_node(node):
|
||||
result = {
|
||||
"type": node.type,
|
||||
"name": node.name
|
||||
}
|
||||
|
||||
# Add value based on type
|
||||
if node.type == "string":
|
||||
result["value"] = node.string_value
|
||||
elif node.type in ("bool", "byte", "int16", "int32", "int64"):
|
||||
result["value"] = node.int_value
|
||||
|
||||
# Add children recursively
|
||||
if node.type == "folder" and len(node.children) > 0:
|
||||
result["children"] = [convert_tree_node(child) for child in node.children]
|
||||
|
||||
return result
|
||||
|
||||
tree_dict = convert_tree_node(response.root) if response.root else None
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"tree": tree_dict,
|
||||
"total_nodes": response.total_nodes
|
||||
}
|
||||
|
||||
except grpc.RpcError as e:
|
||||
logger.error("sdk_bridge_read_configuration_tree_failed", error=str(e))
|
||||
raise
|
||||
|
||||
async def write_configuration_tree(self, tree: dict) -> dict:
|
||||
"""
|
||||
Write modified configuration tree back to GeViServer
|
||||
|
||||
Args:
|
||||
tree: Modified tree structure (dict)
|
||||
|
||||
Returns:
|
||||
Dict with success status and write statistics
|
||||
"""
|
||||
try:
|
||||
import json
|
||||
logger.info("sdk_bridge_write_configuration_tree")
|
||||
|
||||
# Convert tree to JSON string
|
||||
json_data = json.dumps(tree, indent=2)
|
||||
|
||||
# Use import_configuration to write the tree
|
||||
result = await self.import_configuration(json_data)
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error("sdk_bridge_write_configuration_tree_failed", error=str(e))
|
||||
raise
|
||||
|
||||
# Global SDK Bridge client instance
|
||||
sdk_bridge_client = SDKBridgeClient()
|
||||
|
||||
|
||||
1
src/api/protos/__init__.py
Normal file
1
src/api/protos/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
"""Generated protobuf modules"""
|
||||
42
src/api/protos/action_mapping.proto
Normal file
42
src/api/protos/action_mapping.proto
Normal file
@@ -0,0 +1,42 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package action_mapping;
|
||||
|
||||
option csharp_namespace = "GeViScopeBridge.Protos";
|
||||
|
||||
service ActionMappingService {
|
||||
rpc GetActionMappings(GetActionMappingsRequest) returns (GetActionMappingsResponse);
|
||||
rpc GetActionMapping(GetActionMappingRequest) returns (ActionMappingResponse);
|
||||
}
|
||||
|
||||
message GetActionMappingsRequest {
|
||||
bool enabled_only = 1;
|
||||
}
|
||||
|
||||
message GetActionMappingRequest {
|
||||
string id = 1;
|
||||
}
|
||||
|
||||
message ActionMapping {
|
||||
string id = 1;
|
||||
string name = 2;
|
||||
string description = 3;
|
||||
string input_action = 4;
|
||||
repeated string output_actions = 5;
|
||||
bool enabled = 6;
|
||||
int32 execution_count = 7;
|
||||
string last_executed = 8; // ISO 8601 datetime string
|
||||
string created_at = 9; // ISO 8601 datetime string
|
||||
string updated_at = 10; // ISO 8601 datetime string
|
||||
}
|
||||
|
||||
message ActionMappingResponse {
|
||||
ActionMapping mapping = 1;
|
||||
}
|
||||
|
||||
message GetActionMappingsResponse {
|
||||
repeated ActionMapping mappings = 1;
|
||||
int32 total_count = 2;
|
||||
int32 enabled_count = 3;
|
||||
int32 disabled_count = 4;
|
||||
}
|
||||
37
src/api/protos/action_mapping_pb2.py
Normal file
37
src/api/protos/action_mapping_pb2.py
Normal file
@@ -0,0 +1,37 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: action_mapping.proto
|
||||
# Protobuf Python Version: 4.25.0
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x14\x61\x63tion_mapping.proto\x12\x0e\x61\x63tion_mapping\"0\n\x18GetActionMappingsRequest\x12\x14\n\x0c\x65nabled_only\x18\x01 \x01(\x08\"%\n\x17GetActionMappingRequest\x12\n\n\x02id\x18\x01 \x01(\t\"\xd5\x01\n\rActionMapping\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x03 \x01(\t\x12\x14\n\x0cinput_action\x18\x04 \x01(\t\x12\x16\n\x0eoutput_actions\x18\x05 \x03(\t\x12\x0f\n\x07\x65nabled\x18\x06 \x01(\x08\x12\x17\n\x0f\x65xecution_count\x18\x07 \x01(\x05\x12\x15\n\rlast_executed\x18\x08 \x01(\t\x12\x12\n\ncreated_at\x18\t \x01(\t\x12\x12\n\nupdated_at\x18\n \x01(\t\"G\n\x15\x41\x63tionMappingResponse\x12.\n\x07mapping\x18\x01 \x01(\x0b\x32\x1d.action_mapping.ActionMapping\"\x90\x01\n\x19GetActionMappingsResponse\x12/\n\x08mappings\x18\x01 \x03(\x0b\x32\x1d.action_mapping.ActionMapping\x12\x13\n\x0btotal_count\x18\x02 \x01(\x05\x12\x15\n\renabled_count\x18\x03 \x01(\x05\x12\x16\n\x0e\x64isabled_count\x18\x04 \x01(\x05\x32\xe4\x01\n\x14\x41\x63tionMappingService\x12h\n\x11GetActionMappings\x12(.action_mapping.GetActionMappingsRequest\x1a).action_mapping.GetActionMappingsResponse\x12\x62\n\x10GetActionMapping\x12\'.action_mapping.GetActionMappingRequest\x1a%.action_mapping.ActionMappingResponseB\x19\xaa\x02\x16GeViScopeBridge.Protosb\x06proto3')
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'action_mapping_pb2', _globals)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
_globals['DESCRIPTOR']._options = None
|
||||
_globals['DESCRIPTOR']._serialized_options = b'\252\002\026GeViScopeBridge.Protos'
|
||||
_globals['_GETACTIONMAPPINGSREQUEST']._serialized_start=40
|
||||
_globals['_GETACTIONMAPPINGSREQUEST']._serialized_end=88
|
||||
_globals['_GETACTIONMAPPINGREQUEST']._serialized_start=90
|
||||
_globals['_GETACTIONMAPPINGREQUEST']._serialized_end=127
|
||||
_globals['_ACTIONMAPPING']._serialized_start=130
|
||||
_globals['_ACTIONMAPPING']._serialized_end=343
|
||||
_globals['_ACTIONMAPPINGRESPONSE']._serialized_start=345
|
||||
_globals['_ACTIONMAPPINGRESPONSE']._serialized_end=416
|
||||
_globals['_GETACTIONMAPPINGSRESPONSE']._serialized_start=419
|
||||
_globals['_GETACTIONMAPPINGSRESPONSE']._serialized_end=563
|
||||
_globals['_ACTIONMAPPINGSERVICE']._serialized_start=566
|
||||
_globals['_ACTIONMAPPINGSERVICE']._serialized_end=794
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
60
src/api/protos/action_mapping_pb2.pyi
Normal file
60
src/api/protos/action_mapping_pb2.pyi
Normal file
@@ -0,0 +1,60 @@
|
||||
from google.protobuf.internal import containers as _containers
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union
|
||||
|
||||
DESCRIPTOR: _descriptor.FileDescriptor
|
||||
|
||||
class GetActionMappingsRequest(_message.Message):
|
||||
__slots__ = ("enabled_only",)
|
||||
ENABLED_ONLY_FIELD_NUMBER: _ClassVar[int]
|
||||
enabled_only: bool
|
||||
def __init__(self, enabled_only: bool = ...) -> None: ...
|
||||
|
||||
class GetActionMappingRequest(_message.Message):
|
||||
__slots__ = ("id",)
|
||||
ID_FIELD_NUMBER: _ClassVar[int]
|
||||
id: str
|
||||
def __init__(self, id: _Optional[str] = ...) -> None: ...
|
||||
|
||||
class ActionMapping(_message.Message):
|
||||
__slots__ = ("id", "name", "description", "input_action", "output_actions", "enabled", "execution_count", "last_executed", "created_at", "updated_at")
|
||||
ID_FIELD_NUMBER: _ClassVar[int]
|
||||
NAME_FIELD_NUMBER: _ClassVar[int]
|
||||
DESCRIPTION_FIELD_NUMBER: _ClassVar[int]
|
||||
INPUT_ACTION_FIELD_NUMBER: _ClassVar[int]
|
||||
OUTPUT_ACTIONS_FIELD_NUMBER: _ClassVar[int]
|
||||
ENABLED_FIELD_NUMBER: _ClassVar[int]
|
||||
EXECUTION_COUNT_FIELD_NUMBER: _ClassVar[int]
|
||||
LAST_EXECUTED_FIELD_NUMBER: _ClassVar[int]
|
||||
CREATED_AT_FIELD_NUMBER: _ClassVar[int]
|
||||
UPDATED_AT_FIELD_NUMBER: _ClassVar[int]
|
||||
id: str
|
||||
name: str
|
||||
description: str
|
||||
input_action: str
|
||||
output_actions: _containers.RepeatedScalarFieldContainer[str]
|
||||
enabled: bool
|
||||
execution_count: int
|
||||
last_executed: str
|
||||
created_at: str
|
||||
updated_at: str
|
||||
def __init__(self, id: _Optional[str] = ..., name: _Optional[str] = ..., description: _Optional[str] = ..., input_action: _Optional[str] = ..., output_actions: _Optional[_Iterable[str]] = ..., enabled: bool = ..., execution_count: _Optional[int] = ..., last_executed: _Optional[str] = ..., created_at: _Optional[str] = ..., updated_at: _Optional[str] = ...) -> None: ...
|
||||
|
||||
class ActionMappingResponse(_message.Message):
|
||||
__slots__ = ("mapping",)
|
||||
MAPPING_FIELD_NUMBER: _ClassVar[int]
|
||||
mapping: ActionMapping
|
||||
def __init__(self, mapping: _Optional[_Union[ActionMapping, _Mapping]] = ...) -> None: ...
|
||||
|
||||
class GetActionMappingsResponse(_message.Message):
|
||||
__slots__ = ("mappings", "total_count", "enabled_count", "disabled_count")
|
||||
MAPPINGS_FIELD_NUMBER: _ClassVar[int]
|
||||
TOTAL_COUNT_FIELD_NUMBER: _ClassVar[int]
|
||||
ENABLED_COUNT_FIELD_NUMBER: _ClassVar[int]
|
||||
DISABLED_COUNT_FIELD_NUMBER: _ClassVar[int]
|
||||
mappings: _containers.RepeatedCompositeFieldContainer[ActionMapping]
|
||||
total_count: int
|
||||
enabled_count: int
|
||||
disabled_count: int
|
||||
def __init__(self, mappings: _Optional[_Iterable[_Union[ActionMapping, _Mapping]]] = ..., total_count: _Optional[int] = ..., enabled_count: _Optional[int] = ..., disabled_count: _Optional[int] = ...) -> None: ...
|
||||
99
src/api/protos/action_mapping_pb2_grpc.py
Normal file
99
src/api/protos/action_mapping_pb2_grpc.py
Normal file
@@ -0,0 +1,99 @@
|
||||
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
|
||||
"""Client and server classes corresponding to protobuf-defined services."""
|
||||
import grpc
|
||||
|
||||
import action_mapping_pb2 as action__mapping__pb2
|
||||
|
||||
|
||||
class ActionMappingServiceStub(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
def __init__(self, channel):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
channel: A grpc.Channel.
|
||||
"""
|
||||
self.GetActionMappings = channel.unary_unary(
|
||||
'/action_mapping.ActionMappingService/GetActionMappings',
|
||||
request_serializer=action__mapping__pb2.GetActionMappingsRequest.SerializeToString,
|
||||
response_deserializer=action__mapping__pb2.GetActionMappingsResponse.FromString,
|
||||
)
|
||||
self.GetActionMapping = channel.unary_unary(
|
||||
'/action_mapping.ActionMappingService/GetActionMapping',
|
||||
request_serializer=action__mapping__pb2.GetActionMappingRequest.SerializeToString,
|
||||
response_deserializer=action__mapping__pb2.ActionMappingResponse.FromString,
|
||||
)
|
||||
|
||||
|
||||
class ActionMappingServiceServicer(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
def GetActionMappings(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def GetActionMapping(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
|
||||
def add_ActionMappingServiceServicer_to_server(servicer, server):
|
||||
rpc_method_handlers = {
|
||||
'GetActionMappings': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetActionMappings,
|
||||
request_deserializer=action__mapping__pb2.GetActionMappingsRequest.FromString,
|
||||
response_serializer=action__mapping__pb2.GetActionMappingsResponse.SerializeToString,
|
||||
),
|
||||
'GetActionMapping': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetActionMapping,
|
||||
request_deserializer=action__mapping__pb2.GetActionMappingRequest.FromString,
|
||||
response_serializer=action__mapping__pb2.ActionMappingResponse.SerializeToString,
|
||||
),
|
||||
}
|
||||
generic_handler = grpc.method_handlers_generic_handler(
|
||||
'action_mapping.ActionMappingService', rpc_method_handlers)
|
||||
server.add_generic_rpc_handlers((generic_handler,))
|
||||
|
||||
|
||||
# This class is part of an EXPERIMENTAL API.
|
||||
class ActionMappingService(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
@staticmethod
|
||||
def GetActionMappings(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/action_mapping.ActionMappingService/GetActionMappings',
|
||||
action__mapping__pb2.GetActionMappingsRequest.SerializeToString,
|
||||
action__mapping__pb2.GetActionMappingsResponse.FromString,
|
||||
options, channel_credentials,
|
||||
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def GetActionMapping(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/action_mapping.ActionMappingService/GetActionMapping',
|
||||
action__mapping__pb2.GetActionMappingRequest.SerializeToString,
|
||||
action__mapping__pb2.ActionMappingResponse.FromString,
|
||||
options, channel_credentials,
|
||||
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
36
src/api/protos/camera_pb2.py
Normal file
36
src/api/protos/camera_pb2.py
Normal file
@@ -0,0 +1,36 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: camera.proto
|
||||
# Protobuf Python Version: 4.25.0
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
from protos import common_pb2 as common__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0c\x63\x61mera.proto\x12\x0fgeviscopebridge\x1a\x0c\x63ommon.proto\"\x14\n\x12ListCamerasRequest\"X\n\x13ListCamerasResponse\x12,\n\x07\x63\x61meras\x18\x01 \x03(\x0b\x32\x1b.geviscopebridge.CameraInfo\x12\x13\n\x0btotal_count\x18\x02 \x01(\x05\"%\n\x10GetCameraRequest\x12\x11\n\tcamera_id\x18\x01 \x01(\x05\"\xa5\x01\n\nCameraInfo\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x03 \x01(\t\x12\x0f\n\x07has_ptz\x18\x04 \x01(\x08\x12\x18\n\x10has_video_sensor\x18\x05 \x01(\x08\x12\x0e\n\x06status\x18\x06 \x01(\t\x12-\n\tlast_seen\x18\x07 \x01(\x0b\x32\x1a.geviscopebridge.Timestamp2\xb6\x01\n\rCameraService\x12X\n\x0bListCameras\x12#.geviscopebridge.ListCamerasRequest\x1a$.geviscopebridge.ListCamerasResponse\x12K\n\tGetCamera\x12!.geviscopebridge.GetCameraRequest\x1a\x1b.geviscopebridge.CameraInfoB\x19\xaa\x02\x16GeViScopeBridge.Protosb\x06proto3')
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'camera_pb2', _globals)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
_globals['DESCRIPTOR']._options = None
|
||||
_globals['DESCRIPTOR']._serialized_options = b'\252\002\026GeViScopeBridge.Protos'
|
||||
_globals['_LISTCAMERASREQUEST']._serialized_start=47
|
||||
_globals['_LISTCAMERASREQUEST']._serialized_end=67
|
||||
_globals['_LISTCAMERASRESPONSE']._serialized_start=69
|
||||
_globals['_LISTCAMERASRESPONSE']._serialized_end=157
|
||||
_globals['_GETCAMERAREQUEST']._serialized_start=159
|
||||
_globals['_GETCAMERAREQUEST']._serialized_end=196
|
||||
_globals['_CAMERAINFO']._serialized_start=199
|
||||
_globals['_CAMERAINFO']._serialized_end=364
|
||||
_globals['_CAMERASERVICE']._serialized_start=367
|
||||
_globals['_CAMERASERVICE']._serialized_end=549
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
0
src/api/protos/camera_pb2_grpc.py
Normal file
0
src/api/protos/camera_pb2_grpc.py
Normal file
33
src/api/protos/common_pb2.py
Normal file
33
src/api/protos/common_pb2.py
Normal file
@@ -0,0 +1,33 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: common.proto
|
||||
# Protobuf Python Version: 4.25.0
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0c\x63ommon.proto\x12\x0fgeviscopebridge\"\x07\n\x05\x45mpty\">\n\x06Status\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x12\n\nerror_code\x18\x03 \x01(\x05\"+\n\tTimestamp\x12\x0f\n\x07seconds\x18\x01 \x01(\x03\x12\r\n\x05nanos\x18\x02 \x01(\x05\"N\n\x0c\x45rrorDetails\x12\x15\n\rerror_message\x18\x01 \x01(\t\x12\x12\n\nerror_code\x18\x02 \x01(\x05\x12\x13\n\x0bstack_trace\x18\x03 \x01(\tB\x19\xaa\x02\x16GeViScopeBridge.Protosb\x06proto3')
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'common_pb2', _globals)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
_globals['DESCRIPTOR']._options = None
|
||||
_globals['DESCRIPTOR']._serialized_options = b'\252\002\026GeViScopeBridge.Protos'
|
||||
_globals['_EMPTY']._serialized_start=33
|
||||
_globals['_EMPTY']._serialized_end=40
|
||||
_globals['_STATUS']._serialized_start=42
|
||||
_globals['_STATUS']._serialized_end=104
|
||||
_globals['_TIMESTAMP']._serialized_start=106
|
||||
_globals['_TIMESTAMP']._serialized_end=149
|
||||
_globals['_ERRORDETAILS']._serialized_start=151
|
||||
_globals['_ERRORDETAILS']._serialized_end=229
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
0
src/api/protos/common_pb2_grpc.py
Normal file
0
src/api/protos/common_pb2_grpc.py
Normal file
298
src/api/protos/configuration.proto
Normal file
298
src/api/protos/configuration.proto
Normal file
@@ -0,0 +1,298 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package configuration;
|
||||
|
||||
option csharp_namespace = "GeViScopeBridge.Protos";
|
||||
|
||||
service ConfigurationService {
|
||||
// Read and parse complete configuration from GeViServer
|
||||
rpc ReadConfiguration(ReadConfigurationRequest) returns (ConfigurationResponse);
|
||||
|
||||
// Export configuration as JSON string
|
||||
rpc ExportConfigurationJson(ExportJsonRequest) returns (JsonExportResponse);
|
||||
|
||||
// Modify configuration values and write back to server
|
||||
rpc ModifyConfiguration(ModifyConfigurationRequest) returns (ModifyConfigurationResponse);
|
||||
|
||||
// Import complete configuration from JSON and write to GeViServer
|
||||
rpc ImportConfiguration(ImportConfigurationRequest) returns (ImportConfigurationResponse);
|
||||
|
||||
// SELECTIVE/TARGETED READ METHODS (Fast, lightweight)
|
||||
|
||||
// Read ONLY action mappings (Rules markers) - optimized for speed
|
||||
rpc ReadActionMappings(ReadActionMappingsRequest) returns (ActionMappingsResponse);
|
||||
|
||||
// Read specific markers by name - extensible for future config types
|
||||
rpc ReadSpecificMarkers(ReadSpecificMarkersRequest) returns (SelectiveConfigResponse);
|
||||
|
||||
// ACTION MAPPING WRITE METHODS
|
||||
|
||||
// Create a new action mapping
|
||||
rpc CreateActionMapping(CreateActionMappingRequest) returns (ActionMappingOperationResponse);
|
||||
|
||||
// Update an existing action mapping by ID
|
||||
rpc UpdateActionMapping(UpdateActionMappingRequest) returns (ActionMappingOperationResponse);
|
||||
|
||||
// Delete an action mapping by ID
|
||||
rpc DeleteActionMapping(DeleteActionMappingRequest) returns (ActionMappingOperationResponse);
|
||||
|
||||
// SERVER CONFIGURATION WRITE METHODS (G-CORE SERVERS)
|
||||
|
||||
// Create a new G-core server
|
||||
rpc CreateServer(CreateServerRequest) returns (ServerOperationResponse);
|
||||
|
||||
// Update an existing G-core server
|
||||
rpc UpdateServer(UpdateServerRequest) returns (ServerOperationResponse);
|
||||
|
||||
// Delete a G-core server
|
||||
rpc DeleteServer(DeleteServerRequest) returns (ServerOperationResponse);
|
||||
|
||||
// TREE FORMAT (RECOMMENDED)
|
||||
|
||||
// Read configuration as hierarchical folder tree - much more readable than flat format
|
||||
rpc ReadConfigurationTree(ReadConfigurationTreeRequest) returns (ConfigurationTreeResponse);
|
||||
|
||||
// REGISTRY EXPLORATION METHODS
|
||||
|
||||
// List top-level registry nodes
|
||||
rpc ListRegistryNodes(ListRegistryNodesRequest) returns (RegistryNodesResponse);
|
||||
|
||||
// Get details about a specific registry node
|
||||
rpc GetRegistryNodeDetails(GetRegistryNodeDetailsRequest) returns (RegistryNodeDetailsResponse);
|
||||
|
||||
// Search for action mapping paths in registry
|
||||
rpc SearchActionMappingPaths(SearchActionMappingPathsRequest) returns (ActionMappingPathsResponse);
|
||||
}
|
||||
|
||||
message ReadConfigurationRequest {
|
||||
// Empty - uses connection from setup client
|
||||
}
|
||||
|
||||
message ConfigurationStatistics {
|
||||
int32 total_nodes = 1;
|
||||
int32 boolean_count = 2;
|
||||
int32 integer_count = 3;
|
||||
int32 string_count = 4;
|
||||
int32 property_count = 5;
|
||||
int32 marker_count = 6;
|
||||
int32 rules_section_count = 7;
|
||||
}
|
||||
|
||||
message ConfigNode {
|
||||
int32 start_offset = 1;
|
||||
int32 end_offset = 2;
|
||||
string node_type = 3; // "boolean", "integer", "string", "property", "marker"
|
||||
string name = 4;
|
||||
string value = 5; // Serialized as string
|
||||
string value_type = 6;
|
||||
}
|
||||
|
||||
message ConfigurationResponse {
|
||||
bool success = 1;
|
||||
string error_message = 2;
|
||||
int32 file_size = 3;
|
||||
string header = 4;
|
||||
repeated ConfigNode nodes = 5;
|
||||
ConfigurationStatistics statistics = 6;
|
||||
}
|
||||
|
||||
message ExportJsonRequest {
|
||||
// Empty - exports current configuration
|
||||
}
|
||||
|
||||
message JsonExportResponse {
|
||||
bool success = 1;
|
||||
string error_message = 2;
|
||||
string json_data = 3;
|
||||
int32 json_size = 4;
|
||||
}
|
||||
|
||||
message NodeModification {
|
||||
int32 start_offset = 1;
|
||||
string node_type = 2; // "boolean", "integer", "string"
|
||||
string new_value = 3; // Serialized as string
|
||||
}
|
||||
|
||||
message ModifyConfigurationRequest {
|
||||
repeated NodeModification modifications = 1;
|
||||
}
|
||||
|
||||
message ModifyConfigurationResponse {
|
||||
bool success = 1;
|
||||
string error_message = 2;
|
||||
int32 modifications_applied = 3;
|
||||
}
|
||||
|
||||
message ImportConfigurationRequest {
|
||||
string json_data = 1; // Complete configuration as JSON string
|
||||
}
|
||||
|
||||
message ImportConfigurationResponse {
|
||||
bool success = 1;
|
||||
string error_message = 2;
|
||||
int32 bytes_written = 3;
|
||||
int32 nodes_imported = 4;
|
||||
}
|
||||
|
||||
// ========== SELECTIVE READ MESSAGES ==========
|
||||
|
||||
message ReadActionMappingsRequest {
|
||||
// Empty - reads action mappings from current configuration
|
||||
}
|
||||
|
||||
message ActionParameter {
|
||||
string name = 1; // Parameter name (e.g., "VideoInput", "G-core alias")
|
||||
string value = 2; // Parameter value (e.g., "101027", "gscope-cdu-3")
|
||||
}
|
||||
|
||||
message ActionDefinition {
|
||||
string action = 1; // Action name (e.g., "CrossSwitch C_101027 -> M")
|
||||
repeated ActionParameter parameters = 2; // Named parameters
|
||||
}
|
||||
|
||||
message ConfigActionMapping {
|
||||
string name = 1; // Mapping name (e.g., "CrossSwitch C_101027 -> M")
|
||||
repeated ActionDefinition input_actions = 2; // Trigger/condition actions
|
||||
repeated ActionDefinition output_actions = 3; // Response actions
|
||||
int32 start_offset = 4;
|
||||
int32 end_offset = 5;
|
||||
|
||||
// Deprecated - kept for backward compatibility
|
||||
repeated string actions = 6; // List of action strings (old format)
|
||||
}
|
||||
|
||||
message ActionMappingsResponse {
|
||||
bool success = 1;
|
||||
string error_message = 2;
|
||||
repeated ConfigActionMapping mappings = 3;
|
||||
int32 total_count = 4;
|
||||
}
|
||||
|
||||
message ReadSpecificMarkersRequest {
|
||||
repeated string marker_names = 1; // Names of markers to extract (e.g., "Rules", "Camera")
|
||||
}
|
||||
|
||||
message SelectiveConfigResponse {
|
||||
bool success = 1;
|
||||
string error_message = 2;
|
||||
int32 file_size = 3;
|
||||
repeated string requested_markers = 4;
|
||||
repeated ConfigNode extracted_nodes = 5;
|
||||
int32 markers_found = 6;
|
||||
}
|
||||
|
||||
// ========== ACTION MAPPING WRITE MESSAGES ==========
|
||||
|
||||
message ActionMappingInput {
|
||||
string name = 1; // Mapping caption (required for GeViSet display)
|
||||
repeated ActionDefinition input_actions = 2; // Trigger actions
|
||||
repeated ActionDefinition output_actions = 3; // Response actions (required)
|
||||
int32 video_input = 4; // Video input ID (optional, but recommended for GeViSet display)
|
||||
}
|
||||
|
||||
message CreateActionMappingRequest {
|
||||
ActionMappingInput mapping = 1;
|
||||
}
|
||||
|
||||
message UpdateActionMappingRequest {
|
||||
int32 mapping_id = 1; // 1-based ID of mapping to update
|
||||
ActionMappingInput mapping = 2; // New data (fields can be partial)
|
||||
}
|
||||
|
||||
message DeleteActionMappingRequest {
|
||||
int32 mapping_id = 1; // 1-based ID of mapping to delete
|
||||
}
|
||||
|
||||
message ActionMappingOperationResponse {
|
||||
bool success = 1;
|
||||
string error_message = 2;
|
||||
ConfigActionMapping mapping = 3; // Created/updated mapping (null for delete)
|
||||
string message = 4; // Success/info message
|
||||
}
|
||||
|
||||
// REGISTRY EXPLORATION MESSAGES
|
||||
|
||||
message ListRegistryNodesRequest {
|
||||
// Empty - lists top-level nodes
|
||||
}
|
||||
|
||||
message RegistryNodesResponse {
|
||||
bool success = 1;
|
||||
repeated string node_paths = 2;
|
||||
string error_message = 3;
|
||||
}
|
||||
|
||||
message GetRegistryNodeDetailsRequest {
|
||||
string node_path = 1;
|
||||
}
|
||||
|
||||
message RegistryNodeDetailsResponse {
|
||||
bool success = 1;
|
||||
string details = 2;
|
||||
string error_message = 3;
|
||||
}
|
||||
|
||||
message SearchActionMappingPathsRequest {
|
||||
// Empty - searches for action mapping related nodes
|
||||
}
|
||||
|
||||
message ActionMappingPathsResponse {
|
||||
bool success = 1;
|
||||
repeated string paths = 2;
|
||||
string error_message = 3;
|
||||
}
|
||||
|
||||
// ========== SERVER CRUD MESSAGES ==========
|
||||
|
||||
message ServerData {
|
||||
string id = 1; // Server ID (folder name in GeViGCoreServer)
|
||||
string alias = 2; // Alias (display name)
|
||||
string host = 3; // Host/IP address
|
||||
string user = 4; // Username
|
||||
string password = 5; // Password
|
||||
bool enabled = 6; // Enabled flag
|
||||
bool deactivate_echo = 7; // DeactivateEcho flag
|
||||
bool deactivate_live_check = 8; // DeactivateLiveCheck flag
|
||||
}
|
||||
|
||||
message CreateServerRequest {
|
||||
ServerData server = 1;
|
||||
}
|
||||
|
||||
message UpdateServerRequest {
|
||||
string server_id = 1; // ID of server to update
|
||||
ServerData server = 2; // New server data (fields can be partial)
|
||||
}
|
||||
|
||||
message DeleteServerRequest {
|
||||
string server_id = 1; // ID of server to delete
|
||||
}
|
||||
|
||||
message ServerOperationResponse {
|
||||
bool success = 1;
|
||||
string error_message = 2;
|
||||
ServerData server = 3; // Created/updated server (null for delete)
|
||||
string message = 4; // Success/info message
|
||||
int32 bytes_written = 5; // Size of configuration written
|
||||
}
|
||||
|
||||
// ========== TREE FORMAT MESSAGES ==========
|
||||
|
||||
message ReadConfigurationTreeRequest {
|
||||
// Empty - reads entire configuration as tree
|
||||
}
|
||||
|
||||
message TreeNode {
|
||||
string type = 1; // "folder", "bool", "byte", "int16", "int32", "int64", "string"
|
||||
string name = 2; // Node name
|
||||
int64 int_value = 3; // For integer/bool types
|
||||
string string_value = 4; // For string types
|
||||
repeated TreeNode children = 5; // For folders (hierarchical structure)
|
||||
}
|
||||
|
||||
message ConfigurationTreeResponse {
|
||||
bool success = 1;
|
||||
string error_message = 2;
|
||||
TreeNode root = 3; // Root folder node containing entire configuration tree
|
||||
int32 total_nodes = 4; // Total node count (all levels)
|
||||
}
|
||||
101
src/api/protos/configuration_pb2.py
Normal file
101
src/api/protos/configuration_pb2.py
Normal file
File diff suppressed because one or more lines are too long
362
src/api/protos/configuration_pb2.pyi
Normal file
362
src/api/protos/configuration_pb2.pyi
Normal file
@@ -0,0 +1,362 @@
|
||||
from google.protobuf.internal import containers as _containers
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union
|
||||
|
||||
DESCRIPTOR: _descriptor.FileDescriptor
|
||||
|
||||
class ReadConfigurationRequest(_message.Message):
|
||||
__slots__ = ()
|
||||
def __init__(self) -> None: ...
|
||||
|
||||
class ConfigurationStatistics(_message.Message):
|
||||
__slots__ = ("total_nodes", "boolean_count", "integer_count", "string_count", "property_count", "marker_count", "rules_section_count")
|
||||
TOTAL_NODES_FIELD_NUMBER: _ClassVar[int]
|
||||
BOOLEAN_COUNT_FIELD_NUMBER: _ClassVar[int]
|
||||
INTEGER_COUNT_FIELD_NUMBER: _ClassVar[int]
|
||||
STRING_COUNT_FIELD_NUMBER: _ClassVar[int]
|
||||
PROPERTY_COUNT_FIELD_NUMBER: _ClassVar[int]
|
||||
MARKER_COUNT_FIELD_NUMBER: _ClassVar[int]
|
||||
RULES_SECTION_COUNT_FIELD_NUMBER: _ClassVar[int]
|
||||
total_nodes: int
|
||||
boolean_count: int
|
||||
integer_count: int
|
||||
string_count: int
|
||||
property_count: int
|
||||
marker_count: int
|
||||
rules_section_count: int
|
||||
def __init__(self, total_nodes: _Optional[int] = ..., boolean_count: _Optional[int] = ..., integer_count: _Optional[int] = ..., string_count: _Optional[int] = ..., property_count: _Optional[int] = ..., marker_count: _Optional[int] = ..., rules_section_count: _Optional[int] = ...) -> None: ...
|
||||
|
||||
class ConfigNode(_message.Message):
|
||||
__slots__ = ("start_offset", "end_offset", "node_type", "name", "value", "value_type")
|
||||
START_OFFSET_FIELD_NUMBER: _ClassVar[int]
|
||||
END_OFFSET_FIELD_NUMBER: _ClassVar[int]
|
||||
NODE_TYPE_FIELD_NUMBER: _ClassVar[int]
|
||||
NAME_FIELD_NUMBER: _ClassVar[int]
|
||||
VALUE_FIELD_NUMBER: _ClassVar[int]
|
||||
VALUE_TYPE_FIELD_NUMBER: _ClassVar[int]
|
||||
start_offset: int
|
||||
end_offset: int
|
||||
node_type: str
|
||||
name: str
|
||||
value: str
|
||||
value_type: str
|
||||
def __init__(self, start_offset: _Optional[int] = ..., end_offset: _Optional[int] = ..., node_type: _Optional[str] = ..., name: _Optional[str] = ..., value: _Optional[str] = ..., value_type: _Optional[str] = ...) -> None: ...
|
||||
|
||||
class ConfigurationResponse(_message.Message):
|
||||
__slots__ = ("success", "error_message", "file_size", "header", "nodes", "statistics")
|
||||
SUCCESS_FIELD_NUMBER: _ClassVar[int]
|
||||
ERROR_MESSAGE_FIELD_NUMBER: _ClassVar[int]
|
||||
FILE_SIZE_FIELD_NUMBER: _ClassVar[int]
|
||||
HEADER_FIELD_NUMBER: _ClassVar[int]
|
||||
NODES_FIELD_NUMBER: _ClassVar[int]
|
||||
STATISTICS_FIELD_NUMBER: _ClassVar[int]
|
||||
success: bool
|
||||
error_message: str
|
||||
file_size: int
|
||||
header: str
|
||||
nodes: _containers.RepeatedCompositeFieldContainer[ConfigNode]
|
||||
statistics: ConfigurationStatistics
|
||||
def __init__(self, success: bool = ..., error_message: _Optional[str] = ..., file_size: _Optional[int] = ..., header: _Optional[str] = ..., nodes: _Optional[_Iterable[_Union[ConfigNode, _Mapping]]] = ..., statistics: _Optional[_Union[ConfigurationStatistics, _Mapping]] = ...) -> None: ...
|
||||
|
||||
class ExportJsonRequest(_message.Message):
|
||||
__slots__ = ()
|
||||
def __init__(self) -> None: ...
|
||||
|
||||
class JsonExportResponse(_message.Message):
|
||||
__slots__ = ("success", "error_message", "json_data", "json_size")
|
||||
SUCCESS_FIELD_NUMBER: _ClassVar[int]
|
||||
ERROR_MESSAGE_FIELD_NUMBER: _ClassVar[int]
|
||||
JSON_DATA_FIELD_NUMBER: _ClassVar[int]
|
||||
JSON_SIZE_FIELD_NUMBER: _ClassVar[int]
|
||||
success: bool
|
||||
error_message: str
|
||||
json_data: str
|
||||
json_size: int
|
||||
def __init__(self, success: bool = ..., error_message: _Optional[str] = ..., json_data: _Optional[str] = ..., json_size: _Optional[int] = ...) -> None: ...
|
||||
|
||||
class NodeModification(_message.Message):
|
||||
__slots__ = ("start_offset", "node_type", "new_value")
|
||||
START_OFFSET_FIELD_NUMBER: _ClassVar[int]
|
||||
NODE_TYPE_FIELD_NUMBER: _ClassVar[int]
|
||||
NEW_VALUE_FIELD_NUMBER: _ClassVar[int]
|
||||
start_offset: int
|
||||
node_type: str
|
||||
new_value: str
|
||||
def __init__(self, start_offset: _Optional[int] = ..., node_type: _Optional[str] = ..., new_value: _Optional[str] = ...) -> None: ...
|
||||
|
||||
class ModifyConfigurationRequest(_message.Message):
|
||||
__slots__ = ("modifications",)
|
||||
MODIFICATIONS_FIELD_NUMBER: _ClassVar[int]
|
||||
modifications: _containers.RepeatedCompositeFieldContainer[NodeModification]
|
||||
def __init__(self, modifications: _Optional[_Iterable[_Union[NodeModification, _Mapping]]] = ...) -> None: ...
|
||||
|
||||
class ModifyConfigurationResponse(_message.Message):
|
||||
__slots__ = ("success", "error_message", "modifications_applied")
|
||||
SUCCESS_FIELD_NUMBER: _ClassVar[int]
|
||||
ERROR_MESSAGE_FIELD_NUMBER: _ClassVar[int]
|
||||
MODIFICATIONS_APPLIED_FIELD_NUMBER: _ClassVar[int]
|
||||
success: bool
|
||||
error_message: str
|
||||
modifications_applied: int
|
||||
def __init__(self, success: bool = ..., error_message: _Optional[str] = ..., modifications_applied: _Optional[int] = ...) -> None: ...
|
||||
|
||||
class ImportConfigurationRequest(_message.Message):
|
||||
__slots__ = ("json_data",)
|
||||
JSON_DATA_FIELD_NUMBER: _ClassVar[int]
|
||||
json_data: str
|
||||
def __init__(self, json_data: _Optional[str] = ...) -> None: ...
|
||||
|
||||
class ImportConfigurationResponse(_message.Message):
|
||||
__slots__ = ("success", "error_message", "bytes_written", "nodes_imported")
|
||||
SUCCESS_FIELD_NUMBER: _ClassVar[int]
|
||||
ERROR_MESSAGE_FIELD_NUMBER: _ClassVar[int]
|
||||
BYTES_WRITTEN_FIELD_NUMBER: _ClassVar[int]
|
||||
NODES_IMPORTED_FIELD_NUMBER: _ClassVar[int]
|
||||
success: bool
|
||||
error_message: str
|
||||
bytes_written: int
|
||||
nodes_imported: int
|
||||
def __init__(self, success: bool = ..., error_message: _Optional[str] = ..., bytes_written: _Optional[int] = ..., nodes_imported: _Optional[int] = ...) -> None: ...
|
||||
|
||||
class ReadActionMappingsRequest(_message.Message):
|
||||
__slots__ = ()
|
||||
def __init__(self) -> None: ...
|
||||
|
||||
class ActionParameter(_message.Message):
|
||||
__slots__ = ("name", "value")
|
||||
NAME_FIELD_NUMBER: _ClassVar[int]
|
||||
VALUE_FIELD_NUMBER: _ClassVar[int]
|
||||
name: str
|
||||
value: str
|
||||
def __init__(self, name: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
|
||||
|
||||
class ActionDefinition(_message.Message):
|
||||
__slots__ = ("action", "parameters")
|
||||
ACTION_FIELD_NUMBER: _ClassVar[int]
|
||||
PARAMETERS_FIELD_NUMBER: _ClassVar[int]
|
||||
action: str
|
||||
parameters: _containers.RepeatedCompositeFieldContainer[ActionParameter]
|
||||
def __init__(self, action: _Optional[str] = ..., parameters: _Optional[_Iterable[_Union[ActionParameter, _Mapping]]] = ...) -> None: ...
|
||||
|
||||
class ConfigActionMapping(_message.Message):
|
||||
__slots__ = ("name", "input_actions", "output_actions", "start_offset", "end_offset", "actions")
|
||||
NAME_FIELD_NUMBER: _ClassVar[int]
|
||||
INPUT_ACTIONS_FIELD_NUMBER: _ClassVar[int]
|
||||
OUTPUT_ACTIONS_FIELD_NUMBER: _ClassVar[int]
|
||||
START_OFFSET_FIELD_NUMBER: _ClassVar[int]
|
||||
END_OFFSET_FIELD_NUMBER: _ClassVar[int]
|
||||
ACTIONS_FIELD_NUMBER: _ClassVar[int]
|
||||
name: str
|
||||
input_actions: _containers.RepeatedCompositeFieldContainer[ActionDefinition]
|
||||
output_actions: _containers.RepeatedCompositeFieldContainer[ActionDefinition]
|
||||
start_offset: int
|
||||
end_offset: int
|
||||
actions: _containers.RepeatedScalarFieldContainer[str]
|
||||
def __init__(self, name: _Optional[str] = ..., input_actions: _Optional[_Iterable[_Union[ActionDefinition, _Mapping]]] = ..., output_actions: _Optional[_Iterable[_Union[ActionDefinition, _Mapping]]] = ..., start_offset: _Optional[int] = ..., end_offset: _Optional[int] = ..., actions: _Optional[_Iterable[str]] = ...) -> None: ...
|
||||
|
||||
class ActionMappingsResponse(_message.Message):
|
||||
__slots__ = ("success", "error_message", "mappings", "total_count")
|
||||
SUCCESS_FIELD_NUMBER: _ClassVar[int]
|
||||
ERROR_MESSAGE_FIELD_NUMBER: _ClassVar[int]
|
||||
MAPPINGS_FIELD_NUMBER: _ClassVar[int]
|
||||
TOTAL_COUNT_FIELD_NUMBER: _ClassVar[int]
|
||||
success: bool
|
||||
error_message: str
|
||||
mappings: _containers.RepeatedCompositeFieldContainer[ConfigActionMapping]
|
||||
total_count: int
|
||||
def __init__(self, success: bool = ..., error_message: _Optional[str] = ..., mappings: _Optional[_Iterable[_Union[ConfigActionMapping, _Mapping]]] = ..., total_count: _Optional[int] = ...) -> None: ...
|
||||
|
||||
class ReadSpecificMarkersRequest(_message.Message):
|
||||
__slots__ = ("marker_names",)
|
||||
MARKER_NAMES_FIELD_NUMBER: _ClassVar[int]
|
||||
marker_names: _containers.RepeatedScalarFieldContainer[str]
|
||||
def __init__(self, marker_names: _Optional[_Iterable[str]] = ...) -> None: ...
|
||||
|
||||
class SelectiveConfigResponse(_message.Message):
|
||||
__slots__ = ("success", "error_message", "file_size", "requested_markers", "extracted_nodes", "markers_found")
|
||||
SUCCESS_FIELD_NUMBER: _ClassVar[int]
|
||||
ERROR_MESSAGE_FIELD_NUMBER: _ClassVar[int]
|
||||
FILE_SIZE_FIELD_NUMBER: _ClassVar[int]
|
||||
REQUESTED_MARKERS_FIELD_NUMBER: _ClassVar[int]
|
||||
EXTRACTED_NODES_FIELD_NUMBER: _ClassVar[int]
|
||||
MARKERS_FOUND_FIELD_NUMBER: _ClassVar[int]
|
||||
success: bool
|
||||
error_message: str
|
||||
file_size: int
|
||||
requested_markers: _containers.RepeatedScalarFieldContainer[str]
|
||||
extracted_nodes: _containers.RepeatedCompositeFieldContainer[ConfigNode]
|
||||
markers_found: int
|
||||
def __init__(self, success: bool = ..., error_message: _Optional[str] = ..., file_size: _Optional[int] = ..., requested_markers: _Optional[_Iterable[str]] = ..., extracted_nodes: _Optional[_Iterable[_Union[ConfigNode, _Mapping]]] = ..., markers_found: _Optional[int] = ...) -> None: ...
|
||||
|
||||
class ActionMappingInput(_message.Message):
|
||||
__slots__ = ("name", "input_actions", "output_actions", "video_input")
|
||||
NAME_FIELD_NUMBER: _ClassVar[int]
|
||||
INPUT_ACTIONS_FIELD_NUMBER: _ClassVar[int]
|
||||
OUTPUT_ACTIONS_FIELD_NUMBER: _ClassVar[int]
|
||||
VIDEO_INPUT_FIELD_NUMBER: _ClassVar[int]
|
||||
name: str
|
||||
input_actions: _containers.RepeatedCompositeFieldContainer[ActionDefinition]
|
||||
output_actions: _containers.RepeatedCompositeFieldContainer[ActionDefinition]
|
||||
video_input: int
|
||||
def __init__(self, name: _Optional[str] = ..., input_actions: _Optional[_Iterable[_Union[ActionDefinition, _Mapping]]] = ..., output_actions: _Optional[_Iterable[_Union[ActionDefinition, _Mapping]]] = ..., video_input: _Optional[int] = ...) -> None: ...
|
||||
|
||||
class CreateActionMappingRequest(_message.Message):
|
||||
__slots__ = ("mapping",)
|
||||
MAPPING_FIELD_NUMBER: _ClassVar[int]
|
||||
mapping: ActionMappingInput
|
||||
def __init__(self, mapping: _Optional[_Union[ActionMappingInput, _Mapping]] = ...) -> None: ...
|
||||
|
||||
class UpdateActionMappingRequest(_message.Message):
|
||||
__slots__ = ("mapping_id", "mapping")
|
||||
MAPPING_ID_FIELD_NUMBER: _ClassVar[int]
|
||||
MAPPING_FIELD_NUMBER: _ClassVar[int]
|
||||
mapping_id: int
|
||||
mapping: ActionMappingInput
|
||||
def __init__(self, mapping_id: _Optional[int] = ..., mapping: _Optional[_Union[ActionMappingInput, _Mapping]] = ...) -> None: ...
|
||||
|
||||
class DeleteActionMappingRequest(_message.Message):
|
||||
__slots__ = ("mapping_id",)
|
||||
MAPPING_ID_FIELD_NUMBER: _ClassVar[int]
|
||||
mapping_id: int
|
||||
def __init__(self, mapping_id: _Optional[int] = ...) -> None: ...
|
||||
|
||||
class ActionMappingOperationResponse(_message.Message):
|
||||
__slots__ = ("success", "error_message", "mapping", "message")
|
||||
SUCCESS_FIELD_NUMBER: _ClassVar[int]
|
||||
ERROR_MESSAGE_FIELD_NUMBER: _ClassVar[int]
|
||||
MAPPING_FIELD_NUMBER: _ClassVar[int]
|
||||
MESSAGE_FIELD_NUMBER: _ClassVar[int]
|
||||
success: bool
|
||||
error_message: str
|
||||
mapping: ConfigActionMapping
|
||||
message: str
|
||||
def __init__(self, success: bool = ..., error_message: _Optional[str] = ..., mapping: _Optional[_Union[ConfigActionMapping, _Mapping]] = ..., message: _Optional[str] = ...) -> None: ...
|
||||
|
||||
class ListRegistryNodesRequest(_message.Message):
|
||||
__slots__ = ()
|
||||
def __init__(self) -> None: ...
|
||||
|
||||
class RegistryNodesResponse(_message.Message):
|
||||
__slots__ = ("success", "node_paths", "error_message")
|
||||
SUCCESS_FIELD_NUMBER: _ClassVar[int]
|
||||
NODE_PATHS_FIELD_NUMBER: _ClassVar[int]
|
||||
ERROR_MESSAGE_FIELD_NUMBER: _ClassVar[int]
|
||||
success: bool
|
||||
node_paths: _containers.RepeatedScalarFieldContainer[str]
|
||||
error_message: str
|
||||
def __init__(self, success: bool = ..., node_paths: _Optional[_Iterable[str]] = ..., error_message: _Optional[str] = ...) -> None: ...
|
||||
|
||||
class GetRegistryNodeDetailsRequest(_message.Message):
|
||||
__slots__ = ("node_path",)
|
||||
NODE_PATH_FIELD_NUMBER: _ClassVar[int]
|
||||
node_path: str
|
||||
def __init__(self, node_path: _Optional[str] = ...) -> None: ...
|
||||
|
||||
class RegistryNodeDetailsResponse(_message.Message):
|
||||
__slots__ = ("success", "details", "error_message")
|
||||
SUCCESS_FIELD_NUMBER: _ClassVar[int]
|
||||
DETAILS_FIELD_NUMBER: _ClassVar[int]
|
||||
ERROR_MESSAGE_FIELD_NUMBER: _ClassVar[int]
|
||||
success: bool
|
||||
details: str
|
||||
error_message: str
|
||||
def __init__(self, success: bool = ..., details: _Optional[str] = ..., error_message: _Optional[str] = ...) -> None: ...
|
||||
|
||||
class SearchActionMappingPathsRequest(_message.Message):
|
||||
__slots__ = ()
|
||||
def __init__(self) -> None: ...
|
||||
|
||||
class ActionMappingPathsResponse(_message.Message):
|
||||
__slots__ = ("success", "paths", "error_message")
|
||||
SUCCESS_FIELD_NUMBER: _ClassVar[int]
|
||||
PATHS_FIELD_NUMBER: _ClassVar[int]
|
||||
ERROR_MESSAGE_FIELD_NUMBER: _ClassVar[int]
|
||||
success: bool
|
||||
paths: _containers.RepeatedScalarFieldContainer[str]
|
||||
error_message: str
|
||||
def __init__(self, success: bool = ..., paths: _Optional[_Iterable[str]] = ..., error_message: _Optional[str] = ...) -> None: ...
|
||||
|
||||
class ServerData(_message.Message):
|
||||
__slots__ = ("id", "alias", "host", "user", "password", "enabled", "deactivate_echo", "deactivate_live_check")
|
||||
ID_FIELD_NUMBER: _ClassVar[int]
|
||||
ALIAS_FIELD_NUMBER: _ClassVar[int]
|
||||
HOST_FIELD_NUMBER: _ClassVar[int]
|
||||
USER_FIELD_NUMBER: _ClassVar[int]
|
||||
PASSWORD_FIELD_NUMBER: _ClassVar[int]
|
||||
ENABLED_FIELD_NUMBER: _ClassVar[int]
|
||||
DEACTIVATE_ECHO_FIELD_NUMBER: _ClassVar[int]
|
||||
DEACTIVATE_LIVE_CHECK_FIELD_NUMBER: _ClassVar[int]
|
||||
id: str
|
||||
alias: str
|
||||
host: str
|
||||
user: str
|
||||
password: str
|
||||
enabled: bool
|
||||
deactivate_echo: bool
|
||||
deactivate_live_check: bool
|
||||
def __init__(self, id: _Optional[str] = ..., alias: _Optional[str] = ..., host: _Optional[str] = ..., user: _Optional[str] = ..., password: _Optional[str] = ..., enabled: bool = ..., deactivate_echo: bool = ..., deactivate_live_check: bool = ...) -> None: ...
|
||||
|
||||
class CreateServerRequest(_message.Message):
|
||||
__slots__ = ("server",)
|
||||
SERVER_FIELD_NUMBER: _ClassVar[int]
|
||||
server: ServerData
|
||||
def __init__(self, server: _Optional[_Union[ServerData, _Mapping]] = ...) -> None: ...
|
||||
|
||||
class UpdateServerRequest(_message.Message):
|
||||
__slots__ = ("server_id", "server")
|
||||
SERVER_ID_FIELD_NUMBER: _ClassVar[int]
|
||||
SERVER_FIELD_NUMBER: _ClassVar[int]
|
||||
server_id: str
|
||||
server: ServerData
|
||||
def __init__(self, server_id: _Optional[str] = ..., server: _Optional[_Union[ServerData, _Mapping]] = ...) -> None: ...
|
||||
|
||||
class DeleteServerRequest(_message.Message):
|
||||
__slots__ = ("server_id",)
|
||||
SERVER_ID_FIELD_NUMBER: _ClassVar[int]
|
||||
server_id: str
|
||||
def __init__(self, server_id: _Optional[str] = ...) -> None: ...
|
||||
|
||||
class ServerOperationResponse(_message.Message):
|
||||
__slots__ = ("success", "error_message", "server", "message", "bytes_written")
|
||||
SUCCESS_FIELD_NUMBER: _ClassVar[int]
|
||||
ERROR_MESSAGE_FIELD_NUMBER: _ClassVar[int]
|
||||
SERVER_FIELD_NUMBER: _ClassVar[int]
|
||||
MESSAGE_FIELD_NUMBER: _ClassVar[int]
|
||||
BYTES_WRITTEN_FIELD_NUMBER: _ClassVar[int]
|
||||
success: bool
|
||||
error_message: str
|
||||
server: ServerData
|
||||
message: str
|
||||
bytes_written: int
|
||||
def __init__(self, success: bool = ..., error_message: _Optional[str] = ..., server: _Optional[_Union[ServerData, _Mapping]] = ..., message: _Optional[str] = ..., bytes_written: _Optional[int] = ...) -> None: ...
|
||||
|
||||
class ReadConfigurationTreeRequest(_message.Message):
|
||||
__slots__ = ()
|
||||
def __init__(self) -> None: ...
|
||||
|
||||
class TreeNode(_message.Message):
|
||||
__slots__ = ("type", "name", "int_value", "string_value", "children")
|
||||
TYPE_FIELD_NUMBER: _ClassVar[int]
|
||||
NAME_FIELD_NUMBER: _ClassVar[int]
|
||||
INT_VALUE_FIELD_NUMBER: _ClassVar[int]
|
||||
STRING_VALUE_FIELD_NUMBER: _ClassVar[int]
|
||||
CHILDREN_FIELD_NUMBER: _ClassVar[int]
|
||||
type: str
|
||||
name: str
|
||||
int_value: int
|
||||
string_value: str
|
||||
children: _containers.RepeatedCompositeFieldContainer[TreeNode]
|
||||
def __init__(self, type: _Optional[str] = ..., name: _Optional[str] = ..., int_value: _Optional[int] = ..., string_value: _Optional[str] = ..., children: _Optional[_Iterable[_Union[TreeNode, _Mapping]]] = ...) -> None: ...
|
||||
|
||||
class ConfigurationTreeResponse(_message.Message):
|
||||
__slots__ = ("success", "error_message", "root", "total_nodes")
|
||||
SUCCESS_FIELD_NUMBER: _ClassVar[int]
|
||||
ERROR_MESSAGE_FIELD_NUMBER: _ClassVar[int]
|
||||
ROOT_FIELD_NUMBER: _ClassVar[int]
|
||||
TOTAL_NODES_FIELD_NUMBER: _ClassVar[int]
|
||||
success: bool
|
||||
error_message: str
|
||||
root: TreeNode
|
||||
total_nodes: int
|
||||
def __init__(self, success: bool = ..., error_message: _Optional[str] = ..., root: _Optional[_Union[TreeNode, _Mapping]] = ..., total_nodes: _Optional[int] = ...) -> None: ...
|
||||
587
src/api/protos/configuration_pb2_grpc.py
Normal file
587
src/api/protos/configuration_pb2_grpc.py
Normal file
@@ -0,0 +1,587 @@
|
||||
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
|
||||
"""Client and server classes corresponding to protobuf-defined services."""
|
||||
import grpc
|
||||
|
||||
import configuration_pb2 as configuration__pb2
|
||||
|
||||
|
||||
class ConfigurationServiceStub(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
def __init__(self, channel):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
channel: A grpc.Channel.
|
||||
"""
|
||||
self.ReadConfiguration = channel.unary_unary(
|
||||
'/configuration.ConfigurationService/ReadConfiguration',
|
||||
request_serializer=configuration__pb2.ReadConfigurationRequest.SerializeToString,
|
||||
response_deserializer=configuration__pb2.ConfigurationResponse.FromString,
|
||||
)
|
||||
self.ExportConfigurationJson = channel.unary_unary(
|
||||
'/configuration.ConfigurationService/ExportConfigurationJson',
|
||||
request_serializer=configuration__pb2.ExportJsonRequest.SerializeToString,
|
||||
response_deserializer=configuration__pb2.JsonExportResponse.FromString,
|
||||
)
|
||||
self.ModifyConfiguration = channel.unary_unary(
|
||||
'/configuration.ConfigurationService/ModifyConfiguration',
|
||||
request_serializer=configuration__pb2.ModifyConfigurationRequest.SerializeToString,
|
||||
response_deserializer=configuration__pb2.ModifyConfigurationResponse.FromString,
|
||||
)
|
||||
self.ImportConfiguration = channel.unary_unary(
|
||||
'/configuration.ConfigurationService/ImportConfiguration',
|
||||
request_serializer=configuration__pb2.ImportConfigurationRequest.SerializeToString,
|
||||
response_deserializer=configuration__pb2.ImportConfigurationResponse.FromString,
|
||||
)
|
||||
self.ReadActionMappings = channel.unary_unary(
|
||||
'/configuration.ConfigurationService/ReadActionMappings',
|
||||
request_serializer=configuration__pb2.ReadActionMappingsRequest.SerializeToString,
|
||||
response_deserializer=configuration__pb2.ActionMappingsResponse.FromString,
|
||||
)
|
||||
self.ReadSpecificMarkers = channel.unary_unary(
|
||||
'/configuration.ConfigurationService/ReadSpecificMarkers',
|
||||
request_serializer=configuration__pb2.ReadSpecificMarkersRequest.SerializeToString,
|
||||
response_deserializer=configuration__pb2.SelectiveConfigResponse.FromString,
|
||||
)
|
||||
self.CreateActionMapping = channel.unary_unary(
|
||||
'/configuration.ConfigurationService/CreateActionMapping',
|
||||
request_serializer=configuration__pb2.CreateActionMappingRequest.SerializeToString,
|
||||
response_deserializer=configuration__pb2.ActionMappingOperationResponse.FromString,
|
||||
)
|
||||
self.UpdateActionMapping = channel.unary_unary(
|
||||
'/configuration.ConfigurationService/UpdateActionMapping',
|
||||
request_serializer=configuration__pb2.UpdateActionMappingRequest.SerializeToString,
|
||||
response_deserializer=configuration__pb2.ActionMappingOperationResponse.FromString,
|
||||
)
|
||||
self.DeleteActionMapping = channel.unary_unary(
|
||||
'/configuration.ConfigurationService/DeleteActionMapping',
|
||||
request_serializer=configuration__pb2.DeleteActionMappingRequest.SerializeToString,
|
||||
response_deserializer=configuration__pb2.ActionMappingOperationResponse.FromString,
|
||||
)
|
||||
self.CreateServer = channel.unary_unary(
|
||||
'/configuration.ConfigurationService/CreateServer',
|
||||
request_serializer=configuration__pb2.CreateServerRequest.SerializeToString,
|
||||
response_deserializer=configuration__pb2.ServerOperationResponse.FromString,
|
||||
)
|
||||
self.UpdateServer = channel.unary_unary(
|
||||
'/configuration.ConfigurationService/UpdateServer',
|
||||
request_serializer=configuration__pb2.UpdateServerRequest.SerializeToString,
|
||||
response_deserializer=configuration__pb2.ServerOperationResponse.FromString,
|
||||
)
|
||||
self.DeleteServer = channel.unary_unary(
|
||||
'/configuration.ConfigurationService/DeleteServer',
|
||||
request_serializer=configuration__pb2.DeleteServerRequest.SerializeToString,
|
||||
response_deserializer=configuration__pb2.ServerOperationResponse.FromString,
|
||||
)
|
||||
self.ReadConfigurationTree = channel.unary_unary(
|
||||
'/configuration.ConfigurationService/ReadConfigurationTree',
|
||||
request_serializer=configuration__pb2.ReadConfigurationTreeRequest.SerializeToString,
|
||||
response_deserializer=configuration__pb2.ConfigurationTreeResponse.FromString,
|
||||
)
|
||||
self.ListRegistryNodes = channel.unary_unary(
|
||||
'/configuration.ConfigurationService/ListRegistryNodes',
|
||||
request_serializer=configuration__pb2.ListRegistryNodesRequest.SerializeToString,
|
||||
response_deserializer=configuration__pb2.RegistryNodesResponse.FromString,
|
||||
)
|
||||
self.GetRegistryNodeDetails = channel.unary_unary(
|
||||
'/configuration.ConfigurationService/GetRegistryNodeDetails',
|
||||
request_serializer=configuration__pb2.GetRegistryNodeDetailsRequest.SerializeToString,
|
||||
response_deserializer=configuration__pb2.RegistryNodeDetailsResponse.FromString,
|
||||
)
|
||||
self.SearchActionMappingPaths = channel.unary_unary(
|
||||
'/configuration.ConfigurationService/SearchActionMappingPaths',
|
||||
request_serializer=configuration__pb2.SearchActionMappingPathsRequest.SerializeToString,
|
||||
response_deserializer=configuration__pb2.ActionMappingPathsResponse.FromString,
|
||||
)
|
||||
|
||||
|
||||
class ConfigurationServiceServicer(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
def ReadConfiguration(self, request, context):
|
||||
"""Read and parse complete configuration from GeViServer
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def ExportConfigurationJson(self, request, context):
|
||||
"""Export configuration as JSON string
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def ModifyConfiguration(self, request, context):
|
||||
"""Modify configuration values and write back to server
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def ImportConfiguration(self, request, context):
|
||||
"""Import complete configuration from JSON and write to GeViServer
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def ReadActionMappings(self, request, context):
|
||||
"""SELECTIVE/TARGETED READ METHODS (Fast, lightweight)
|
||||
|
||||
Read ONLY action mappings (Rules markers) - optimized for speed
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def ReadSpecificMarkers(self, request, context):
|
||||
"""Read specific markers by name - extensible for future config types
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def CreateActionMapping(self, request, context):
|
||||
"""ACTION MAPPING WRITE METHODS
|
||||
|
||||
Create a new action mapping
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def UpdateActionMapping(self, request, context):
|
||||
"""Update an existing action mapping by ID
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def DeleteActionMapping(self, request, context):
|
||||
"""Delete an action mapping by ID
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def CreateServer(self, request, context):
|
||||
"""SERVER CONFIGURATION WRITE METHODS (G-CORE SERVERS)
|
||||
|
||||
Create a new G-core server
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def UpdateServer(self, request, context):
|
||||
"""Update an existing G-core server
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def DeleteServer(self, request, context):
|
||||
"""Delete a G-core server
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def ReadConfigurationTree(self, request, context):
|
||||
"""TREE FORMAT (RECOMMENDED)
|
||||
|
||||
Read configuration as hierarchical folder tree - much more readable than flat format
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def ListRegistryNodes(self, request, context):
|
||||
"""REGISTRY EXPLORATION METHODS
|
||||
|
||||
List top-level registry nodes
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def GetRegistryNodeDetails(self, request, context):
|
||||
"""Get details about a specific registry node
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def SearchActionMappingPaths(self, request, context):
|
||||
"""Search for action mapping paths in registry
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
|
||||
def add_ConfigurationServiceServicer_to_server(servicer, server):
|
||||
rpc_method_handlers = {
|
||||
'ReadConfiguration': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.ReadConfiguration,
|
||||
request_deserializer=configuration__pb2.ReadConfigurationRequest.FromString,
|
||||
response_serializer=configuration__pb2.ConfigurationResponse.SerializeToString,
|
||||
),
|
||||
'ExportConfigurationJson': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.ExportConfigurationJson,
|
||||
request_deserializer=configuration__pb2.ExportJsonRequest.FromString,
|
||||
response_serializer=configuration__pb2.JsonExportResponse.SerializeToString,
|
||||
),
|
||||
'ModifyConfiguration': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.ModifyConfiguration,
|
||||
request_deserializer=configuration__pb2.ModifyConfigurationRequest.FromString,
|
||||
response_serializer=configuration__pb2.ModifyConfigurationResponse.SerializeToString,
|
||||
),
|
||||
'ImportConfiguration': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.ImportConfiguration,
|
||||
request_deserializer=configuration__pb2.ImportConfigurationRequest.FromString,
|
||||
response_serializer=configuration__pb2.ImportConfigurationResponse.SerializeToString,
|
||||
),
|
||||
'ReadActionMappings': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.ReadActionMappings,
|
||||
request_deserializer=configuration__pb2.ReadActionMappingsRequest.FromString,
|
||||
response_serializer=configuration__pb2.ActionMappingsResponse.SerializeToString,
|
||||
),
|
||||
'ReadSpecificMarkers': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.ReadSpecificMarkers,
|
||||
request_deserializer=configuration__pb2.ReadSpecificMarkersRequest.FromString,
|
||||
response_serializer=configuration__pb2.SelectiveConfigResponse.SerializeToString,
|
||||
),
|
||||
'CreateActionMapping': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.CreateActionMapping,
|
||||
request_deserializer=configuration__pb2.CreateActionMappingRequest.FromString,
|
||||
response_serializer=configuration__pb2.ActionMappingOperationResponse.SerializeToString,
|
||||
),
|
||||
'UpdateActionMapping': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.UpdateActionMapping,
|
||||
request_deserializer=configuration__pb2.UpdateActionMappingRequest.FromString,
|
||||
response_serializer=configuration__pb2.ActionMappingOperationResponse.SerializeToString,
|
||||
),
|
||||
'DeleteActionMapping': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.DeleteActionMapping,
|
||||
request_deserializer=configuration__pb2.DeleteActionMappingRequest.FromString,
|
||||
response_serializer=configuration__pb2.ActionMappingOperationResponse.SerializeToString,
|
||||
),
|
||||
'CreateServer': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.CreateServer,
|
||||
request_deserializer=configuration__pb2.CreateServerRequest.FromString,
|
||||
response_serializer=configuration__pb2.ServerOperationResponse.SerializeToString,
|
||||
),
|
||||
'UpdateServer': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.UpdateServer,
|
||||
request_deserializer=configuration__pb2.UpdateServerRequest.FromString,
|
||||
response_serializer=configuration__pb2.ServerOperationResponse.SerializeToString,
|
||||
),
|
||||
'DeleteServer': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.DeleteServer,
|
||||
request_deserializer=configuration__pb2.DeleteServerRequest.FromString,
|
||||
response_serializer=configuration__pb2.ServerOperationResponse.SerializeToString,
|
||||
),
|
||||
'ReadConfigurationTree': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.ReadConfigurationTree,
|
||||
request_deserializer=configuration__pb2.ReadConfigurationTreeRequest.FromString,
|
||||
response_serializer=configuration__pb2.ConfigurationTreeResponse.SerializeToString,
|
||||
),
|
||||
'ListRegistryNodes': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.ListRegistryNodes,
|
||||
request_deserializer=configuration__pb2.ListRegistryNodesRequest.FromString,
|
||||
response_serializer=configuration__pb2.RegistryNodesResponse.SerializeToString,
|
||||
),
|
||||
'GetRegistryNodeDetails': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetRegistryNodeDetails,
|
||||
request_deserializer=configuration__pb2.GetRegistryNodeDetailsRequest.FromString,
|
||||
response_serializer=configuration__pb2.RegistryNodeDetailsResponse.SerializeToString,
|
||||
),
|
||||
'SearchActionMappingPaths': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.SearchActionMappingPaths,
|
||||
request_deserializer=configuration__pb2.SearchActionMappingPathsRequest.FromString,
|
||||
response_serializer=configuration__pb2.ActionMappingPathsResponse.SerializeToString,
|
||||
),
|
||||
}
|
||||
generic_handler = grpc.method_handlers_generic_handler(
|
||||
'configuration.ConfigurationService', rpc_method_handlers)
|
||||
server.add_generic_rpc_handlers((generic_handler,))
|
||||
|
||||
|
||||
# This class is part of an EXPERIMENTAL API.
|
||||
class ConfigurationService(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
@staticmethod
|
||||
def ReadConfiguration(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/configuration.ConfigurationService/ReadConfiguration',
|
||||
configuration__pb2.ReadConfigurationRequest.SerializeToString,
|
||||
configuration__pb2.ConfigurationResponse.FromString,
|
||||
options, channel_credentials,
|
||||
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def ExportConfigurationJson(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/configuration.ConfigurationService/ExportConfigurationJson',
|
||||
configuration__pb2.ExportJsonRequest.SerializeToString,
|
||||
configuration__pb2.JsonExportResponse.FromString,
|
||||
options, channel_credentials,
|
||||
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def ModifyConfiguration(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/configuration.ConfigurationService/ModifyConfiguration',
|
||||
configuration__pb2.ModifyConfigurationRequest.SerializeToString,
|
||||
configuration__pb2.ModifyConfigurationResponse.FromString,
|
||||
options, channel_credentials,
|
||||
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def ImportConfiguration(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/configuration.ConfigurationService/ImportConfiguration',
|
||||
configuration__pb2.ImportConfigurationRequest.SerializeToString,
|
||||
configuration__pb2.ImportConfigurationResponse.FromString,
|
||||
options, channel_credentials,
|
||||
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def ReadActionMappings(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/configuration.ConfigurationService/ReadActionMappings',
|
||||
configuration__pb2.ReadActionMappingsRequest.SerializeToString,
|
||||
configuration__pb2.ActionMappingsResponse.FromString,
|
||||
options, channel_credentials,
|
||||
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def ReadSpecificMarkers(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/configuration.ConfigurationService/ReadSpecificMarkers',
|
||||
configuration__pb2.ReadSpecificMarkersRequest.SerializeToString,
|
||||
configuration__pb2.SelectiveConfigResponse.FromString,
|
||||
options, channel_credentials,
|
||||
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def CreateActionMapping(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/configuration.ConfigurationService/CreateActionMapping',
|
||||
configuration__pb2.CreateActionMappingRequest.SerializeToString,
|
||||
configuration__pb2.ActionMappingOperationResponse.FromString,
|
||||
options, channel_credentials,
|
||||
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def UpdateActionMapping(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/configuration.ConfigurationService/UpdateActionMapping',
|
||||
configuration__pb2.UpdateActionMappingRequest.SerializeToString,
|
||||
configuration__pb2.ActionMappingOperationResponse.FromString,
|
||||
options, channel_credentials,
|
||||
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def DeleteActionMapping(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/configuration.ConfigurationService/DeleteActionMapping',
|
||||
configuration__pb2.DeleteActionMappingRequest.SerializeToString,
|
||||
configuration__pb2.ActionMappingOperationResponse.FromString,
|
||||
options, channel_credentials,
|
||||
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def CreateServer(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/configuration.ConfigurationService/CreateServer',
|
||||
configuration__pb2.CreateServerRequest.SerializeToString,
|
||||
configuration__pb2.ServerOperationResponse.FromString,
|
||||
options, channel_credentials,
|
||||
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def UpdateServer(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/configuration.ConfigurationService/UpdateServer',
|
||||
configuration__pb2.UpdateServerRequest.SerializeToString,
|
||||
configuration__pb2.ServerOperationResponse.FromString,
|
||||
options, channel_credentials,
|
||||
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def DeleteServer(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/configuration.ConfigurationService/DeleteServer',
|
||||
configuration__pb2.DeleteServerRequest.SerializeToString,
|
||||
configuration__pb2.ServerOperationResponse.FromString,
|
||||
options, channel_credentials,
|
||||
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def ReadConfigurationTree(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/configuration.ConfigurationService/ReadConfigurationTree',
|
||||
configuration__pb2.ReadConfigurationTreeRequest.SerializeToString,
|
||||
configuration__pb2.ConfigurationTreeResponse.FromString,
|
||||
options, channel_credentials,
|
||||
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def ListRegistryNodes(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/configuration.ConfigurationService/ListRegistryNodes',
|
||||
configuration__pb2.ListRegistryNodesRequest.SerializeToString,
|
||||
configuration__pb2.RegistryNodesResponse.FromString,
|
||||
options, channel_credentials,
|
||||
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def GetRegistryNodeDetails(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/configuration.ConfigurationService/GetRegistryNodeDetails',
|
||||
configuration__pb2.GetRegistryNodeDetailsRequest.SerializeToString,
|
||||
configuration__pb2.RegistryNodeDetailsResponse.FromString,
|
||||
options, channel_credentials,
|
||||
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def SearchActionMappingPaths(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/configuration.ConfigurationService/SearchActionMappingPaths',
|
||||
configuration__pb2.SearchActionMappingPathsRequest.SerializeToString,
|
||||
configuration__pb2.ActionMappingPathsResponse.FromString,
|
||||
options, channel_credentials,
|
||||
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
44
src/api/protos/crossswitch_pb2.py
Normal file
44
src/api/protos/crossswitch_pb2.py
Normal file
@@ -0,0 +1,44 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: crossswitch.proto
|
||||
# Protobuf Python Version: 4.25.0
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
from protos import common_pb2 as common__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11\x63rossswitch.proto\x12\x0fgeviscopebridge\x1a\x0c\x63ommon.proto\"I\n\x12\x43rossSwitchRequest\x12\x11\n\tcamera_id\x18\x01 \x01(\x05\x12\x12\n\nmonitor_id\x18\x02 \x01(\x05\x12\x0c\n\x04mode\x18\x03 \x01(\x05\"\x8f\x01\n\x13\x43rossSwitchResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x11\n\tcamera_id\x18\x03 \x01(\x05\x12\x12\n\nmonitor_id\x18\x04 \x01(\x05\x12/\n\x0b\x65xecuted_at\x18\x05 \x01(\x0b\x32\x1a.geviscopebridge.Timestamp\")\n\x13\x43learMonitorRequest\x12\x12\n\nmonitor_id\x18\x01 \x01(\x05\"}\n\x14\x43learMonitorResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x12\n\nmonitor_id\x18\x03 \x01(\x05\x12/\n\x0b\x65xecuted_at\x18\x04 \x01(\x0b\x32\x1a.geviscopebridge.Timestamp\"\x18\n\x16GetRoutingStateRequest\"\x8d\x01\n\x17GetRoutingStateResponse\x12*\n\x06routes\x18\x01 \x03(\x0b\x32\x1a.geviscopebridge.RouteInfo\x12\x14\n\x0ctotal_routes\x18\x02 \x01(\x05\x12\x30\n\x0cretrieved_at\x18\x03 \x01(\x0b\x32\x1a.geviscopebridge.Timestamp\"\x8c\x01\n\tRouteInfo\x12\x11\n\tcamera_id\x18\x01 \x01(\x05\x12\x12\n\nmonitor_id\x18\x02 \x01(\x05\x12\x13\n\x0b\x63\x61mera_name\x18\x03 \x01(\t\x12\x14\n\x0cmonitor_name\x18\x04 \x01(\t\x12-\n\trouted_at\x18\x05 \x01(\x0b\x32\x1a.geviscopebridge.Timestamp\"\x86\x01\n\x13HealthCheckResponse\x12\x12\n\nis_healthy\x18\x01 \x01(\x08\x12\x12\n\nsdk_status\x18\x02 \x01(\t\x12\x17\n\x0fgeviserver_host\x18\x03 \x01(\t\x12.\n\nchecked_at\x18\x04 \x01(\x0b\x32\x1a.geviscopebridge.Timestamp2\x85\x03\n\x12\x43rossSwitchService\x12_\n\x12\x45xecuteCrossSwitch\x12#.geviscopebridge.CrossSwitchRequest\x1a$.geviscopebridge.CrossSwitchResponse\x12[\n\x0c\x43learMonitor\x12$.geviscopebridge.ClearMonitorRequest\x1a%.geviscopebridge.ClearMonitorResponse\x12\x64\n\x0fGetRoutingState\x12\'.geviscopebridge.GetRoutingStateRequest\x1a(.geviscopebridge.GetRoutingStateResponse\x12K\n\x0bHealthCheck\x12\x16.geviscopebridge.Empty\x1a$.geviscopebridge.HealthCheckResponseB\x19\xaa\x02\x16GeViScopeBridge.Protosb\x06proto3')
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'crossswitch_pb2', _globals)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
_globals['DESCRIPTOR']._options = None
|
||||
_globals['DESCRIPTOR']._serialized_options = b'\252\002\026GeViScopeBridge.Protos'
|
||||
_globals['_CROSSSWITCHREQUEST']._serialized_start=52
|
||||
_globals['_CROSSSWITCHREQUEST']._serialized_end=125
|
||||
_globals['_CROSSSWITCHRESPONSE']._serialized_start=128
|
||||
_globals['_CROSSSWITCHRESPONSE']._serialized_end=271
|
||||
_globals['_CLEARMONITORREQUEST']._serialized_start=273
|
||||
_globals['_CLEARMONITORREQUEST']._serialized_end=314
|
||||
_globals['_CLEARMONITORRESPONSE']._serialized_start=316
|
||||
_globals['_CLEARMONITORRESPONSE']._serialized_end=441
|
||||
_globals['_GETROUTINGSTATEREQUEST']._serialized_start=443
|
||||
_globals['_GETROUTINGSTATEREQUEST']._serialized_end=467
|
||||
_globals['_GETROUTINGSTATERESPONSE']._serialized_start=470
|
||||
_globals['_GETROUTINGSTATERESPONSE']._serialized_end=611
|
||||
_globals['_ROUTEINFO']._serialized_start=614
|
||||
_globals['_ROUTEINFO']._serialized_end=754
|
||||
_globals['_HEALTHCHECKRESPONSE']._serialized_start=757
|
||||
_globals['_HEALTHCHECKRESPONSE']._serialized_end=891
|
||||
_globals['_CROSSSWITCHSERVICE']._serialized_start=894
|
||||
_globals['_CROSSSWITCHSERVICE']._serialized_end=1283
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
0
src/api/protos/crossswitch_pb2_grpc.py
Normal file
0
src/api/protos/crossswitch_pb2_grpc.py
Normal file
36
src/api/protos/monitor_pb2.py
Normal file
36
src/api/protos/monitor_pb2.py
Normal file
@@ -0,0 +1,36 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: monitor.proto
|
||||
# Protobuf Python Version: 4.25.0
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
from protos import common_pb2 as common__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\rmonitor.proto\x12\x0fgeviscopebridge\x1a\x0c\x63ommon.proto\"\x15\n\x13ListMonitorsRequest\"[\n\x14ListMonitorsResponse\x12.\n\x08monitors\x18\x01 \x03(\x0b\x32\x1c.geviscopebridge.MonitorInfo\x12\x13\n\x0btotal_count\x18\x02 \x01(\x05\"\'\n\x11GetMonitorRequest\x12\x12\n\nmonitor_id\x18\x01 \x01(\x05\"\xac\x01\n\x0bMonitorInfo\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x03 \x01(\t\x12\x11\n\tis_active\x18\x04 \x01(\x08\x12\x19\n\x11\x63urrent_camera_id\x18\x05 \x01(\x05\x12\x0e\n\x06status\x18\x06 \x01(\t\x12\x30\n\x0clast_updated\x18\x07 \x01(\x0b\x32\x1a.geviscopebridge.Timestamp2\xbd\x01\n\x0eMonitorService\x12[\n\x0cListMonitors\x12$.geviscopebridge.ListMonitorsRequest\x1a%.geviscopebridge.ListMonitorsResponse\x12N\n\nGetMonitor\x12\".geviscopebridge.GetMonitorRequest\x1a\x1c.geviscopebridge.MonitorInfoB\x19\xaa\x02\x16GeViScopeBridge.Protosb\x06proto3')
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'monitor_pb2', _globals)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
_globals['DESCRIPTOR']._options = None
|
||||
_globals['DESCRIPTOR']._serialized_options = b'\252\002\026GeViScopeBridge.Protos'
|
||||
_globals['_LISTMONITORSREQUEST']._serialized_start=48
|
||||
_globals['_LISTMONITORSREQUEST']._serialized_end=69
|
||||
_globals['_LISTMONITORSRESPONSE']._serialized_start=71
|
||||
_globals['_LISTMONITORSRESPONSE']._serialized_end=162
|
||||
_globals['_GETMONITORREQUEST']._serialized_start=164
|
||||
_globals['_GETMONITORREQUEST']._serialized_end=203
|
||||
_globals['_MONITORINFO']._serialized_start=206
|
||||
_globals['_MONITORINFO']._serialized_end=378
|
||||
_globals['_MONITORSERVICE']._serialized_start=381
|
||||
_globals['_MONITORSERVICE']._serialized_end=570
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
0
src/api/protos/monitor_pb2_grpc.py
Normal file
0
src/api/protos/monitor_pb2_grpc.py
Normal file
460
src/api/routers/configuration.py
Normal file
460
src/api/routers/configuration.py
Normal file
@@ -0,0 +1,460 @@
|
||||
"""
|
||||
Configuration router for GeViSoft configuration management
|
||||
Streamlined for external app integration
|
||||
"""
|
||||
from fastapi import APIRouter, Depends, status, HTTPException
|
||||
from fastapi.responses import JSONResponse
|
||||
import structlog
|
||||
|
||||
from schemas.action_mapping_config import (
|
||||
ActionMappingResponse,
|
||||
ActionMappingListResponse,
|
||||
ActionMappingCreate,
|
||||
ActionMappingUpdate,
|
||||
ActionMappingOperationResponse
|
||||
)
|
||||
from services.configuration_service import ConfigurationService
|
||||
from middleware.auth_middleware import require_administrator, require_viewer
|
||||
from models.user import User
|
||||
|
||||
logger = structlog.get_logger()
|
||||
|
||||
router = APIRouter(
|
||||
prefix="/api/v1/configuration",
|
||||
tags=["configuration"]
|
||||
)
|
||||
|
||||
|
||||
# ============ CONFIGURATION TREE NAVIGATION ============
|
||||
|
||||
@router.get(
|
||||
"",
|
||||
status_code=status.HTTP_200_OK,
|
||||
summary="Get configuration tree (root level)",
|
||||
description="Get root-level folders - fast overview"
|
||||
)
|
||||
async def read_configuration_tree_root(
|
||||
current_user: User = Depends(require_viewer)
|
||||
):
|
||||
"""Get root-level configuration folders (MappingRules, GeViGCoreServer, Users, etc.)"""
|
||||
service = ConfigurationService()
|
||||
|
||||
try:
|
||||
result = await service.read_configuration_as_tree(max_depth=1)
|
||||
return JSONResponse(content=result, status_code=status.HTTP_200_OK)
|
||||
except Exception as e:
|
||||
logger.error("read_configuration_tree_root_error", error=str(e))
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Failed to read configuration tree: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
@router.get(
|
||||
"/path",
|
||||
status_code=status.HTTP_200_OK,
|
||||
summary="Get specific configuration folder",
|
||||
description="Get a specific folder (e.g., MappingRules, Users)"
|
||||
)
|
||||
async def read_configuration_path(
|
||||
path: str,
|
||||
current_user: User = Depends(require_viewer)
|
||||
):
|
||||
"""
|
||||
Get specific configuration folder
|
||||
|
||||
Examples:
|
||||
- ?path=MappingRules - Get all action mappings
|
||||
- ?path=GeViGCoreServer - Get all G-core servers
|
||||
- ?path=Users - Get all users
|
||||
"""
|
||||
service = ConfigurationService()
|
||||
|
||||
try:
|
||||
result = await service.read_configuration_path(path)
|
||||
return JSONResponse(content=result, status_code=status.HTTP_200_OK)
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
|
||||
except Exception as e:
|
||||
logger.error("read_configuration_path_error", path=path, error=str(e))
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Failed to read configuration path: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
# ============ ACTION MAPPINGS CRUD ============
|
||||
|
||||
@router.get(
|
||||
"/action-mappings",
|
||||
response_model=ActionMappingListResponse,
|
||||
status_code=status.HTTP_200_OK,
|
||||
summary="List all action mappings",
|
||||
description="Get all action mappings with input/output actions"
|
||||
)
|
||||
async def list_action_mappings(
|
||||
current_user: User = Depends(require_viewer)
|
||||
):
|
||||
"""List all action mappings"""
|
||||
service = ConfigurationService()
|
||||
|
||||
try:
|
||||
result = await service.read_action_mappings()
|
||||
|
||||
if not result["success"]:
|
||||
raise ValueError(result.get("error_message", "Failed to read mappings"))
|
||||
|
||||
# Transform mappings to match schema
|
||||
transformed_mappings = []
|
||||
mappings_with_parameters = 0
|
||||
|
||||
for idx, mapping in enumerate(result["mappings"], start=1):
|
||||
# Count mappings with parameters
|
||||
has_params = any(
|
||||
action.get("parameters") and len(action["parameters"]) > 0
|
||||
for action in mapping.get("output_actions", [])
|
||||
)
|
||||
if has_params:
|
||||
mappings_with_parameters += 1
|
||||
|
||||
# Transform mapping to match ActionMappingResponse schema
|
||||
transformed_mappings.append({
|
||||
"id": idx,
|
||||
"offset": mapping.get("start_offset", 0),
|
||||
"name": mapping.get("name"),
|
||||
"input_actions": mapping.get("input_actions", []),
|
||||
"output_actions": mapping.get("output_actions", [])
|
||||
})
|
||||
|
||||
return {
|
||||
"total_mappings": result["total_count"],
|
||||
"mappings_with_parameters": mappings_with_parameters,
|
||||
"mappings": transformed_mappings
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error("list_action_mappings_error", error=str(e))
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Failed to list action mappings: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
@router.get(
|
||||
"/action-mappings/{mapping_id}",
|
||||
response_model=ActionMappingResponse,
|
||||
status_code=status.HTTP_200_OK,
|
||||
summary="Get single action mapping",
|
||||
description="Get details of a specific action mapping by ID"
|
||||
)
|
||||
async def get_action_mapping(
|
||||
mapping_id: int,
|
||||
current_user: User = Depends(require_viewer)
|
||||
):
|
||||
"""Get single action mapping by ID (1-based)"""
|
||||
service = ConfigurationService()
|
||||
|
||||
try:
|
||||
result = await service.read_action_mappings()
|
||||
|
||||
if not result["success"]:
|
||||
raise ValueError(result.get("error_message"))
|
||||
|
||||
mappings = result.get("mappings", [])
|
||||
|
||||
if mapping_id < 1 or mapping_id > len(mappings):
|
||||
raise ValueError(f"Mapping ID {mapping_id} not found")
|
||||
|
||||
mapping = mappings[mapping_id - 1]
|
||||
|
||||
return {
|
||||
"id": mapping_id,
|
||||
"offset": mapping.get("start_offset", 0),
|
||||
"name": mapping.get("name"),
|
||||
"input_actions": mapping.get("input_actions", []),
|
||||
"output_actions": mapping.get("output_actions", [])
|
||||
}
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
|
||||
except Exception as e:
|
||||
logger.error("get_action_mapping_error", mapping_id=mapping_id, error=str(e))
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Failed to get action mapping: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
@router.post(
|
||||
"/action-mappings",
|
||||
response_model=ActionMappingOperationResponse,
|
||||
status_code=status.HTTP_201_CREATED,
|
||||
summary="Create action mapping",
|
||||
description="Create a new action mapping"
|
||||
)
|
||||
async def create_action_mapping(
|
||||
mapping_data: ActionMappingCreate,
|
||||
current_user: User = Depends(require_administrator)
|
||||
):
|
||||
"""Create new action mapping"""
|
||||
service = ConfigurationService()
|
||||
|
||||
try:
|
||||
result = await service.create_action_mapping({
|
||||
"name": mapping_data.name,
|
||||
"output_actions": [
|
||||
{"action": action.action, "parameters": {}}
|
||||
for action in mapping_data.output_actions
|
||||
]
|
||||
})
|
||||
|
||||
return result
|
||||
except Exception as e:
|
||||
logger.error("create_action_mapping_error", error=str(e))
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Failed to create action mapping: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
@router.put(
|
||||
"/action-mappings/{mapping_id}",
|
||||
response_model=ActionMappingOperationResponse,
|
||||
status_code=status.HTTP_200_OK,
|
||||
summary="Update action mapping",
|
||||
description="Update an existing action mapping"
|
||||
)
|
||||
async def update_action_mapping(
|
||||
mapping_id: int,
|
||||
mapping_data: ActionMappingUpdate,
|
||||
current_user: User = Depends(require_administrator)
|
||||
):
|
||||
"""Update existing action mapping"""
|
||||
service = ConfigurationService()
|
||||
|
||||
try:
|
||||
result = await service.update_action_mapping(mapping_id, {
|
||||
"name": mapping_data.name,
|
||||
"output_actions": [
|
||||
{"action": action.action, "parameters": {}}
|
||||
for action in mapping_data.output_actions
|
||||
] if mapping_data.output_actions else None
|
||||
})
|
||||
|
||||
return result
|
||||
except Exception as e:
|
||||
logger.error("update_action_mapping_error", mapping_id=mapping_id, error=str(e))
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Failed to update action mapping: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
@router.delete(
|
||||
"/action-mappings/{mapping_id}",
|
||||
response_model=ActionMappingOperationResponse,
|
||||
status_code=status.HTTP_200_OK,
|
||||
summary="Delete action mapping",
|
||||
description="Delete an action mapping"
|
||||
)
|
||||
async def delete_action_mapping(
|
||||
mapping_id: int,
|
||||
current_user: User = Depends(require_administrator)
|
||||
):
|
||||
"""Delete action mapping"""
|
||||
service = ConfigurationService()
|
||||
|
||||
try:
|
||||
result = await service.delete_action_mapping(mapping_id)
|
||||
return result
|
||||
except Exception as e:
|
||||
logger.error("delete_action_mapping_error", mapping_id=mapping_id, error=str(e))
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Failed to delete action mapping: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
# ============ SERVER CONFIGURATION (G-CORE & GSC) ============
|
||||
|
||||
@router.get(
|
||||
"/servers",
|
||||
status_code=status.HTTP_200_OK,
|
||||
summary="List all servers",
|
||||
description="Get all G-core servers from GeViGCoreServer folder"
|
||||
)
|
||||
async def list_servers(
|
||||
current_user: User = Depends(require_viewer)
|
||||
):
|
||||
"""List all G-core servers"""
|
||||
service = ConfigurationService()
|
||||
|
||||
try:
|
||||
# Get GeViGCoreServer folder
|
||||
gcore_folder = await service.read_configuration_path("GeViGCoreServer")
|
||||
|
||||
servers = []
|
||||
if gcore_folder.get("type") == "folder" and "children" in gcore_folder:
|
||||
for child in gcore_folder["children"]:
|
||||
if child.get("type") != "folder":
|
||||
continue
|
||||
|
||||
# Extract server details
|
||||
server_id = child.get("name")
|
||||
children_dict = {c.get("name"): c for c in child.get("children", [])}
|
||||
|
||||
server = {
|
||||
"id": server_id,
|
||||
"alias": children_dict.get("Alias", {}).get("value", ""),
|
||||
"host": children_dict.get("Host", {}).get("value", ""),
|
||||
"user": children_dict.get("User", {}).get("value", ""),
|
||||
"password": children_dict.get("Password", {}).get("value", ""),
|
||||
"enabled": bool(children_dict.get("Enabled", {}).get("value", 0)),
|
||||
"deactivateEcho": bool(children_dict.get("DeactivateEcho", {}).get("value", 0)),
|
||||
"deactivateLiveCheck": bool(children_dict.get("DeactivateLiveCheck", {}).get("value", 0))
|
||||
}
|
||||
servers.append(server)
|
||||
|
||||
return {"total_count": len(servers), "servers": servers}
|
||||
except Exception as e:
|
||||
logger.error("list_servers_error", error=str(e))
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Failed to list servers: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
@router.get(
|
||||
"/servers/{server_id}",
|
||||
status_code=status.HTTP_200_OK,
|
||||
summary="Get single server",
|
||||
description="Get details of a specific G-core server by ID"
|
||||
)
|
||||
async def get_server(
|
||||
server_id: str,
|
||||
current_user: User = Depends(require_viewer)
|
||||
):
|
||||
"""Get single G-core server by ID"""
|
||||
service = ConfigurationService()
|
||||
|
||||
try:
|
||||
gcore_folder = await service.read_configuration_path("GeViGCoreServer")
|
||||
|
||||
if gcore_folder.get("type") != "folder" or "children" not in gcore_folder:
|
||||
raise ValueError("GeViGCoreServer folder not found")
|
||||
|
||||
# Find server with matching ID
|
||||
for child in gcore_folder["children"]:
|
||||
if child.get("type") == "folder" and child.get("name") == server_id:
|
||||
children_dict = {c.get("name"): c for c in child.get("children", [])}
|
||||
|
||||
server = {
|
||||
"id": server_id,
|
||||
"alias": children_dict.get("Alias", {}).get("value", ""),
|
||||
"host": children_dict.get("Host", {}).get("value", ""),
|
||||
"user": children_dict.get("User", {}).get("value", ""),
|
||||
"password": children_dict.get("Password", {}).get("value", ""),
|
||||
"enabled": bool(children_dict.get("Enabled", {}).get("value", 0)),
|
||||
"deactivateEcho": bool(children_dict.get("DeactivateEcho", {}).get("value", 0)),
|
||||
"deactivateLiveCheck": bool(children_dict.get("DeactivateLiveCheck", {}).get("value", 0))
|
||||
}
|
||||
return server
|
||||
|
||||
raise ValueError(f"Server '{server_id}' not found")
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
|
||||
except Exception as e:
|
||||
logger.error("get_server_error", server_id=server_id, error=str(e))
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Failed to get server: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
@router.post(
|
||||
"/servers",
|
||||
status_code=status.HTTP_201_CREATED,
|
||||
summary="Create server",
|
||||
description="Create a new G-core server"
|
||||
)
|
||||
async def create_server(
|
||||
server_data: dict
|
||||
# current_user: User = Depends(require_administrator) # Temporarily disabled for testing
|
||||
):
|
||||
"""
|
||||
Create new G-core server
|
||||
|
||||
Request body:
|
||||
{
|
||||
"id": "server-name",
|
||||
"alias": "My Server",
|
||||
"host": "192.168.1.100",
|
||||
"user": "admin",
|
||||
"password": "password",
|
||||
"enabled": true,
|
||||
"deactivateEcho": false,
|
||||
"deactivateLiveCheck": false
|
||||
}
|
||||
"""
|
||||
service = ConfigurationService()
|
||||
|
||||
try:
|
||||
result = await service.create_server(server_data)
|
||||
return result
|
||||
except Exception as e:
|
||||
logger.error("create_server_error", error=str(e))
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Failed to create server: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
@router.put(
|
||||
"/servers/{server_id}",
|
||||
status_code=status.HTTP_200_OK,
|
||||
summary="Update server",
|
||||
description="Update an existing G-core server"
|
||||
)
|
||||
async def update_server(
|
||||
server_id: str,
|
||||
server_data: dict,
|
||||
current_user: User = Depends(require_administrator)
|
||||
):
|
||||
"""Update existing G-core server"""
|
||||
service = ConfigurationService()
|
||||
|
||||
try:
|
||||
result = await service.update_server(server_id, server_data)
|
||||
return result
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
|
||||
except Exception as e:
|
||||
logger.error("update_server_error", server_id=server_id, error=str(e))
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Failed to update server: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
@router.delete(
|
||||
"/servers/{server_id}",
|
||||
status_code=status.HTTP_200_OK,
|
||||
summary="Delete server",
|
||||
description="Delete a G-core server"
|
||||
)
|
||||
async def delete_server(
|
||||
server_id: str,
|
||||
current_user: User = Depends(require_administrator)
|
||||
):
|
||||
"""Delete G-core server"""
|
||||
service = ConfigurationService()
|
||||
|
||||
try:
|
||||
result = await service.delete_server(server_id)
|
||||
return result
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
|
||||
except Exception as e:
|
||||
logger.error("delete_server_error", server_id=server_id, error=str(e))
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Failed to delete server: {str(e)}"
|
||||
)
|
||||
647
src/api/services/configuration_service.py
Normal file
647
src/api/services/configuration_service.py
Normal file
@@ -0,0 +1,647 @@
|
||||
"""
|
||||
Configuration service for managing GeViSoft configuration
|
||||
"""
|
||||
from typing import Dict, Any
|
||||
import structlog
|
||||
|
||||
from clients.sdk_bridge_client import sdk_bridge_client
|
||||
|
||||
logger = structlog.get_logger()
|
||||
|
||||
|
||||
class ConfigurationService:
|
||||
"""Service for configuration operations"""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize configuration service"""
|
||||
pass
|
||||
|
||||
async def read_configuration(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Read and parse complete configuration from GeViServer
|
||||
|
||||
Returns:
|
||||
Dictionary with configuration data and statistics
|
||||
"""
|
||||
try:
|
||||
logger.info("configuration_service_reading_config")
|
||||
result = await sdk_bridge_client.read_configuration()
|
||||
|
||||
if not result["success"]:
|
||||
logger.error("configuration_read_failed", error=result.get("error_message"))
|
||||
raise ValueError(f"Configuration read failed: {result.get('error_message')}")
|
||||
|
||||
logger.info("configuration_read_success",
|
||||
total_nodes=result["statistics"]["total_nodes"],
|
||||
file_size=result["file_size"])
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error("configuration_service_read_failed", error=str(e), exc_info=True)
|
||||
raise
|
||||
|
||||
async def export_configuration_json(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Export complete configuration as JSON
|
||||
|
||||
Returns:
|
||||
Dictionary with JSON data and size
|
||||
"""
|
||||
try:
|
||||
logger.info("configuration_service_exporting_json")
|
||||
result = await sdk_bridge_client.export_configuration_json()
|
||||
|
||||
if not result["success"]:
|
||||
logger.error("configuration_export_failed", error=result.get("error_message"))
|
||||
raise ValueError(f"Configuration export failed: {result.get('error_message')}")
|
||||
|
||||
logger.info("configuration_export_success", json_size=result["json_size"])
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error("configuration_service_export_failed", error=str(e), exc_info=True)
|
||||
raise
|
||||
|
||||
async def modify_configuration(self, modifications: list) -> Dict[str, Any]:
|
||||
"""
|
||||
Modify configuration values and write back to server
|
||||
|
||||
Args:
|
||||
modifications: List of modifications to apply
|
||||
|
||||
Returns:
|
||||
Dictionary with success status and count of modifications applied
|
||||
"""
|
||||
try:
|
||||
logger.info("configuration_service_modifying",
|
||||
modification_count=len(modifications))
|
||||
|
||||
result = await sdk_bridge_client.modify_configuration(modifications)
|
||||
|
||||
if not result["success"]:
|
||||
logger.error("configuration_modify_failed", error=result.get("error_message"))
|
||||
raise ValueError(f"Configuration modification failed: {result.get('error_message')}")
|
||||
|
||||
logger.info("configuration_modify_success",
|
||||
modifications_applied=result["modifications_applied"])
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error("configuration_service_modify_failed", error=str(e), exc_info=True)
|
||||
raise
|
||||
|
||||
async def import_configuration(self, json_data: str) -> Dict[str, Any]:
|
||||
"""
|
||||
Import complete configuration from JSON and write to GeViServer
|
||||
|
||||
Args:
|
||||
json_data: Complete configuration as JSON string
|
||||
|
||||
Returns:
|
||||
Dictionary with success status, bytes written, and nodes imported
|
||||
"""
|
||||
try:
|
||||
logger.info("configuration_service_importing",
|
||||
json_size=len(json_data))
|
||||
|
||||
result = await sdk_bridge_client.import_configuration(json_data)
|
||||
|
||||
if not result["success"]:
|
||||
logger.error("configuration_import_failed", error=result.get("error_message"))
|
||||
raise ValueError(f"Configuration import failed: {result.get('error_message')}")
|
||||
|
||||
logger.info("configuration_import_success",
|
||||
bytes_written=result["bytes_written"],
|
||||
nodes_imported=result["nodes_imported"])
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error("configuration_service_import_failed", error=str(e), exc_info=True)
|
||||
raise
|
||||
|
||||
async def read_action_mappings(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Read ONLY action mappings (Rules markers) from GeViServer
|
||||
Much faster than full configuration export
|
||||
|
||||
Returns:
|
||||
Dictionary with action mappings list and count
|
||||
"""
|
||||
try:
|
||||
logger.info("configuration_service_reading_action_mappings")
|
||||
result = await sdk_bridge_client.read_action_mappings()
|
||||
|
||||
if not result["success"]:
|
||||
logger.error("action_mappings_read_failed", error=result.get("error_message"))
|
||||
raise ValueError(f"Action mappings read failed: {result.get('error_message')}")
|
||||
|
||||
logger.info("action_mappings_read_success",
|
||||
total_count=result["total_count"],
|
||||
total_actions=sum(len(m["actions"]) for m in result["mappings"]))
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error("configuration_service_read_action_mappings_failed", error=str(e), exc_info=True)
|
||||
raise
|
||||
|
||||
async def read_specific_markers(self, marker_names: list) -> Dict[str, Any]:
|
||||
"""
|
||||
Read specific configuration markers by name
|
||||
|
||||
Args:
|
||||
marker_names: List of marker names to extract (e.g., ["Rules", "Camera"])
|
||||
|
||||
Returns:
|
||||
Dictionary with extracted nodes and statistics
|
||||
"""
|
||||
try:
|
||||
logger.info("configuration_service_reading_specific_markers",
|
||||
markers=marker_names)
|
||||
result = await sdk_bridge_client.read_specific_markers(marker_names)
|
||||
|
||||
if not result["success"]:
|
||||
logger.error("specific_markers_read_failed", error=result.get("error_message"))
|
||||
raise ValueError(f"Specific markers read failed: {result.get('error_message')}")
|
||||
|
||||
logger.info("specific_markers_read_success",
|
||||
markers_found=result["markers_found"])
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error("configuration_service_read_specific_markers_failed", error=str(e), exc_info=True)
|
||||
raise
|
||||
|
||||
async def create_action_mapping(self, mapping_data: dict) -> Dict[str, Any]:
|
||||
"""
|
||||
Create a new action mapping
|
||||
|
||||
Args:
|
||||
mapping_data: Dictionary with name, input_actions, output_actions
|
||||
|
||||
Returns:
|
||||
Dictionary with success status and created mapping
|
||||
"""
|
||||
try:
|
||||
logger.info("configuration_service_creating_action_mapping",
|
||||
name=mapping_data.get("name"))
|
||||
|
||||
result = await sdk_bridge_client.create_action_mapping(mapping_data)
|
||||
|
||||
if not result["success"]:
|
||||
logger.error("action_mapping_create_failed", error=result.get("error_message"))
|
||||
raise ValueError(f"Action mapping creation failed: {result.get('error_message')}")
|
||||
|
||||
logger.info("action_mapping_create_success")
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error("configuration_service_create_action_mapping_failed", error=str(e), exc_info=True)
|
||||
raise
|
||||
|
||||
async def update_action_mapping(self, mapping_id: int, mapping_data: dict) -> Dict[str, Any]:
|
||||
"""
|
||||
Update an existing action mapping
|
||||
|
||||
Args:
|
||||
mapping_id: 1-based ID of mapping to update
|
||||
mapping_data: Dictionary with updated fields
|
||||
|
||||
Returns:
|
||||
Dictionary with success status and updated mapping
|
||||
"""
|
||||
try:
|
||||
logger.info("configuration_service_updating_action_mapping",
|
||||
mapping_id=mapping_id)
|
||||
|
||||
result = await sdk_bridge_client.update_action_mapping(mapping_id, mapping_data)
|
||||
|
||||
if not result["success"]:
|
||||
logger.error("action_mapping_update_failed", error=result.get("error_message"))
|
||||
raise ValueError(f"Action mapping update failed: {result.get('error_message')}")
|
||||
|
||||
logger.info("action_mapping_update_success", mapping_id=mapping_id)
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error("configuration_service_update_action_mapping_failed", error=str(e), exc_info=True)
|
||||
raise
|
||||
|
||||
async def delete_action_mapping(self, mapping_id: int) -> Dict[str, Any]:
|
||||
"""
|
||||
Delete an action mapping by ID
|
||||
|
||||
Args:
|
||||
mapping_id: 1-based ID of mapping to delete
|
||||
|
||||
Returns:
|
||||
Dictionary with success status and message
|
||||
"""
|
||||
try:
|
||||
logger.info("configuration_service_deleting_action_mapping",
|
||||
mapping_id=mapping_id)
|
||||
|
||||
result = await sdk_bridge_client.delete_action_mapping(mapping_id)
|
||||
|
||||
if not result["success"]:
|
||||
logger.error("action_mapping_delete_failed", error=result.get("error_message"))
|
||||
raise ValueError(f"Action mapping deletion failed: {result.get('error_message')}")
|
||||
|
||||
logger.info("action_mapping_delete_success", mapping_id=mapping_id)
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error("configuration_service_delete_action_mapping_failed", error=str(e), exc_info=True)
|
||||
raise
|
||||
|
||||
async def read_configuration_as_tree(self, max_depth: int = None) -> Dict[str, Any]:
|
||||
"""
|
||||
Read configuration as hierarchical folder tree
|
||||
|
||||
Args:
|
||||
max_depth: Maximum depth to traverse (None = unlimited, 1 = root level only)
|
||||
|
||||
Returns:
|
||||
Dictionary with tree structure
|
||||
"""
|
||||
try:
|
||||
logger.info("configuration_service_reading_tree", max_depth=max_depth)
|
||||
result = await sdk_bridge_client.read_configuration_tree()
|
||||
|
||||
if not result["success"]:
|
||||
logger.error("configuration_tree_read_failed", error=result.get("error_message"))
|
||||
raise ValueError(f"Configuration tree read failed: {result.get('error_message')}")
|
||||
|
||||
tree = result["tree"]
|
||||
|
||||
# Apply depth limit if specified
|
||||
if max_depth is not None:
|
||||
tree = self._limit_tree_depth(tree, max_depth)
|
||||
|
||||
logger.info("configuration_tree_read_success",
|
||||
total_nodes=result["total_nodes"],
|
||||
max_depth=max_depth)
|
||||
|
||||
return tree
|
||||
|
||||
except Exception as e:
|
||||
logger.error("configuration_service_read_tree_failed", error=str(e), exc_info=True)
|
||||
raise
|
||||
|
||||
async def read_configuration_path(self, path: str) -> Dict[str, Any]:
|
||||
"""
|
||||
Read a specific folder from configuration tree
|
||||
|
||||
Args:
|
||||
path: Path to folder (e.g., "MappingRules" or "MappingRules/1")
|
||||
|
||||
Returns:
|
||||
Dictionary with subtree
|
||||
"""
|
||||
try:
|
||||
logger.info("configuration_service_reading_path", path=path)
|
||||
result = await sdk_bridge_client.read_configuration_tree()
|
||||
|
||||
if not result["success"]:
|
||||
logger.error("configuration_tree_read_failed", error=result.get("error_message"))
|
||||
raise ValueError(f"Configuration tree read failed: {result.get('error_message')}")
|
||||
|
||||
tree = result["tree"]
|
||||
|
||||
# Navigate to requested path
|
||||
path_parts = path.split("/")
|
||||
current = tree
|
||||
|
||||
for part in path_parts:
|
||||
if not part: # Skip empty parts
|
||||
continue
|
||||
|
||||
# Find child with matching name
|
||||
if current.get("type") != "folder" or "children" not in current:
|
||||
raise ValueError(f"Path '{path}' not found: '{part}' is not a folder")
|
||||
|
||||
found = None
|
||||
for child in current["children"]:
|
||||
if child.get("name") == part:
|
||||
found = child
|
||||
break
|
||||
|
||||
if found is None:
|
||||
raise ValueError(f"Path '{path}' not found: folder '{part}' does not exist")
|
||||
|
||||
current = found
|
||||
|
||||
logger.info("configuration_path_read_success", path=path)
|
||||
return current
|
||||
|
||||
except ValueError:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error("configuration_service_read_path_failed", path=path, error=str(e), exc_info=True)
|
||||
raise
|
||||
|
||||
def _limit_tree_depth(self, node: Dict[str, Any], max_depth: int, current_depth: int = 0) -> Dict[str, Any]:
|
||||
"""
|
||||
Limit tree depth by removing children beyond max_depth
|
||||
|
||||
Args:
|
||||
node: Tree node
|
||||
max_depth: Maximum depth
|
||||
current_depth: Current depth (internal)
|
||||
|
||||
Returns:
|
||||
Tree node with limited depth
|
||||
"""
|
||||
if current_depth >= max_depth:
|
||||
# At max depth - remove children
|
||||
limited = {k: v for k, v in node.items() if k != "children"}
|
||||
return limited
|
||||
|
||||
# Not at max depth yet - recurse into children
|
||||
result = node.copy()
|
||||
if "children" in node and node.get("type") == "folder":
|
||||
result["children"] = [
|
||||
self._limit_tree_depth(child, max_depth, current_depth + 1)
|
||||
for child in node["children"]
|
||||
]
|
||||
|
||||
return result
|
||||
|
||||
async def create_server(self, server_data: dict) -> dict:
|
||||
"""
|
||||
Create a new G-core server and persist to GeViServer
|
||||
|
||||
Args:
|
||||
server_data: Dictionary with server configuration (id, alias, host, user, password, enabled, etc.)
|
||||
|
||||
Returns:
|
||||
Dictionary with success status and created server
|
||||
"""
|
||||
try:
|
||||
server_id = server_data.get("id")
|
||||
if not server_id:
|
||||
raise ValueError("Server ID is required")
|
||||
|
||||
logger.info("configuration_service_creating_server", server_id=server_id)
|
||||
|
||||
# Read current tree
|
||||
tree_result = await sdk_bridge_client.read_configuration_tree()
|
||||
if not tree_result["success"]:
|
||||
raise ValueError(f"Failed to read configuration tree: {tree_result.get('error_message')}")
|
||||
|
||||
tree = tree_result["tree"]
|
||||
|
||||
# Find GeViGCoreServer folder
|
||||
gcore_folder = self._find_child(tree, "GeViGCoreServer")
|
||||
if not gcore_folder:
|
||||
raise ValueError("GeViGCoreServer folder not found in configuration")
|
||||
|
||||
# Check if server already exists
|
||||
if self._find_child(gcore_folder, server_id):
|
||||
raise ValueError(f"Server '{server_id}' already exists")
|
||||
|
||||
# Create new server folder structure
|
||||
new_server = {
|
||||
"type": "folder",
|
||||
"name": server_id,
|
||||
"children": [
|
||||
{"type": "string", "name": "Alias", "value": server_data.get("alias", "")},
|
||||
{"type": "string", "name": "Host", "value": server_data.get("host", "")},
|
||||
{"type": "string", "name": "User", "value": server_data.get("user", "")},
|
||||
{"type": "string", "name": "Password", "value": server_data.get("password", "")},
|
||||
{"type": "int32", "name": "Enabled", "value": 1 if server_data.get("enabled", True) else 0},
|
||||
{"type": "int32", "name": "DeactivateEcho", "value": 1 if server_data.get("deactivateEcho", False) else 0},
|
||||
{"type": "int32", "name": "DeactivateLiveCheck", "value": 1 if server_data.get("deactivateLiveCheck", False) else 0}
|
||||
]
|
||||
}
|
||||
|
||||
# Add server to GeViGCoreServer folder
|
||||
if "children" not in gcore_folder:
|
||||
gcore_folder["children"] = []
|
||||
gcore_folder["children"].append(new_server)
|
||||
|
||||
# Write modified tree back to GeViServer
|
||||
write_result = await sdk_bridge_client.write_configuration_tree(tree)
|
||||
|
||||
if not write_result["success"]:
|
||||
raise ValueError(f"Failed to write configuration: {write_result.get('error_message')}")
|
||||
|
||||
logger.info("configuration_service_server_created", server_id=server_id,
|
||||
bytes_written=write_result.get("bytes_written"))
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"message": f"Server '{server_id}' created successfully",
|
||||
"server": server_data,
|
||||
"bytes_written": write_result.get("bytes_written")
|
||||
}
|
||||
|
||||
except ValueError:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error("configuration_service_create_server_failed", error=str(e), exc_info=True)
|
||||
raise
|
||||
|
||||
async def update_server(self, server_id: str, server_data: dict) -> dict:
|
||||
"""
|
||||
Update an existing G-core server and persist to GeViServer
|
||||
|
||||
Args:
|
||||
server_id: ID of the server to update
|
||||
server_data: Dictionary with updated server configuration
|
||||
|
||||
Returns:
|
||||
Dictionary with success status
|
||||
"""
|
||||
try:
|
||||
logger.info("configuration_service_updating_server", server_id=server_id)
|
||||
|
||||
# Read current tree
|
||||
tree_result = await sdk_bridge_client.read_configuration_tree()
|
||||
if not tree_result["success"]:
|
||||
raise ValueError(f"Failed to read configuration tree: {tree_result.get('error_message')}")
|
||||
|
||||
tree = tree_result["tree"]
|
||||
|
||||
# Find GeViGCoreServer folder
|
||||
gcore_folder = self._find_child(tree, "GeViGCoreServer")
|
||||
if not gcore_folder:
|
||||
raise ValueError("GeViGCoreServer folder not found in configuration")
|
||||
|
||||
# Find the server to update
|
||||
server_folder = self._find_child(gcore_folder, server_id)
|
||||
if not server_folder:
|
||||
raise ValueError(f"Server '{server_id}' not found")
|
||||
|
||||
# Update server properties
|
||||
children_dict = {c.get("name"): c for c in server_folder.get("children", [])}
|
||||
|
||||
if "alias" in server_data:
|
||||
if "Alias" in children_dict:
|
||||
children_dict["Alias"]["value"] = server_data["alias"]
|
||||
else:
|
||||
server_folder.setdefault("children", []).append(
|
||||
{"type": "string", "name": "Alias", "value": server_data["alias"]}
|
||||
)
|
||||
|
||||
if "host" in server_data:
|
||||
if "Host" in children_dict:
|
||||
children_dict["Host"]["value"] = server_data["host"]
|
||||
else:
|
||||
server_folder.setdefault("children", []).append(
|
||||
{"type": "string", "name": "Host", "value": server_data["host"]}
|
||||
)
|
||||
|
||||
if "user" in server_data:
|
||||
if "User" in children_dict:
|
||||
children_dict["User"]["value"] = server_data["user"]
|
||||
else:
|
||||
server_folder.setdefault("children", []).append(
|
||||
{"type": "string", "name": "User", "value": server_data["user"]}
|
||||
)
|
||||
|
||||
if "password" in server_data:
|
||||
if "Password" in children_dict:
|
||||
children_dict["Password"]["value"] = server_data["password"]
|
||||
else:
|
||||
server_folder.setdefault("children", []).append(
|
||||
{"type": "string", "name": "Password", "value": server_data["password"]}
|
||||
)
|
||||
|
||||
if "enabled" in server_data:
|
||||
enabled_value = 1 if server_data["enabled"] else 0
|
||||
if "Enabled" in children_dict:
|
||||
children_dict["Enabled"]["value"] = enabled_value
|
||||
else:
|
||||
server_folder.setdefault("children", []).append(
|
||||
{"type": "int32", "name": "Enabled", "value": enabled_value}
|
||||
)
|
||||
|
||||
if "deactivateEcho" in server_data:
|
||||
echo_value = 1 if server_data["deactivateEcho"] else 0
|
||||
if "DeactivateEcho" in children_dict:
|
||||
children_dict["DeactivateEcho"]["value"] = echo_value
|
||||
else:
|
||||
server_folder.setdefault("children", []).append(
|
||||
{"type": "int32", "name": "DeactivateEcho", "value": echo_value}
|
||||
)
|
||||
|
||||
if "deactivateLiveCheck" in server_data:
|
||||
livecheck_value = 1 if server_data["deactivateLiveCheck"] else 0
|
||||
if "DeactivateLiveCheck" in children_dict:
|
||||
children_dict["DeactivateLiveCheck"]["value"] = livecheck_value
|
||||
else:
|
||||
server_folder.setdefault("children", []).append(
|
||||
{"type": "int32", "name": "DeactivateLiveCheck", "value": livecheck_value}
|
||||
)
|
||||
|
||||
# Write modified tree back to GeViServer
|
||||
write_result = await sdk_bridge_client.write_configuration_tree(tree)
|
||||
|
||||
if not write_result["success"]:
|
||||
raise ValueError(f"Failed to write configuration: {write_result.get('error_message')}")
|
||||
|
||||
logger.info("configuration_service_server_updated", server_id=server_id,
|
||||
bytes_written=write_result.get("bytes_written"))
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"message": f"Server '{server_id}' updated successfully",
|
||||
"bytes_written": write_result.get("bytes_written")
|
||||
}
|
||||
|
||||
except ValueError:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error("configuration_service_update_server_failed", server_id=server_id, error=str(e), exc_info=True)
|
||||
raise
|
||||
|
||||
async def delete_server(self, server_id: str) -> dict:
|
||||
"""
|
||||
Delete a G-core server and persist to GeViServer
|
||||
|
||||
Args:
|
||||
server_id: ID of the server to delete
|
||||
|
||||
Returns:
|
||||
Dictionary with success status
|
||||
"""
|
||||
try:
|
||||
logger.info("configuration_service_deleting_server", server_id=server_id)
|
||||
|
||||
# Read current tree
|
||||
tree_result = await sdk_bridge_client.read_configuration_tree()
|
||||
if not tree_result["success"]:
|
||||
raise ValueError(f"Failed to read configuration tree: {tree_result.get('error_message')}")
|
||||
|
||||
tree = tree_result["tree"]
|
||||
|
||||
# Find GeViGCoreServer folder
|
||||
gcore_folder = self._find_child(tree, "GeViGCoreServer")
|
||||
if not gcore_folder:
|
||||
raise ValueError("GeViGCoreServer folder not found in configuration")
|
||||
|
||||
# Find and remove the server
|
||||
if "children" not in gcore_folder:
|
||||
raise ValueError(f"Server '{server_id}' not found")
|
||||
|
||||
server_index = None
|
||||
for i, child in enumerate(gcore_folder["children"]):
|
||||
if child.get("name") == server_id and child.get("type") == "folder":
|
||||
server_index = i
|
||||
break
|
||||
|
||||
if server_index is None:
|
||||
raise ValueError(f"Server '{server_id}' not found")
|
||||
|
||||
# Remove server from children list
|
||||
gcore_folder["children"].pop(server_index)
|
||||
|
||||
# Write modified tree back to GeViServer
|
||||
write_result = await sdk_bridge_client.write_configuration_tree(tree)
|
||||
|
||||
if not write_result["success"]:
|
||||
raise ValueError(f"Failed to write configuration: {write_result.get('error_message')}")
|
||||
|
||||
logger.info("configuration_service_server_deleted", server_id=server_id,
|
||||
bytes_written=write_result.get("bytes_written"))
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"message": f"Server '{server_id}' deleted successfully",
|
||||
"bytes_written": write_result.get("bytes_written")
|
||||
}
|
||||
|
||||
except ValueError:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error("configuration_service_delete_server_failed", server_id=server_id, error=str(e), exc_info=True)
|
||||
raise
|
||||
|
||||
def _find_child(self, parent: dict, child_name: str) -> dict:
|
||||
"""
|
||||
Helper method to find a child node by name
|
||||
|
||||
Args:
|
||||
parent: Parent node (folder)
|
||||
child_name: Name of child to find
|
||||
|
||||
Returns:
|
||||
Child node or None if not found
|
||||
"""
|
||||
if parent.get("type") != "folder" or "children" not in parent:
|
||||
return None
|
||||
|
||||
for child in parent["children"]:
|
||||
if child.get("name") == child_name:
|
||||
return child
|
||||
|
||||
return None
|
||||
File diff suppressed because it is too large
Load Diff
298
src/sdk-bridge/Protos/configuration.proto
Normal file
298
src/sdk-bridge/Protos/configuration.proto
Normal file
@@ -0,0 +1,298 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package configuration;
|
||||
|
||||
option csharp_namespace = "GeViScopeBridge.Protos";
|
||||
|
||||
service ConfigurationService {
|
||||
// Read and parse complete configuration from GeViServer
|
||||
rpc ReadConfiguration(ReadConfigurationRequest) returns (ConfigurationResponse);
|
||||
|
||||
// Export configuration as JSON string
|
||||
rpc ExportConfigurationJson(ExportJsonRequest) returns (JsonExportResponse);
|
||||
|
||||
// Modify configuration values and write back to server
|
||||
rpc ModifyConfiguration(ModifyConfigurationRequest) returns (ModifyConfigurationResponse);
|
||||
|
||||
// Import complete configuration from JSON and write to GeViServer
|
||||
rpc ImportConfiguration(ImportConfigurationRequest) returns (ImportConfigurationResponse);
|
||||
|
||||
// SELECTIVE/TARGETED READ METHODS (Fast, lightweight)
|
||||
|
||||
// Read ONLY action mappings (Rules markers) - optimized for speed
|
||||
rpc ReadActionMappings(ReadActionMappingsRequest) returns (ActionMappingsResponse);
|
||||
|
||||
// Read specific markers by name - extensible for future config types
|
||||
rpc ReadSpecificMarkers(ReadSpecificMarkersRequest) returns (SelectiveConfigResponse);
|
||||
|
||||
// ACTION MAPPING WRITE METHODS
|
||||
|
||||
// Create a new action mapping
|
||||
rpc CreateActionMapping(CreateActionMappingRequest) returns (ActionMappingOperationResponse);
|
||||
|
||||
// Update an existing action mapping by ID
|
||||
rpc UpdateActionMapping(UpdateActionMappingRequest) returns (ActionMappingOperationResponse);
|
||||
|
||||
// Delete an action mapping by ID
|
||||
rpc DeleteActionMapping(DeleteActionMappingRequest) returns (ActionMappingOperationResponse);
|
||||
|
||||
// SERVER CONFIGURATION WRITE METHODS (G-CORE SERVERS)
|
||||
|
||||
// Create a new G-core server
|
||||
rpc CreateServer(CreateServerRequest) returns (ServerOperationResponse);
|
||||
|
||||
// Update an existing G-core server
|
||||
rpc UpdateServer(UpdateServerRequest) returns (ServerOperationResponse);
|
||||
|
||||
// Delete a G-core server
|
||||
rpc DeleteServer(DeleteServerRequest) returns (ServerOperationResponse);
|
||||
|
||||
// TREE FORMAT (RECOMMENDED)
|
||||
|
||||
// Read configuration as hierarchical folder tree - much more readable than flat format
|
||||
rpc ReadConfigurationTree(ReadConfigurationTreeRequest) returns (ConfigurationTreeResponse);
|
||||
|
||||
// REGISTRY EXPLORATION METHODS
|
||||
|
||||
// List top-level registry nodes
|
||||
rpc ListRegistryNodes(ListRegistryNodesRequest) returns (RegistryNodesResponse);
|
||||
|
||||
// Get details about a specific registry node
|
||||
rpc GetRegistryNodeDetails(GetRegistryNodeDetailsRequest) returns (RegistryNodeDetailsResponse);
|
||||
|
||||
// Search for action mapping paths in registry
|
||||
rpc SearchActionMappingPaths(SearchActionMappingPathsRequest) returns (ActionMappingPathsResponse);
|
||||
}
|
||||
|
||||
message ReadConfigurationRequest {
|
||||
// Empty - uses connection from setup client
|
||||
}
|
||||
|
||||
message ConfigurationStatistics {
|
||||
int32 total_nodes = 1;
|
||||
int32 boolean_count = 2;
|
||||
int32 integer_count = 3;
|
||||
int32 string_count = 4;
|
||||
int32 property_count = 5;
|
||||
int32 marker_count = 6;
|
||||
int32 rules_section_count = 7;
|
||||
}
|
||||
|
||||
message ConfigNode {
|
||||
int32 start_offset = 1;
|
||||
int32 end_offset = 2;
|
||||
string node_type = 3; // "boolean", "integer", "string", "property", "marker"
|
||||
string name = 4;
|
||||
string value = 5; // Serialized as string
|
||||
string value_type = 6;
|
||||
}
|
||||
|
||||
message ConfigurationResponse {
|
||||
bool success = 1;
|
||||
string error_message = 2;
|
||||
int32 file_size = 3;
|
||||
string header = 4;
|
||||
repeated ConfigNode nodes = 5;
|
||||
ConfigurationStatistics statistics = 6;
|
||||
}
|
||||
|
||||
message ExportJsonRequest {
|
||||
// Empty - exports current configuration
|
||||
}
|
||||
|
||||
message JsonExportResponse {
|
||||
bool success = 1;
|
||||
string error_message = 2;
|
||||
string json_data = 3;
|
||||
int32 json_size = 4;
|
||||
}
|
||||
|
||||
message NodeModification {
|
||||
int32 start_offset = 1;
|
||||
string node_type = 2; // "boolean", "integer", "string"
|
||||
string new_value = 3; // Serialized as string
|
||||
}
|
||||
|
||||
message ModifyConfigurationRequest {
|
||||
repeated NodeModification modifications = 1;
|
||||
}
|
||||
|
||||
message ModifyConfigurationResponse {
|
||||
bool success = 1;
|
||||
string error_message = 2;
|
||||
int32 modifications_applied = 3;
|
||||
}
|
||||
|
||||
message ImportConfigurationRequest {
|
||||
string json_data = 1; // Complete configuration as JSON string
|
||||
}
|
||||
|
||||
message ImportConfigurationResponse {
|
||||
bool success = 1;
|
||||
string error_message = 2;
|
||||
int32 bytes_written = 3;
|
||||
int32 nodes_imported = 4;
|
||||
}
|
||||
|
||||
// ========== SELECTIVE READ MESSAGES ==========
|
||||
|
||||
message ReadActionMappingsRequest {
|
||||
// Empty - reads action mappings from current configuration
|
||||
}
|
||||
|
||||
message ActionParameter {
|
||||
string name = 1; // Parameter name (e.g., "VideoInput", "G-core alias")
|
||||
string value = 2; // Parameter value (e.g., "101027", "gscope-cdu-3")
|
||||
}
|
||||
|
||||
message ActionDefinition {
|
||||
string action = 1; // Action name (e.g., "CrossSwitch C_101027 -> M")
|
||||
repeated ActionParameter parameters = 2; // Named parameters
|
||||
}
|
||||
|
||||
message ConfigActionMapping {
|
||||
string name = 1; // Mapping name (e.g., "CrossSwitch C_101027 -> M")
|
||||
repeated ActionDefinition input_actions = 2; // Trigger/condition actions
|
||||
repeated ActionDefinition output_actions = 3; // Response actions
|
||||
int32 start_offset = 4;
|
||||
int32 end_offset = 5;
|
||||
|
||||
// Deprecated - kept for backward compatibility
|
||||
repeated string actions = 6; // List of action strings (old format)
|
||||
}
|
||||
|
||||
message ActionMappingsResponse {
|
||||
bool success = 1;
|
||||
string error_message = 2;
|
||||
repeated ConfigActionMapping mappings = 3;
|
||||
int32 total_count = 4;
|
||||
}
|
||||
|
||||
message ReadSpecificMarkersRequest {
|
||||
repeated string marker_names = 1; // Names of markers to extract (e.g., "Rules", "Camera")
|
||||
}
|
||||
|
||||
message SelectiveConfigResponse {
|
||||
bool success = 1;
|
||||
string error_message = 2;
|
||||
int32 file_size = 3;
|
||||
repeated string requested_markers = 4;
|
||||
repeated ConfigNode extracted_nodes = 5;
|
||||
int32 markers_found = 6;
|
||||
}
|
||||
|
||||
// ========== ACTION MAPPING WRITE MESSAGES ==========
|
||||
|
||||
message ActionMappingInput {
|
||||
string name = 1; // Mapping caption (required for GeViSet display)
|
||||
repeated ActionDefinition input_actions = 2; // Trigger actions
|
||||
repeated ActionDefinition output_actions = 3; // Response actions (required)
|
||||
int32 video_input = 4; // Video input ID (optional, but recommended for GeViSet display)
|
||||
}
|
||||
|
||||
message CreateActionMappingRequest {
|
||||
ActionMappingInput mapping = 1;
|
||||
}
|
||||
|
||||
message UpdateActionMappingRequest {
|
||||
int32 mapping_id = 1; // 1-based ID of mapping to update
|
||||
ActionMappingInput mapping = 2; // New data (fields can be partial)
|
||||
}
|
||||
|
||||
message DeleteActionMappingRequest {
|
||||
int32 mapping_id = 1; // 1-based ID of mapping to delete
|
||||
}
|
||||
|
||||
message ActionMappingOperationResponse {
|
||||
bool success = 1;
|
||||
string error_message = 2;
|
||||
ConfigActionMapping mapping = 3; // Created/updated mapping (null for delete)
|
||||
string message = 4; // Success/info message
|
||||
}
|
||||
|
||||
// REGISTRY EXPLORATION MESSAGES
|
||||
|
||||
message ListRegistryNodesRequest {
|
||||
// Empty - lists top-level nodes
|
||||
}
|
||||
|
||||
message RegistryNodesResponse {
|
||||
bool success = 1;
|
||||
repeated string node_paths = 2;
|
||||
string error_message = 3;
|
||||
}
|
||||
|
||||
message GetRegistryNodeDetailsRequest {
|
||||
string node_path = 1;
|
||||
}
|
||||
|
||||
message RegistryNodeDetailsResponse {
|
||||
bool success = 1;
|
||||
string details = 2;
|
||||
string error_message = 3;
|
||||
}
|
||||
|
||||
message SearchActionMappingPathsRequest {
|
||||
// Empty - searches for action mapping related nodes
|
||||
}
|
||||
|
||||
message ActionMappingPathsResponse {
|
||||
bool success = 1;
|
||||
repeated string paths = 2;
|
||||
string error_message = 3;
|
||||
}
|
||||
|
||||
// ========== SERVER CRUD MESSAGES ==========
|
||||
|
||||
message ServerData {
|
||||
string id = 1; // Server ID (folder name in GeViGCoreServer)
|
||||
string alias = 2; // Alias (display name)
|
||||
string host = 3; // Host/IP address
|
||||
string user = 4; // Username
|
||||
string password = 5; // Password
|
||||
bool enabled = 6; // Enabled flag
|
||||
bool deactivate_echo = 7; // DeactivateEcho flag
|
||||
bool deactivate_live_check = 8; // DeactivateLiveCheck flag
|
||||
}
|
||||
|
||||
message CreateServerRequest {
|
||||
ServerData server = 1;
|
||||
}
|
||||
|
||||
message UpdateServerRequest {
|
||||
string server_id = 1; // ID of server to update
|
||||
ServerData server = 2; // New server data (fields can be partial)
|
||||
}
|
||||
|
||||
message DeleteServerRequest {
|
||||
string server_id = 1; // ID of server to delete
|
||||
}
|
||||
|
||||
message ServerOperationResponse {
|
||||
bool success = 1;
|
||||
string error_message = 2;
|
||||
ServerData server = 3; // Created/updated server (null for delete)
|
||||
string message = 4; // Success/info message
|
||||
int32 bytes_written = 5; // Size of configuration written
|
||||
}
|
||||
|
||||
// ========== TREE FORMAT MESSAGES ==========
|
||||
|
||||
message ReadConfigurationTreeRequest {
|
||||
// Empty - reads entire configuration as tree
|
||||
}
|
||||
|
||||
message TreeNode {
|
||||
string type = 1; // "folder", "bool", "byte", "int16", "int32", "int64", "string"
|
||||
string name = 2; // Node name
|
||||
int64 int_value = 3; // For integer/bool types
|
||||
string string_value = 4; // For string types
|
||||
repeated TreeNode children = 5; // For folders (hierarchical structure)
|
||||
}
|
||||
|
||||
message ConfigurationTreeResponse {
|
||||
bool success = 1;
|
||||
string error_message = 2;
|
||||
TreeNode root = 3; // Root folder node containing entire configuration tree
|
||||
int32 total_nodes = 4; // Total node count (all levels)
|
||||
}
|
||||
Reference in New Issue
Block a user