# 🛠️ ИНСТРУКЦИЯ ПО ПЕРЕПИСЫВАНИЮ СИСТЕМЫ VIDEOREADER **Версия:** 1.0 **Дата:** 9 октября 2025 г. **Цель:** Создание собственной безопасной системы видеонаблюдения --- ## 📋 ПЛАН МИГРАЦИИ ### Этап 1: Анализ и планирование (1-2 недели) ### Этап 2: Инфраструктура (2-3 недели) ### Етап 3: Backend разработка (3-4 недели) ### Этап 4: Клиентские приложения (4-6 недель) ### Этап 5: Тестирование и деплой (2 недели) --- ## 🏗️ СОВРЕМЕННАЯ АРХИТЕКТУРА ### Рекомендуемый стек технологий: #### 🌐 Backend (Сигналинг сервер) ``` ├── Node.js + TypeScript ├── Socket.IO / WebSocket ├── Redis (для сессий) ├── PostgreSQL (метаданные) ├── Docker + Docker Compose └── Nginx (Reverse Proxy) ``` #### 📱 Android приложение ``` ├── Kotlin / Java ├── WebRTC Android API ├── Camera2 API ├── Retrofit (HTTP клиент) ├── Room (локальная БД) └── Dagger/Hilt (DI) ``` #### 💻 Desktop приложение ``` Вариант 1: Electron + React/Vue ├── TypeScript ├── WebRTC Web API ├── FFmpeg.js └── Material-UI / Ant Design Вариант 2: .NET MAUI ├── C# .NET 8 ├── WebRTC.NET ├── FFMpegCore └── Avalonia UI Вариант 3: Flutter Desktop ├── Dart ├── WebRTC Flutter plugin ├── FFmpeg Flutter └── Material Design ``` --- ## 🚀 ЭТАП 1: НАСТРОЙКА ИНФРАСТРУКТУРЫ ### 1.1 Создание сигналинг сервера ```bash # Создание проекта mkdir videoreader-signaling cd videoreader-signaling npm init -y # Установка зависимостей npm install express socket.io redis ioredis npm install @types/node typescript ts-node nodemon --save-dev ``` ### 1.2 Базовая структура сервера ```typescript // src/server.ts import express from 'express'; import { createServer } from 'http'; import { Server } from 'socket.io'; import Redis from 'ioredis'; const app = express(); const server = createServer(app); const io = new Server(server, { cors: { origin: "*" } }); const redis = new Redis(process.env.REDIS_URL || 'redis://localhost:6379'); interface Device { id: string; type: 'sender' | 'receiver'; channel: string; socketId: string; } // Управление каналами и устройствами class ChannelManager { async addDevice(device: Device) { await redis.hset(`channel:${device.channel}`, device.type, device.socketId); await redis.expire(`channel:${device.channel}`, 3600); // TTL 1 час } async getPartner(channel: string, deviceType: string) { const partnerType = deviceType === 'sender' ? 'receiver' : 'sender'; return await redis.hget(`channel:${channel}`, partnerType); } } const channelManager = new ChannelManager(); io.on('connection', (socket) => { socket.on('join-channel', async (data: {channel: string, type: 'sender'|'receiver'}) => { await channelManager.addDevice({ id: socket.id, type: data.type, channel: data.channel, socketId: socket.id }); // Поиск партнера const partner = await channelManager.getPartner(data.channel, data.type); if (partner) { socket.emit('partner-found', { partnerId: partner }); io.to(partner).emit('partner-found', { partnerId: socket.id }); } }); // WebRTC signaling socket.on('webrtc-offer', (data) => { io.to(data.to).emit('webrtc-offer', { from: socket.id, offer: data.offer }); }); socket.on('webrtc-answer', (data) => { io.to(data.to).emit('webrtc-answer', { from: socket.id, answer: data.answer }); }); socket.on('webrtc-ice-candidate', (data) => { io.to(data.to).emit('webrtc-ice-candidate', { from: socket.id, candidate: data.candidate }); }); }); server.listen(3000, () => console.log('Signaling server running on port 3000')); ``` ### 1.3 Docker конфигурация ```dockerfile # Dockerfile FROM node:18-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . RUN npm run build EXPOSE 3000 CMD ["npm", "start"] ``` ```yaml # docker-compose.yml version: '3.8' services: signaling: build: . ports: - "3000:3000" environment: - REDIS_URL=redis://redis:6379 depends_on: - redis redis: image: redis:7-alpine ports: - "6379:6379" nginx: image: nginx:alpine ports: - "80:80" - "443:443" volumes: - ./nginx.conf:/etc/nginx/nginx.conf - ./ssl:/etc/nginx/ssl ``` --- ## 📱 ЭТАП 2: ANDROID ПРИЛОЖЕНИЕ (KOTLIN) ### 2.1 Создание проекта ```kotlin // build.gradle (Module: app) dependencies { implementation 'org.webrtc:google-webrtc:1.0.32006' implementation 'io.socket:socket.io-client:2.0.0' implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'androidx.camera:camera-camera2:1.3.0' implementation 'androidx.camera:camera-lifecycle:1.3.0' implementation 'androidx.camera:camera-view:1.3.0' } ``` ### 2.2 WebRTC интеграция ```kotlin // WebRTCManager.kt class WebRTCManager(private val context: Context) { private var peerConnection: PeerConnection? = null private var localVideoTrack: VideoTrack? = null private var socket: Socket? = null fun initialize() { // Инициализация PeerConnectionFactory PeerConnectionFactory.initializeAndroidGlobals( context, true, true, true ) val factory = PeerConnectionFactory.builder() .createPeerConnectionFactory() // Настройка ICE серверов val iceServers = listOf( PeerConnection.IceServer.builder("stun:stun.l.google.com:19302").createIceServer() ) peerConnection = factory.createPeerConnection( PeerConnection.RTCConfiguration(iceServers), object : PeerConnection.Observer { override fun onIceCandidate(candidate: IceCandidate) { sendIceCandidate(candidate) } // ... другие callbacks } ) } fun startCapture() { val videoCapturer = Camera2Enumerator(context).run { deviceNames.firstOrNull()?.let { createCapturer(it, null) } } val surfaceTextureHelper = SurfaceTextureHelper.create("CaptureThread", null) val videoSource = factory.createVideoSource(false) videoCapturer?.initialize(surfaceTextureHelper, context, videoSource.capturerObserver) localVideoTrack = factory.createVideoTrack("local_video", videoSource) peerConnection?.addTrack(localVideoTrack, listOf("stream_id")) } private fun sendIceCandidate(candidate: IceCandidate) { socket?.emit("webrtc-ice-candidate", JSONObject().apply { put("to", partnerId) put("candidate", candidate.toJson()) }) } } ``` ### 2.3 Сигналинг клиент ```kotlin // SignalingClient.kt class SignalingClient(private val serverUrl: String) { private var socket: Socket? = null private var webRTCManager: WebRTCManager? = null fun connect(channel: String) { socket = IO.socket(serverUrl).apply { on(Socket.EVENT_CONNECT) { emit("join-channel", JSONObject().apply { put("channel", channel) put("type", "sender") }) } on("partner-found") { args -> val data = args[0] as JSONObject val partnerId = data.getString("partnerId") createOffer(partnerId) } on("webrtc-offer") { args -> val data = args[0] as JSONObject handleOffer(data) } connect() } } private fun createOffer(partnerId: String) { webRTCManager?.createOffer { offer -> socket?.emit("webrtc-offer", JSONObject().apply { put("to", partnerId) put("offer", offer.toJson()) }) } } } ``` --- ## 💻 ЭТАП 3: DESKTOP ПРИЛОЖЕНИЕ (ELECTRON) ### 3.1 Инициализация проекта ```bash mkdir videoreader-desktop cd videoreader-desktop npm init -y npm install electron react react-dom typescript npm install simple-peer socket.io-client --save ``` ### 3.2 WebRTC компонент ```typescript // src/components/VideoReceiver.tsx import React, { useEffect, useRef, useState } from 'react'; import io from 'socket.io-client'; import SimplePeer from 'simple-peer'; interface VideoReceiverProps { channel: string; serverUrl: string; } export const VideoReceiver: React.FC = ({ channel, serverUrl }) => { const videoRef = useRef(null); const [connected, setConnected] = useState(false); const [peer, setPeer] = useState(null); const socket = useRef(io(serverUrl)); useEffect(() => { socket.current.emit('join-channel', { channel, type: 'receiver' }); socket.current.on('partner-found', (data: { partnerId: string }) => { const newPeer = new SimplePeer({ initiator: false, trickle: false }); newPeer.on('signal', (signal) => { socket.current.emit('webrtc-answer', { to: data.partnerId, answer: signal }); }); newPeer.on('stream', (stream) => { if (videoRef.current) { videoRef.current.srcObject = stream; setConnected(true); } }); setPeer(newPeer); }); socket.current.on('webrtc-offer', (data: { from: string; offer: any }) => { if (peer) { peer.signal(data.offer); } }); return () => { socket.current.disconnect(); peer?.destroy(); }; }, [channel, serverUrl, peer]); return (

