connection fixes

This commit is contained in:
2025-10-06 09:41:23 +09:00
parent 4ceccae6ce
commit fa55367e68
361 changed files with 24633 additions and 6206 deletions

0
docs/ANDROID_APP_FIX.md Normal file
View File

View File

View File

View File

0
docs/BUGFIX_REPORT.md Normal file
View File

View File

View File

@@ -1,316 +0,0 @@
# ConnectionManager API Документация
## Обзор
`ConnectionManager` - это центральный компонент системы GodEye Signal Center, который управляет полным жизненным циклом подключений между операторами и Android устройствами. Он обеспечивает надежное создание, управление и завершение подключений с таймаутами и валидацией.
## Архитектура
```
Desktop Operator ←→ ConnectionManager ←→ Android Device
SessionManager
DeviceManager
```
### Основные компоненты:
- **ConnectionManager**: Управление подключениями и их жизненным циклом
- **DeviceManager**: Управление устройствами и операторами
- **SessionManager**: Управление WebRTC сессиями
- **Socket.IO**: Транспорт для событий подключения
## События WebSocket
### Новые события ConnectionManager
#### `connection:initiated`
Подключение инициировано ConnectionManager
```javascript
{
connectionId: "conn_uuid",
sessionId: "session_uuid",
deviceId: "device_id",
cameraType: "back",
status: "pending",
createdAt: "2023-..."
}
```
#### `connection:accepted`
Устройство приняло запрос подключения
```javascript
{
connectionId: "conn_uuid",
sessionId: "session_uuid",
deviceId: "device_id",
cameraType: "back",
streamUrl: "webrtc_stream_url",
status: "active"
}
```
#### `connection:rejected`
Устройство отклонило запрос подключения
```javascript
{
sessionId: "session_uuid",
deviceId: "device_id",
cameraType: "back",
error: "Device camera is busy"
}
```
#### `connection:terminated`
Подключение завершено
```javascript
{
connectionId: "conn_uuid",
timestamp: "2023-..."
}
```
#### `connection:error`
Ошибка подключения
```javascript
{
error: "Error message"
}
```
### Команды от клиента
#### `connection:terminate`
Завершить подключение
```javascript
{
connectionId: "conn_uuid"
}
```
#### `connection:status`
Запросить статистику подключений
```javascript
{} // Ответ в callback или connection:status_response
```
#### `connection:list`
Список подключений оператора
```javascript
{} // Ответ в callback или connection:list_response
```
## Desktop Operator API
### Новые методы
#### `terminateConnection(connectionId, sessionId)`
Завершает подключение через ConnectionManager
```javascript
operator.terminateConnection('conn_123', 'session_456');
```
#### `getConnectionStatus()`
Получает статистику всех подключений системы
```javascript
operator.getConnectionStatus();
```
#### `listMyConnections()`
Получает список подключений текущего оператора
```javascript
operator.listMyConnections();
```
### Обновленные методы
#### `requestCamera(deviceId, cameraType)`
Теперь использует ConnectionManager для создания подключений
```javascript
operator.requestCamera('device_123', 'back');
```
## Backend ConnectionManager API
### Основные методы
#### `async initiateConnection(operatorId, deviceId, cameraType)`
Инициирует новое подключение между оператором и устройством
```javascript
const connection = await connectionManager.initiateConnection(
'operator_123',
'device_456',
'back'
);
```
#### `async acceptConnection(sessionId, metadata)`
Принимает подключение со стороны устройства
```javascript
const connection = await connectionManager.acceptConnection(
'session_123',
{ streamUrl: 'webrtc://...' }
);
```
#### `async rejectConnection(sessionId, reason)`
Отклоняет подключение
```javascript
await connectionManager.rejectConnection(
'session_123',
'Camera is busy'
);
```
#### `async terminateConnection(connectionId)`
Завершает активное подключение
```javascript
await connectionManager.terminateConnection('conn_123');
```
### Утилиты
#### `getConnection(sessionId)`
Получает подключение по ID сессии
```javascript
const connection = connectionManager.getConnection('session_123');
```
#### `getConnectionStats()`
Получает статистику всех подключений
```javascript
const stats = connectionManager.getConnectionStats();
// { total: 5, active: 2, pending: 1, completed: 2 }
```
#### `getOperatorConnections(operatorId)`
Получает все подключения оператора
```javascript
const connections = connectionManager.getOperatorConnections('operator_123');
```
#### `cleanup*()`
Методы очистки подключений при отключении участников
```javascript
connectionManager.cleanupDeviceConnections('device_123');
connectionManager.cleanupOperatorConnections('operator_456');
```
## Жизненный цикл подключения
### 1. Инициирование подключения
```
Desktop Operator → camera:request → ConnectionManager.initiateConnection()
Создание Connection объекта
Отправка camera:request → Android Device
Desktop Operator ← connection:initiated ← ConnectionManager
```
### 2. Ответ устройства
```
Android Device → camera:response → ConnectionManager.acceptConnection()
Обновление Connection статуса
Desktop Operator ← connection:accepted ← ConnectionManager
Инициирование WebRTC
```
### 3. Завершение подключения
```
Desktop Operator → connection:terminate → ConnectionManager.terminateConnection()
Очистка ресурсов
connection:terminated ← ConnectionManager
```
## Конфигурация таймаутов
```javascript
// В ConnectionManager.js
CONNECTION_TIMEOUT: 30000, // 30 секунд на установку подключения
CLEANUP_INTERVAL: 60000 // Очистка каждую минуту
```
## Обратная совместимость
Система поддерживает старые события для совместимости:
- `session:created``connection:initiated`
- `session:accepted``connection:accepted`
- `session:rejected``connection:rejected`
- `camera:response` (продолжает работать)
## Логирование
ConnectionManager использует Winston logger для отслеживания:
- ✅ Успешные подключения
- ❌ Ошибки и отклонения
- 🔄 Переходы состояний
- ⏰ Таймауты подключений
- 🧹 Операции очистки
## Примеры использования
### Полный цикл подключения от Desktop Operator
```javascript
// 1. Инициирование подключения
operator.requestCamera('device_123', 'back');
// 2. Обработка ответа
operator.socket.on('connection:accepted', (data) => {
console.log('Подключение установлено:', data.connectionId);
// Запускаем WebRTC...
});
// 3. Завершение подключения
operator.terminateConnection(connectionId, sessionId);
```
### Мониторинг подключений
```javascript
// Получение статистики
operator.getConnectionStatus();
// Список моих подключений
operator.listMyConnections();
// Обработка ошибок
operator.socket.on('connection:error', (data) => {
console.error('Ошибка подключения:', data.error);
});
```
## Миграция с старой системы
Старые методы продолжают работать, но рекомендуется переход на новые:
### Было:
```javascript
operator.socket.on('session:created', ...);
operator.socket.on('session:accepted', ...);
```
### Стало:
```javascript
operator.socket.on('connection:initiated', ...);
operator.socket.on('connection:accepted', ...);
```
### UI обновления
- Кнопки завершения сессий теперь используют `terminateConnection()`
- Статус подключений отображается с `connectionId`
- Добавлены индикаторы состояния подключений
---
Для дополнительной информации см. исходный код:
- `/backend/src/managers/ConnectionManager.js`
- `/backend/src/server.js` (обработчики событий)
- `/desktop-operator/src/renderer/app.js` (клиентские методы)

