#!/usr/bin/env node /** * Тестовый скрипт для симуляции подключения Android устройства * и тестирования подключения Desktop Operator к телефону */ const io = require('socket.io-client'); const axios = require('axios'); const SERVER_URL = 'http://localhost:3001'; const WS_URL = 'ws://localhost:3001'; // Симулируем Android устройство class AndroidSimulator { constructor(deviceId) { this.deviceId = deviceId; this.socket = null; this.isRegistered = false; } async connect() { console.log('📱 Подключение Android устройства...'); this.socket = io(WS_URL, { transports: ['websocket'] }); return new Promise((resolve, reject) => { this.socket.on('connect', () => { console.log(`✅ Android подключен: ${this.socket.id}`); this.register(); resolve(); }); this.socket.on('connect_error', (error) => { console.error('❌ Ошибка подключения Android:', error); reject(error); }); // Обработка запросов подключения this.socket.on('connection:request', (data) => { console.log('📞 Получен запрос подключения:', data); this.handleConnectionRequest(data); }); // Legacy обработка this.socket.on('camera:request', (data) => { console.log('📷 Получен запрос камеры (legacy):', data); this.handleCameraRequest(data); }); }); } register() { console.log('📝 Регистрация Android устройства...'); this.socket.emit('register:android', { deviceId: this.deviceId, deviceInfo: { manufacturer: 'Samsung', model: 'Galaxy S21 Test', androidVersion: '11', availableCameras: ['back', 'front', 'ultra_wide', 'telephoto'], appVersion: '1.0.0-test' } }); this.socket.on('register:success', (data) => { console.log('✅ Android зарегистрирован:', data); this.isRegistered = true; }); } handleConnectionRequest(data) { console.log(` 🔔 ЗАПРОС ПОДКЛЮЧЕНИЯ: Connection ID: ${data.connectionId} Operator: ${data.operatorInfo?.name || 'Unknown'} Camera: ${data.cameraType} Expires: ${data.expiresAt} `); // Симулируем принятие запроса через 2 секунды setTimeout(() => { console.log('✅ Принимаем запрос подключения...'); this.socket.emit('connection:accept', { connectionId: data.connectionId, sessionId: data.sessionId, cameraType: data.cameraType, webrtcInfo: { supported: true, codecs: ['H264', 'VP8'], resolutions: ['720p', '1080p', '4K'] }, timestamp: new Date().toISOString() }); }, 2000); } handleCameraRequest(data) { console.log(` 📷 LEGACY ЗАПРОС КАМЕРЫ: Session ID: ${data.sessionId} Operator: ${data.operatorId} Camera: ${data.cameraType} `); // Симулируем принятие запроса setTimeout(() => { console.log('✅ Принимаем запрос камеры (legacy)...'); this.socket.emit('camera:response', { sessionId: data.sessionId, accepted: true, reason: 'camera_granted', cameraType: data.cameraType, timestamp: new Date().toISOString() }); }, 1500); } disconnect() { if (this.socket) { this.socket.disconnect(); console.log('📱 Android отключен'); } } } // Симулируем Desktop Operator class OperatorSimulator { constructor(operatorId) { this.operatorId = operatorId; this.socket = null; this.isRegistered = false; } async connect() { console.log('💻 Подключение Desktop Operator...'); this.socket = io(WS_URL, { transports: ['websocket'] }); return new Promise((resolve, reject) => { this.socket.on('connect', () => { console.log(`✅ Operator подключен: ${this.socket.id}`); this.register(); resolve(); }); this.socket.on('connect_error', (error) => { console.error('❌ Ошибка подключения Operator:', error); reject(error); }); // Обработка ответов на подключения this.socket.on('connection:accepted', (data) => { console.log('🎉 Подключение принято Android:', data); }); this.socket.on('connection:rejected', (data) => { console.log('❌ Подключение отклонено Android:', data); }); this.socket.on('connection:timeout', (data) => { console.log('⏰ Таймаут подключения:', data); }); // Legacy события this.socket.on('camera:accepted', (data) => { console.log('📹 Камера принята (legacy):', data); }); }); } register() { console.log('📝 Регистрация Desktop Operator...'); this.socket.emit('register:operator', { operatorId: this.operatorId, operatorInfo: { name: 'Тестовый Оператор', organization: 'QA Отдел', permissions: ['view_cameras', 'request_camera', 'initiate_connection'] } }); this.socket.on('register:success', (data) => { console.log('✅ Operator зарегистрирован:', data); this.isRegistered = true; }); } async getAvailableDevices() { try { const response = await axios.get(`${SERVER_URL}/api/operators/devices`, { headers: { 'x-operator-id': this.operatorId } }); console.log('📱 Доступные устройства:', response.data); return response.data.devices; } catch (error) { console.error('❌ Ошибка получения устройств:', error.response?.data || error.message); return []; } } async requestConnection(deviceId, cameraType = 'back') { try { console.log(`🔗 Запрос подключения к ${deviceId} (${cameraType})...`); const response = await axios.post(`${SERVER_URL}/api/operators/connections/request`, { deviceId, cameraType }, { headers: { 'Content-Type': 'application/json', 'x-operator-id': this.operatorId } }); console.log('✅ Запрос подключения отправлен:', response.data); return response.data; } catch (error) { console.error('❌ Ошибка запроса подключения:', error.response?.data || error.message); return null; } } async getConnections() { try { const response = await axios.get(`${SERVER_URL}/api/operators/connections`, { headers: { 'x-operator-id': this.operatorId } }); console.log('🔗 Активные подключения:', response.data); return response.data.connections; } catch (error) { console.error('❌ Ошибка получения подключений:', error.response?.data || error.message); return []; } } disconnect() { if (this.socket) { this.socket.disconnect(); console.log('💻 Operator отключен'); } } } // Основная функция тестирования async function runTest() { console.log('🚀 Запуск тестирования подключения Operator → Android'); console.log('=' .repeat(60)); const deviceId = 'test_android_' + Math.random().toString(36).substr(2, 9); const operatorId = 'test_operator_' + Math.random().toString(36).substr(2, 9); const android = new AndroidSimulator(deviceId); const operator = new OperatorSimulator(operatorId); try { // 1. Подключаем Android await android.connect(); await new Promise(resolve => setTimeout(resolve, 1000)); // 2. Подключаем Operator await operator.connect(); await new Promise(resolve => setTimeout(resolve, 1000)); // 3. Проверяем доступные устройства console.log('\n📋 Шаг 1: Проверка доступных устройств'); const devices = await operator.getAvailableDevices(); if (devices.length === 0) { console.log('❌ Нет доступных устройств'); return; } // 4. Инициируем подключение console.log('\n🔗 Шаг 2: Инициация подключения'); const connectionResult = await operator.requestConnection(deviceId, 'back'); if (!connectionResult) { console.log('❌ Не удалось создать подключение'); return; } // 5. Ждем обработки подключения console.log('\n⏳ Шаг 3: Ожидание ответа Android...'); await new Promise(resolve => setTimeout(resolve, 5000)); // 6. Проверяем статус подключений console.log('\n📊 Шаг 4: Проверка статуса подключений'); await operator.getConnections(); console.log('\n✅ Тестирование завершено!'); } catch (error) { console.error('❌ Ошибка тестирования:', error); } finally { // Отключаем всех setTimeout(() => { android.disconnect(); operator.disconnect(); process.exit(0); }, 2000); } } // Запуск if (require.main === module) { runTest(); } module.exports = { AndroidSimulator, OperatorSimulator };