Channel: {channel}

{connected ? 'Connected' : 'Waiting for connection...'}
); }; ``` ### 3.3 Главное окно Electron ```typescript // src/main.ts import { app, BrowserWindow } from 'electron'; import * as path from 'path'; function createWindow() { const mainWindow = new BrowserWindow({ width: 1200, height: 800, webPreferences: { nodeIntegration: true, contextIsolation: false, webSecurity: false // Для разработки, в продакшене нужно настроить правильно } }); if (process.env.NODE_ENV === 'development') { mainWindow.loadURL('http://localhost:3001'); mainWindow.webContents.openDevTools(); } else { mainWindow.loadFile(path.join(__dirname, '../build/index.html')); } } app.whenReady().then(createWindow); ``` --- ## 🔐 ЭТАП 4: БЕЗОПАСНОСТЬ ### 4.1 Аутентификация пользователей ```typescript // auth/AuthService.ts import jwt from 'jsonwebtoken'; import bcrypt from 'bcrypt'; export class AuthService { private static readonly JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key'; static async hashPassword(password: string): Promise { return bcrypt.hash(password, 12); } static async verifyPassword(password: string, hash: string): Promise { return bcrypt.compare(password, hash); } static generateToken(userId: string): string { return jwt.sign({ userId }, this.JWT_SECRET, { expiresIn: '24h' }); } static verifyToken(token: string): any { return jwt.verify(token, this.JWT_SECRET); } } ``` ### 4.2 HTTPS и WSS ```nginx # nginx.conf server { listen 443 ssl http2; server_name your-domain.com; ssl_certificate /etc/nginx/ssl/cert.pem; ssl_certificate_key /etc/nginx/ssl/key.pem; location / { proxy_pass http://signaling:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } ``` --- ## 📊 ЭТАП 5: МОНИТОРИНГ И МАСШТАБИРОВАНИЕ ### 5.1 Логирование ```typescript // logger/Logger.ts import winston from 'winston'; export const logger = winston.createLogger({ level: 'info', format: winston.format.combine( winston.format.timestamp(), winston.format.errors({ stack: true }), winston.format.json() ), defaultMeta: { service: 'videoreader-signaling' }, transports: [ new winston.transports.File({ filename: 'error.log', level: 'error' }), new winston.transports.File({ filename: 'combined.log' }), new winston.transports.Console({ format: winston.format.simple() }) ] }); ``` ### 5.2 Метрики ```typescript // metrics/Metrics.ts import prometheus from 'prom-client'; export const metrics = { connectionsTotal: new prometheus.Counter({ name: 'connections_total', help: 'Total number of connections' }), activeConnections: new prometheus.Gauge({ name: 'active_connections', help: 'Number of active connections' }), channelsActive: new prometheus.Gauge({ name: 'channels_active', help: 'Number of active channels' }) }; prometheus.register.registerMetric(metrics.connectionsTotal); prometheus.register.registerMetric(metrics.activeConnections); prometheus.register.registerMetric(metrics.channelsActive); ``` --- ## 🚀 ДЕПЛОЙMENT ### Kubernetes манифесты ```yaml # k8s/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: videoreader-signaling spec: replicas: 3 selector: matchLabels: app: videoreader-signaling template: metadata: labels: app: videoreader-signaling spec: containers: - name: signaling image: your-registry/videoreader-signaling:latest ports: - containerPort: 3000 env: - name: REDIS_URL value: "redis://redis-service:6379" - name: JWT_SECRET valueFrom: secretKeyRef: name: app-secrets key: jwt-secret ``` --- ## 💡 РЕКОМЕНДАЦИИ ПО УЛУЧШЕНИЮ ### 1. Производительность - Использование WebRTC для P2P соединений - CDN для статических файлов - Load balancing для сигналинг серверов - Redis Cluster для масштабирования ### 2. Безопасность - End-to-end шифрование - Rate limiting - DDoS защита - Регулярные security аудиты ### 3. Пользовательский опыт - Progressive Web App (PWA) версия - Адаптивный дизайн - Офлайн режим - Уведомления ### 4. Мониторинг - Grafana дашборды - Alertmanager для уведомлений - Jaeger для трейсинга - ELK стек для логов --- ## 📈 ПЛАН РАЗВИТИЯ ### Версия 2.0 - [ ] Групповые видеозвонки - [ ] Запись и хранение видео - [ ] AI анализ контента - [ ] Мобильные push уведомления ### Версия 3.0 - [ ] Облачное хранилище - [ ] API для интеграций - [ ] Белый лейбл решение - [ ] Международная локализация --- **🎯 РЕЗУЛЬТАТ:** Современная, безопасная и масштабируемая система видеонаблюдения с собственной инфраструктурой, готовая к продакшн использованию и дальнейшему развитию.