View File

0
docs/DEPLOYMENT_GUIDE.md Normal file
View File

View File

View File

View File

View File

@@ -1,288 +0,0 @@
# Руководство: Подключение Desktop Operator к Android телефону
## 🔗 Как работает подключение оператора к телефону
### Архитектура подключения
```
Desktop Operator ←→ WebSocket ←→ Сервер ←→ WebSocket ←→ Android телефон
ConnectionManager
(управляет соединениями)
WebRTC P2P соединение
(прямая передача видео)
```
### 1. 📱 Регистрация Android устройства
**Android телефон подключается к серверу:**
```kotlin
// Android код
val socket = IO.socket("ws://192.168.1.100:3001")
socket.emit("register:android", JSONObject().apply {
put("deviceId", "android_unique_id")
put("deviceInfo", JSONObject().apply {
put("manufacturer", "Samsung")
put("model", "Galaxy S21")
put("androidVersion", "11")
put("availableCameras", JSONArray(listOf("back", "front", "ultra_wide")))
put("appVersion", "1.0.0")
})
})
```
**Сервер подтверждает регистрацию:**
```javascript
// Лог сервера
{"level":"info","message":"Android client registered: android_unique_id","timestamp":"..."}
```
### 2. 💻 Подключение Desktop Operator
**Operator приложение подключается:**
```javascript
// Desktop Operator код
const socket = io('ws://192.168.1.100:3001');
socket.emit('register:operator', {
operatorId: 'operator-uuid',
operatorInfo: {
name: 'Иван Петров',
organization: 'Служба безопасности',
permissions: ['view_cameras', 'request_camera', 'initiate_connection']
}
});
```
### 3. 🔍 Проверка доступных устройств
**REST API запрос списка устройств:**
```bash
curl -H "x-operator-id: operator-uuid" \
http://localhost:3001/api/operators/devices
```
**Ответ сервера:**
```json
{
"success": true,
"devices": [
{
"deviceId": "android_unique_id",
"model": "Galaxy S21",
"manufacturer": "Samsung",
"isConnected": true,
"availableCameras": ["back", "front", "ultra_wide"],
"canAcceptNewSession": true,
"activeSessions": 0
}
],
"total": 1
}
```
### 4. 📞 Инициация подключения к телефону
**Оператор запрашивает доступ к камере:**
```bash
curl -X POST http://localhost:3001/api/operators/connections/request \
-H "Content-Type: application/json" \
-H "x-operator-id: operator-uuid" \
-d '{
"deviceId": "android_unique_id",
"cameraType": "back"
}'
```
**Сервер создает подключение:**
```json
{
"success": true,
"connectionId": "conn-uuid",
"sessionId": "session-uuid",
"message": "Connection request initiated"
}
```
### 5. 📲 Android получает запрос подтверждения
**WebSocket событие на Android:**
```javascript
// Сервер → Android
socket.emit('connection:request', {
connectionId: 'conn-uuid',
sessionId: 'session-uuid',
operatorId: 'operator-uuid',
operatorInfo: {
name: 'Иван Петров',
organization: 'Служба безопасности',
reason: 'Проверка безопасности'
},
cameraType: 'back',
timestamp: '2025-10-04T12:00:00.000Z',
expiresAt: '2025-10-04T12:05:00.000Z' // 5 минут на ответ
});
```
**Android показывает диалог пользователю:**
```
┌─────────────────────────────────┐
│ Запрос доступа к камере │
├─────────────────────────────────┤
│ Оператор: Иван Петров │
│ Организация: Служба безопасности│
│ Причина: Проверка безопасности │
│ Камера: Задняя │
│ │
│ Разрешить доступ к камере? │
│ │
│ [Разрешить] [Отклонить] │
└─────────────────────────────────┘
```
### 6. ✅ Пользователь принимает/отклоняет запрос
**Если пользователь принимает:**
```kotlin
// Android → Сервер
socket.emit("connection:accept", JSONObject().apply {
put("connectionId", connectionId)
put("sessionId", sessionId)
put("cameraType", "back")
put("webrtcInfo", JSONObject().apply {
put("supported", true)
put("codecs", JSONArray(listOf("H264", "VP8")))
put("resolutions", JSONArray(listOf("720p", "1080p")))
})
})
```
**Сервер уведомляет оператора:**
```javascript
// Сервер → Desktop Operator
socket.emit('connection:accepted', {
connectionId: 'conn-uuid',
sessionId: 'session-uuid',
webrtcInfo: {
supported: true,
codecs: ['H264', 'VP8'],
resolutions: ['720p', '1080p']
}
});
```
### 7. 🎥 Установка WebRTC соединения
**Обмен WebRTC сигналами:**
```
Desktop Operator → Сервер → Android: webrtc:offer
Android → Сервер → Desktop Operator: webrtc:answer
Desktop Operator ↔ Сервер ↔ Android: webrtc:ice-candidate
```
**После успешного установления WebRTC:**
```
Desktop Operator ←-----WebRTC P2P-----→ Android
(прямое видео)
```
## 🧪 Тестирование подключения
### Проверка 1: Статус системы
```bash
curl http://localhost:3001/api/status | jq
```
### Проверка 2: Список устройств
```bash
curl -H "x-operator-id: YOUR_OPERATOR_ID" \
http://localhost:3001/api/operators/devices | jq
```
### Проверка 3: Инициация подключения
```bash
curl -X POST http://localhost:3001/api/operators/connections/request \
-H "Content-Type: application/json" \
-H "x-operator-id: YOUR_OPERATOR_ID" \
-d '{
"deviceId": "android_device_id",
"cameraType": "back"
}' | jq
```
### Проверка 4: Статус подключений
```bash
curl -H "x-operator-id: YOUR_OPERATOR_ID" \
http://localhost:3001/api/operators/connections | jq
```
## 🐞 Диагностика проблем
### Проблема: "Invalid or disconnected operator"
**Причина:** Оператор не подключен к WebSocket
**Решение:**
1. Откройте веб-демо: http://localhost:3001
2. Проверьте WebSocket подключение в консоли браузера
3. Используйте Operator ID из консоли
### Проблема: "Device not found"
**Причина:** Android устройство не подключено
**Решение:**
1. Перезапустите Android приложение
2. Проверьте сетевое соединение
3. Убедитесь что устройство регистрируется
### Проблема: "Device busy or unavailable"
**Причина:** Устройство занято другой сессией
**Решение:**
1. Завершите активные сессии
2. Подождите таймаут (30 секунд)
3. Попробуйте снова
## 📊 Мониторинг соединений
### Логи сервера
```bash
tail -f /home/data/god_eye/backend/god-eye.log
```
### Административная статистика
```bash
curl http://localhost:3001/api/admin/stats | jq
```
### Real-time статус через WebSocket
```javascript
socket.on('device:connected', (data) => {
console.log('Устройство подключено:', data.deviceId);
});
socket.on('connection:accepted', (data) => {
console.log('Подключение принято:', data.connectionId);
});
```
## 🔒 Безопасность
1. **Разрешения пользователя:** Android требует подтверждения каждого запроса
2. **Таймауты:** Запросы автоматически истекают через 5 минут
3. **Аутентификация:** Проверка Operator ID для всех API запросов
4. **Логирование:** Все операции записываются в логи
## 🚀 Быстрый старт
1. **Запустите сервер:**
```bash
cd /home/data/god_eye/backend && npm start
```
2. **Откройте веб-демо:**
http://localhost:3001
3. **Запустите Android приложение** и подключите к серверу
4. **Инициируйте подключение** через веб-интерфейс или API
5. **Примите запрос** на Android устройстве
6. **Наслаждайтесь** прямым WebRTC видеопотоком!

View File

View File

@@ -1,484 +0,0 @@
# Протокол запросов от сервера к Android устройству
## Обзор
Данный документ описывает протокол WebSocket событий, которые сервер отправляет на Android устройство для запроса подтверждения подключения оператора и открытия сеанса камеры.
## Схема работы
1. **Оператор инициирует подключение** через REST API или WebSocket
2. **Сервер создает соединение** в ConnectionManager
3. **Сервер отправляет запрос на Android** через WebSocket
4. **Android отображает диалог** пользователю
5. **Пользователь принимает/отклоняет** запрос
6. **Android отправляет ответ** серверу
7. **Сервер уведомляет оператора** о результате
## События от сервера к Android
### 1. `connection:request` - Запрос на подключение
Отправляется Android устройству когда оператор запрашивает доступ к камере.
```javascript
// Сервер → Android
socket.emit('connection:request', {
connectionId: 'uuid-connection-id',
sessionId: 'uuid-session-id',
operatorId: 'uuid-operator-id',
operatorInfo: {
name: 'Имя оператора',
organization: 'Организация',
reason: 'Причина запроса доступа'
},
cameraType: 'back', // 'back', 'front', 'wide', 'telephoto'
timestamp: '2025-10-04T12:00:00.000Z',
expiresAt: '2025-10-04T12:05:00.000Z' // Время истечения запроса (5 минут)
});
```
**Ожидаемый ответ от Android:**
- `connection:accept` - пользователь принял запрос
- `connection:reject` - пользователь отклонил запрос
- Timeout через 5 минут если нет ответа
### 2. `camera:request` - Запрос доступа к камере (Legacy)
Для совместимости со старой системой. Используется при прямом запросе камеры.
```javascript
// Сервер → Android
socket.emit('camera:request', {
sessionId: 'uuid-session-id',
operatorId: 'uuid-operator-id',
cameraType: 'back',
timestamp: '2025-10-04T12:00:00.000Z'
});
```
### 3. `camera:switch` - Переключение камеры
Запрос на переключение камеры во время активного сеанса.
```javascript
// Сервер → Android
socket.emit('camera:switch', {
sessionId: 'uuid-session-id',
cameraType: 'front', // Новый тип камеры
timestamp: '2025-10-04T12:00:00.000Z'
});
```
### 4. `camera:disconnect` - Завершение сеанса
Уведомление о завершении сеанса камеры.
```javascript
// Сервер → Android
socket.emit('camera:disconnect', {
sessionId: 'uuid-session-id',
reason: 'operator_disconnect', // 'operator_disconnect', 'timeout', 'error'
timestamp: '2025-10-04T12:00:00.000Z'
});
```
## События от Android к серверу
### 1. `connection:accept` - Принятие подключения
```javascript
// Android → Сервер
socket.emit('connection:accept', {
connectionId: 'uuid-connection-id',
sessionId: 'uuid-session-id',
cameraType: 'back',
webrtcInfo: {
supported: true,
codecs: ['H264', 'VP8'],
resolutions: ['720p', '1080p']
},
timestamp: '2025-10-04T12:00:00.000Z'
});
```
### 2. `connection:reject` - Отклонение подключения
```javascript
// Android → Сервер
socket.emit('connection:reject', {
connectionId: 'uuid-connection-id',
reason: 'user_denied', // 'user_denied', 'camera_busy', 'permission_denied'
timestamp: '2025-10-04T12:00:00.000Z'
});
```
### 3. `camera:response` - Ответ на запрос камеры (Legacy)
```javascript
// Android → Сервер
socket.emit('camera:response', {
sessionId: 'uuid-session-id',
accepted: true, // true/false
reason: 'camera_granted', // или причина отказа
cameraType: 'back',
timestamp: '2025-10-04T12:00:00.000Z'
});
```
## Жизненный цикл подключения
### Успешное подключение
```mermaid
sequenceDiagram
participant O as Оператор
participant S as Сервер
participant A as Android
O->>S: POST /api/operators/connections/request
S->>S: Создание connection в ConnectionManager
S->>A: connection:request
A->>A: Показ диалога пользователю
A->>S: connection:accept
S->>S: Обновление connection (status: accepted)
S->>O: connection:accepted (WebSocket)
Note over O,A: Начало WebRTC сеанса
```
### Отклонение подключения
```mermaid
sequenceDiagram
participant O as Оператор
participant S as Сервер
participant A as Android
O->>S: POST /api/operators/connections/request
S->>S: Создание connection в ConnectionManager
S->>A: connection:request
A->>A: Показ диалога пользователю
A->>S: connection:reject
S->>S: Обновление connection (status: rejected)
S->>O: connection:rejected (WebSocket)
```
### Таймаут подключения
```mermaid
sequenceDiagram
participant O as Оператор
participant S as Сервер
participant A as Android
O->>S: POST /api/operators/connections/request
S->>S: Создание connection в ConnectionManager
S->>A: connection:request
Note over A: Пользователь не отвечает
S->>S: Timeout через 5 минут
S->>S: Обновление connection (status: timeout)
S->>O: connection:timeout (WebSocket)
S->>A: connection:timeout (уведомление)
```
## Обработка в ConnectionManager
### Инициация подключения
```javascript
// В файле /backend/src/managers/ConnectionManager.js
async initiateConnection(operatorId, deviceId, cameraType = 'back') {
// 1. Создание connection объекта
const connection = {
connectionId: uuidv4(),
sessionId: uuidv4(),
operatorId,
deviceId,
cameraType,
status: 'pending',
createdAt: new Date().toISOString(),
expiresAt: new Date(Date.now() + 5 * 60 * 1000).toISOString()
};
// 2. Сохранение в память
this.connections.set(connection.connectionId, connection);
// 3. Отправка запроса на Android
const device = this.deviceManager.getDevice(deviceId);
device.socket.emit('connection:request', {
connectionId: connection.connectionId,
sessionId: connection.sessionId,
operatorId,
operatorInfo: operator.operatorInfo,
cameraType,
timestamp: connection.createdAt,
expiresAt: connection.expiresAt
});
// 4. Установка таймаута
setTimeout(() => {
if (connection.status === 'pending') {
this.handleConnectionTimeout(connection.connectionId);
}
}, 5 * 60 * 1000);
return connection;
}
```
### Принятие подключения
```javascript
async acceptConnection(connectionId, responseData) {
const connection = this.connections.get(connectionId);
// Обновление статуса
connection.status = 'accepted';
connection.acceptedAt = new Date().toISOString();
connection.webrtcInfo = responseData.webrtcInfo;
// Создание сессии
const session = this.sessionManager.createSession(
connection.deviceId,
connection.operatorId,
connection.cameraType
);
// Уведомление оператора
const operator = this.deviceManager.getOperator(connection.operatorId);
operator.socket.emit('connection:accepted', {
connectionId,
sessionId: session.sessionId,
webrtcInfo: connection.webrtcInfo
});
return connection;
}
```
## Обработка в Android приложении
### Регистрация обработчиков событий
```kotlin
// В Android клиенте
socket.on("connection:request") { args ->
val data = args[0] as JSONObject
val connectionId = data.getString("connectionId")
val operatorInfo = data.getJSONObject("operatorInfo")
val cameraType = data.getString("cameraType")
// Показ диалога пользователю
showConnectionRequestDialog(connectionId, operatorInfo, cameraType)
}
socket.on("camera:request") { args ->
val data = args[0] as JSONObject
val sessionId = data.getString("sessionId")
val operatorId = data.getString("operatorId")
val cameraType = data.getString("cameraType")
// Legacy обработка для совместимости
handleCameraRequest(sessionId, operatorId, cameraType)
}
```
### Ответ на запрос подключения
```kotlin
private fun acceptConnection(connectionId: String, cameraType: String) {
val response = JSONObject().apply {
put("connectionId", connectionId)
put("sessionId", sessionId)
put("cameraType", cameraType)
put("webrtcInfo", JSONObject().apply {
put("supported", true)
put("codecs", JSONArray(listOf("H264", "VP8")))
put("resolutions", JSONArray(listOf("720p", "1080p")))
})
put("timestamp", Instant.now().toString())
}
socket.emit("connection:accept", response)
// Начало подготовки камеры
startCameraPreview(cameraType)
}
private fun rejectConnection(connectionId: String, reason: String) {
val response = JSONObject().apply {
put("connectionId", connectionId)
put("reason", reason)
put("timestamp", Instant.now().toString())
}
socket.emit("connection:reject", response)
}
```
## UI диалог на Android
### Пример диалога подтверждения
```kotlin
private fun showConnectionRequestDialog(
connectionId: String,
operatorInfo: JSONObject,
cameraType: String
) {
val dialog = AlertDialog.Builder(this)
.setTitle("Запрос доступа к камере")
.setMessage("""
Оператор: ${operatorInfo.getString("name")}
Организация: ${operatorInfo.getString("organization")}
Причина: ${operatorInfo.getString("reason")}
Камера: ${getCameraDisplayName(cameraType)}
Разрешить доступ к камере?
""".trimIndent())
.setPositiveButton("Разрешить") { _, _ ->
acceptConnection(connectionId, cameraType)
}
.setNegativeButton("Отклонить") { _, _ ->
rejectConnection(connectionId, "user_denied")
}
.setCancelable(false)
.create()
dialog.show()
// Автоматическое закрытие через 5 минут
Handler(Looper.getMainLooper()).postDelayed({
if (dialog.isShowing) {
dialog.dismiss()
rejectConnection(connectionId, "timeout")
}
}, 5 * 60 * 1000)
}
```
## Безопасность и валидация
### Проверки на сервере
1. **Валидация оператора**: проверка разрешений и статуса подключения
2. **Валидация устройства**: проверка доступности и возможности принять сессию
3. **Лимиты времени**: автоматическое завершение запросов через 5 минут
4. **Лимиты сессий**: проверка максимального количества активных сессий
### Проверки на Android
1. **Валидация connectionId**: проверка существования активного запроса
2. **Проверка разрешений**: доступ к камере и микрофону
3. **Проверка состояния**: доступность камеры для использования
4. **Защита от спама**: лимит на количество запросов в минуту
## Логирование и мониторинг
### События для логирования
```javascript
// Сервер
logger.info('Connection request initiated', {
connectionId,
operatorId,
deviceId,
cameraType
});
logger.info('Connection accepted by device', {
connectionId,
sessionId,
responseTime: Date.now() - connection.createdAt
});
logger.warn('Connection rejected by device', {
connectionId,
reason,
operatorId,
deviceId
});
logger.error('Connection timeout', {
connectionId,
operatorId,
deviceId,
duration: 5 * 60 * 1000
});
```
### Метрики для мониторинга
- Время ответа Android устройств на запросы
- Процент принятых/отклоненных подключений
- Количество таймаутов
- Средняя продолжительность сессий
- Ошибки WebRTC соединений
## Совместимость
Система поддерживает как новый протокол подключений (`connection:*` события), так и старый протокол (`camera:*` события) для обратной совместимости.
### Миграция со старого протокола
1. **Этап 1**: Добавление поддержки новых событий в Android
2. **Этап 2**: Постепенный переход операторов на новый API
3. **Этап 3**: Удаление старых обработчиков после полной миграции
## Примеры использования
### Тестирование через WebSocket
```javascript
// Подключение к серверу
const socket = io('ws://localhost:3001');
// Симуляция Android устройства
socket.emit('register:android', {
deviceId: 'test-device-001',
deviceInfo: {
manufacturer: 'Samsung',
model: 'Galaxy S21',
availableCameras: ['back', 'front'],
androidVersion: '11'
}
});
// Обработка запросов
socket.on('connection:request', (data) => {
console.log('Получен запрос подключения:', data);
// Автоматическое принятие для тестирования
setTimeout(() => {
socket.emit('connection:accept', {
connectionId: data.connectionId,
sessionId: data.sessionId,
cameraType: data.cameraType,
webrtcInfo: {
supported: true,
codecs: ['H264'],
resolutions: ['1080p']
}
});
}, 2000);
});
```
### Тестирование через REST API
```bash
# Инициация подключения
curl -X POST http://localhost:3001/api/operators/connections/request \
-H "Content-Type: application/json" \
-H "x-operator-id: operator-uuid" \
-d '{
"deviceId": "test-device-001",
"cameraType": "back"
}'
# Проверка статуса подключений
curl -H "x-operator-id: operator-uuid" \
http://localhost:3001/api/operators/connections
```
Этот протокол обеспечивает надежную и безопасную систему запросов доступа к камере Android устройств с полным контролем пользователя над разрешениями.

View File

View File

View File

View File

View File

View File