docs: переименовать план в websocket-server-plan.md
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
@@ -0,0 +1,656 @@
|
||||
# План: WebSocket сервер для Wyoming Satellite
|
||||
|
||||
**Дата:** 2026-05-20
|
||||
**Статус:** В разработке
|
||||
**Ветка:** `satellite-dev`
|
||||
**Директория для разработки:** `~/projects/satellite-dev`
|
||||
**Файл плана:** `docs/development/websocket-server-plan.md`
|
||||
|
||||
---
|
||||
|
||||
## Чеклист выполнения
|
||||
|
||||
### ✅ Выполнено
|
||||
|
||||
- [x] **Ветка создана** — `satellite-dev` (переименована из `feature/multi-event-server`)
|
||||
- [x] **Окружение настроено** — `.venv/` в корне проекта
|
||||
- [x] **Docker удалён** — файлы Dockerfile, docker-compose.yml, скрипты
|
||||
- [x] **Лишние файлы удалены** — test.wav, start.sh, start-dev.sh, .projectile
|
||||
- [x] **setup_dev.sh создан** — быстрая настройка окружения
|
||||
- [x] **Документация обновлена** — plan.md актуализирован
|
||||
|
||||
### 🔄 В процессе
|
||||
|
||||
- [ ] **Этап WS-1: settings.py** — добавить websocket_enabled, websocket_host, websocket_port
|
||||
- [ ] **Этап WS-2: satellite.py** — встроенный WebSocket сервер
|
||||
- [ ] **Этап WS-3: __main__.py** — CLI аргументы для WebSocket
|
||||
- [ ] **Этап WS-4: Тестирование** — проверка WebSocket клиентов
|
||||
- [ ] **Этап WS-5: Документация** — обновление docs/
|
||||
|
||||
### ⏳ Ожидается
|
||||
|
||||
- [ ] Merge в master
|
||||
- [ ] Production развёртывание
|
||||
|
||||
---
|
||||
|
||||
## Архитектура
|
||||
|
||||
### Текущее состояние (production)
|
||||
|
||||
```
|
||||
┌─────────────────┐ ┌─────────────────┐
|
||||
│ Home Assistant │ ──────► │ Satellite │
|
||||
│ (Wyoming │ 10700 │ (Wyoming │
|
||||
│ Client) │ │ Server) │
|
||||
└─────────────────┘ └────────┬────────┘
|
||||
│
|
||||
│ 10500 (outgoing!)
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ Event Service │
|
||||
│ (LED, MQTT) │
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
**Ограничение:** Satellite **подключается** к event службе, но не может принимать входящие подключения
|
||||
|
||||
### Целевое состояние
|
||||
|
||||
```
|
||||
┌─────────────────┐ ┌──────────────────────────┐
|
||||
│ Home Assistant │ ──────► │ Wyoming Satellite │
|
||||
│ (Wyoming │ 10700 │ (единый процесс) │
|
||||
│ Client) │ │ │
|
||||
└─────────────────┘ │ ┌────────────────────┐ │
|
||||
│ │ Event CLIENT │ │
|
||||
│ │ (outgoing :10500) │ │
|
||||
│ │ → LED, MQTT │ │
|
||||
│ └────────────────────┘ │
|
||||
│ ┌────────────────────┐ │
|
||||
│ │ WebSocket SERVER │ │
|
||||
│ │ (incoming :8675) │ │
|
||||
│ │ ← Browser, UI │ │
|
||||
│ └────────────────────┘ │
|
||||
└──────────────────────────┘
|
||||
```
|
||||
|
||||
**Принцип:**
|
||||
- ✅ **Event CLIENT** (`--event-uri`) — satellite **подключается** к внешней службе (LED, MQTT)
|
||||
- ✅ **WebSocket SERVER** (`--websocket-enabled`) — встроенный сервер, клиенты **подключаются к нему**
|
||||
|
||||
**Преимущества:**
|
||||
- ✅ **Не нужен отдельный процесс** — websocket-service встроен в satellite
|
||||
- ✅ **Прямая трансляция событий** — без промежуточных очередей
|
||||
- ✅ **Масштабируемость** — неограниченное количество WebSocket клиентов
|
||||
- ✅ **Обратная совместимость** — `--event-uri` продолжает работать
|
||||
|
||||
---
|
||||
|
||||
## Этапы реализации
|
||||
|
||||
### Этап 1: Подготовка ✅ ВЫПОЛНЕН
|
||||
|
||||
#### 1.1 Проверка окружения ✅
|
||||
|
||||
```bash
|
||||
# Production версия (не трогать!)
|
||||
cd ~/projects/Satellite
|
||||
git status # Должен быть clean
|
||||
|
||||
# Development версия
|
||||
cd ~/projects/satellite-dev
|
||||
git status # Должен быть на satellite-dev
|
||||
```
|
||||
|
||||
#### 1.2 Настройка venv для satellite-dev ✅
|
||||
|
||||
```bash
|
||||
# Автоматическая настройка
|
||||
cd ~/projects/satellite-dev
|
||||
./setup_dev.sh
|
||||
|
||||
# Или вручную:
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
#### 1.3 Проверка что всё работает ✅
|
||||
|
||||
```bash
|
||||
cd ~/projects/satellite-dev
|
||||
source .venv/bin/activate
|
||||
|
||||
# Проверка импорта
|
||||
python3 -c "from wyoming_satellite.satellite import SatelliteBase; print('OK')"
|
||||
```
|
||||
|
||||
**Итого:** Окружение готово, можно приступать к реализации.
|
||||
|
||||
---
|
||||
|
||||
### Этап WS-1: Модификация `wyoming_satellite/settings.py` (30 мин) 🔄 В ПРОЦЕССЕ
|
||||
|
||||
**Добавить настройки WebSocket сервера:**
|
||||
|
||||
```python
|
||||
@dataclass(frozen=True)
|
||||
class EventSettings(ServiceSettings):
|
||||
# ... существующие поля ...
|
||||
|
||||
# === НОВЫЕ ПОЛЯ: WebSocket server ===
|
||||
websocket_enabled: bool = False
|
||||
"""True если WebSocket сервер должен быть запущен."""
|
||||
|
||||
websocket_host: str = "0.0.0.0"
|
||||
"""Host для WebSocket сервера."""
|
||||
|
||||
websocket_port: int = 8675
|
||||
"""Port для WebSocket сервера."""
|
||||
```
|
||||
|
||||
**Итого изменений:** ~10 строк
|
||||
|
||||
---
|
||||
|
||||
### Этап WS-2: Модификация `wyoming_satellite/satellite.py` (2-3 часа) ⏳ ОЖИДАЕТСЯ
|
||||
|
||||
#### Зависимость
|
||||
|
||||
`websockets>=10.0` уже установлен в `requirements.txt` ✅
|
||||
|
||||
#### 2.1 Добавить атрибуты для WebSocket сервера
|
||||
|
||||
В `SatelliteBase.__init__()` после `_event_task`:
|
||||
|
||||
```python
|
||||
# WebSocket server (новый)
|
||||
self._websocket_server: Optional[websockets.server.Serve] = None
|
||||
self._websocket_clients: Set[websockets.server.WebSocketServerProtocol] = set()
|
||||
self._websocket_lock = asyncio.Lock()
|
||||
```
|
||||
|
||||
**Импорт:** `Set` из `typing`, `websockets`
|
||||
|
||||
#### 2.2 Метод для рассылки в WebSocket
|
||||
|
||||
```python
|
||||
async def _broadcast_to_websocket(self, event: Event) -> None:
|
||||
"""
|
||||
Отправить событие всем WebSocket клиентам.
|
||||
|
||||
Мёртвые подключения автоматически удаляются.
|
||||
"""
|
||||
import json
|
||||
|
||||
async with self._websocket_lock:
|
||||
if not self._websocket_clients:
|
||||
return
|
||||
|
||||
dead_clients = []
|
||||
message = json.dumps(
|
||||
{"type": event.type, "data": event.data or {}},
|
||||
ensure_ascii=False
|
||||
)
|
||||
|
||||
for ws in self._websocket_clients:
|
||||
try:
|
||||
await ws.send(message)
|
||||
except Exception:
|
||||
_LOGGER.debug(
|
||||
f"Failed to send event to WebSocket client, removing"
|
||||
)
|
||||
dead_clients.append(ws)
|
||||
|
||||
# Удалить мёртвые подключения
|
||||
for ws in dead_clients:
|
||||
self._websocket_clients.discard(ws)
|
||||
```
|
||||
|
||||
#### 2.3 WebSocket сервер
|
||||
|
||||
```python
|
||||
async def start_websocket_server(self) -> None:
|
||||
"""
|
||||
Запустить WebSocket сервер для внешних клиентов.
|
||||
|
||||
Клиенты могут подключаться к порту websocket_port и получать все события.
|
||||
"""
|
||||
async def handle_websocket(websocket, path):
|
||||
client_addr = websocket.remote_address
|
||||
_LOGGER.info(f"WebSocket client connected: {client_addr}")
|
||||
|
||||
async with self._websocket_lock:
|
||||
self._websocket_clients.add(websocket)
|
||||
|
||||
try:
|
||||
# Ждать отключения клиента
|
||||
async for message in websocket:
|
||||
# Игнорировать входящие сообщения (только рассылка)
|
||||
_LOGGER.debug(f"Received from WebSocket: {message}")
|
||||
except websockets.exceptions.ConnectionClosed:
|
||||
pass # Нормальное отключение
|
||||
except Exception as exc:
|
||||
_LOGGER.debug(f"WebSocket client error: {exc}")
|
||||
finally:
|
||||
async with self._websocket_lock:
|
||||
self._websocket_clients.discard(websocket)
|
||||
|
||||
_LOGGER.info(f"WebSocket client disconnected: {client_addr}")
|
||||
|
||||
self._websocket_server = await websockets.serve(
|
||||
handle_websocket,
|
||||
self.settings.event.websocket_host,
|
||||
self.settings.event.websocket_port
|
||||
)
|
||||
|
||||
_LOGGER.info(
|
||||
f"WebSocket server listening on "
|
||||
f"{self.settings.event.websocket_host}:{self.settings.event.websocket_port}"
|
||||
)
|
||||
|
||||
async def stop_websocket_server(self) -> None:
|
||||
"""
|
||||
Остановить WebSocket сервер и закрыть все подключения.
|
||||
"""
|
||||
_LOGGER.info("Stopping WebSocket server...")
|
||||
|
||||
if self._websocket_server:
|
||||
self._websocket_server.close()
|
||||
await self._websocket_server.wait_closed()
|
||||
self._websocket_server = None
|
||||
|
||||
# Закрыть все подключения
|
||||
async with self._websocket_lock:
|
||||
for ws in self._websocket_clients:
|
||||
await ws.close(1000, "Server shutting down")
|
||||
self._websocket_clients.clear()
|
||||
|
||||
_LOGGER.info("WebSocket server stopped")
|
||||
```
|
||||
|
||||
#### 2.4 Интеграция в жизненный цикл
|
||||
|
||||
**В `_start()`:**
|
||||
|
||||
```python
|
||||
async def _start(self) -> None:
|
||||
"""Connect to services."""
|
||||
self.state = State.STARTING
|
||||
await self._connect_to_services()
|
||||
|
||||
# Запустить WebSocket сервер (новый)
|
||||
if self.settings.event.websocket_enabled:
|
||||
await self.start_websocket_server()
|
||||
|
||||
self.state = State.STARTED
|
||||
await self.started()
|
||||
```
|
||||
|
||||
**В `_stop()`:**
|
||||
|
||||
```python
|
||||
async def _stop(self) -> None:
|
||||
"""Disconnect from services."""
|
||||
self.server_id = None
|
||||
self._writer = None
|
||||
|
||||
# Остановить WebSocket сервер (новый)
|
||||
if self._websocket_server:
|
||||
await self.stop_websocket_server()
|
||||
|
||||
await self._disconnect_from_services()
|
||||
self._disable_ping()
|
||||
self.state = State.STOPPED
|
||||
```
|
||||
|
||||
#### 2.5 Обновить `forward_event()`
|
||||
|
||||
```python
|
||||
async def forward_event(self, event: Event) -> None:
|
||||
"""
|
||||
Forward an event to all event consumers.
|
||||
|
||||
Sends to:
|
||||
- Legacy event service (if configured via event.uri)
|
||||
- All connected WebSocket clients
|
||||
"""
|
||||
# Legacy event service (через TCP клиент)
|
||||
if self._event_queue is not None:
|
||||
self._event_queue.put_nowait(event)
|
||||
|
||||
# WebSocket клиенты
|
||||
await self._broadcast_to_websocket(event)
|
||||
```
|
||||
|
||||
**Итого изменений:** ~150 строк
|
||||
|
||||
---
|
||||
|
||||
### Этап WS-3: Модификация `wyoming_satellite/__main__.py` (20 мин) ⏳ ОЖИДАЕТСЯ
|
||||
|
||||
#### 3.1 Добавить CLI аргументы
|
||||
|
||||
После существующих аргументов (перед `args = parser.parse_args()`):
|
||||
|
||||
```python
|
||||
# WebSocket server
|
||||
parser.add_argument(
|
||||
"--websocket-enabled",
|
||||
action="store_true",
|
||||
help="Enable WebSocket server for external clients (default: disabled)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--websocket-host",
|
||||
default="0.0.0.0",
|
||||
help="Host for WebSocket server (default: 0.0.0.0)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--websocket-port",
|
||||
type=int,
|
||||
default=8675,
|
||||
help="Port for WebSocket server (default: 8675)"
|
||||
)
|
||||
```
|
||||
|
||||
#### 3.2 Передать настройки в EventSettings
|
||||
|
||||
В существующем `EventSettings(...)`:
|
||||
|
||||
```python
|
||||
event=EventSettings(
|
||||
uri=args.event_uri,
|
||||
# ... существующие поля ...
|
||||
|
||||
# === НОВЫЕ ПОЛЯ ===
|
||||
websocket_enabled=args.websocket_enabled,
|
||||
websocket_host=args.websocket_host,
|
||||
websocket_port=args.websocket_port,
|
||||
),
|
||||
```
|
||||
|
||||
**Итого изменений:** ~20 строк
|
||||
|
||||
---
|
||||
|
||||
### Этап WS-4: Тестирование WebSocket (1 час) ⏳ ОЖИДАЕТСЯ
|
||||
|
||||
#### 4.1 Запустить satellite с WebSocket
|
||||
|
||||
```bash
|
||||
cd ~/projects/satellite-dev
|
||||
source .venv/bin/activate
|
||||
|
||||
python3 -m wyoming_satellite \
|
||||
--uri tcp://0.0.0.0:10700 \
|
||||
--event-uri tcp://127.0.0.1:10500 \
|
||||
--websocket-enabled \
|
||||
--websocket-port 8675 \
|
||||
--debug
|
||||
```
|
||||
|
||||
**Ожидаемый вывод:**
|
||||
```
|
||||
INFO: Ready
|
||||
INFO: WebSocket server listening on 0.0.0.0:8675
|
||||
INFO: Слушаем tcp://0.0.0.0:10700
|
||||
```
|
||||
|
||||
#### 4.2 Проверить подключения
|
||||
|
||||
**Терминал 1: test_client.py**
|
||||
```bash
|
||||
source .venv/bin/activate
|
||||
python3 examples/websocket-service/test_client.py \
|
||||
--uri ws://127.0.0.1:8675
|
||||
```
|
||||
|
||||
**Терминал 2: Браузер**
|
||||
```
|
||||
Открыть examples/websocket-service/client.html
|
||||
```
|
||||
|
||||
**Терминал 3: wyoming-led.py (event client)**
|
||||
```bash
|
||||
source .venv/bin/activate
|
||||
python3 examples/wyoming-led.py --host 127.0.0.1 --port 10500
|
||||
```
|
||||
|
||||
#### 4.3 Проверить логи
|
||||
|
||||
**В логе satellite:**
|
||||
```
|
||||
INFO: WebSocket client connected: ('127.0.0.1', XXXX)
|
||||
INFO: Connected to server # Home Assistant
|
||||
```
|
||||
|
||||
**Проверить:**
|
||||
- ✅ WebSocket клиент получает события
|
||||
- ✅ wyoming-led.py работает через `--event-uri`
|
||||
- ✅ Home Assistant работает (порт 10700)
|
||||
- ✅ При отключении клиента satellite не падает
|
||||
|
||||
---
|
||||
|
||||
### Этап WS-5: Обновление документации (20 мин) ⏳ ОЖИДАЕТСЯ
|
||||
|
||||
#### 5.1 `docs/integration/mqtt-led.md`
|
||||
|
||||
Добавить секцию после "Архитектура USB контроллера":
|
||||
|
||||
```markdown
|
||||
## WebSocket сервер (внешние клиенты)
|
||||
|
||||
Wyoming Satellite поддерживает встроенный WebSocket сервер для внешних клиентов.
|
||||
|
||||
### Преимущества
|
||||
|
||||
- ✅ **Не нужен отдельный процесс** — websocket-service встроен в satellite
|
||||
- ✅ **Прямая трансляция событий** — без промежуточных очередей
|
||||
- ✅ **Масштабируемость** — неограниченное количество WebSocket клиентов
|
||||
|
||||
### Запуск
|
||||
|
||||
```bash
|
||||
python3 -m wyoming_satellite \
|
||||
--uri tcp://0.0.0.0:10700 \
|
||||
--event-uri tcp://127.0.0.1:10500 \
|
||||
--websocket-enabled \
|
||||
--websocket-port 8675
|
||||
```
|
||||
|
||||
### Подключение из браузера
|
||||
|
||||
```javascript
|
||||
const ws = new WebSocket('ws://localhost:8675');
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
console.log('Событие:', data.type, data.data);
|
||||
};
|
||||
```
|
||||
|
||||
### Примеры
|
||||
|
||||
- `examples/websocket-service/client.html` — браузерный клиент
|
||||
- `examples/websocket-service/test_client.py` — Python тест клиент
|
||||
|
||||
### Обратная совместимость
|
||||
|
||||
Старый `wyoming-led.py` продолжает работать через `--event-uri`:
|
||||
|
||||
```bash
|
||||
python3 -m wyoming_satellite \
|
||||
--event-uri tcp://127.0.0.1:10500 \
|
||||
--websocket-enabled \
|
||||
--websocket-port 8675
|
||||
```
|
||||
|
||||
Оба метода работают параллельно!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Итоговые изменения
|
||||
|
||||
| Файл | Тип | Изменения | Строк |
|
||||
|------|-----|-----------|-------|
|
||||
| `wyoming_satellite/settings.py` | Изменён | EventSettings + WebSocket | ~10 |
|
||||
| `wyoming_satellite/satellite.py` | Изменён | WebSocket server + broadcast | ~150 |
|
||||
| `wyoming_satellite/__main__.py` | Изменён | CLI аргументы | ~20 |
|
||||
| `examples/websocket-service/*` | Существующий | Готовые клиенты | — |
|
||||
| `docs/integration/mqtt-led.md` | Изменён | Документация WebSocket | ~50 |
|
||||
| **ВСЕГО** | | | **~230 строк** |
|
||||
|
||||
---
|
||||
|
||||
## Риски и план Б
|
||||
|
||||
| Риск | Вероятность | Влияние | Решение |
|
||||
|------|-------------|---------|---------|
|
||||
| Конфликт портов (8675 занят) | Низкая | Среднее | Проверка `lsof -i :8675`, смена порта |
|
||||
| Утечка памяти (клиенты) | Средняя | Высокое | Логирование подключений, таймауты |
|
||||
| Падение satellite | Низкая | Критичное | Тестирование в ветке, backup файлов |
|
||||
| Home Assistant отключится | Низкая | Критичное | Порт 10700 не меняется, обратная совместимость |
|
||||
| Event client не работает | Низкая | Критичное | `--event-uri` не меняется, проверять логи |
|
||||
|
||||
### План Б: Откат
|
||||
|
||||
Если что-то идёт не так:
|
||||
|
||||
```bash
|
||||
cd ~/projects/Satellite
|
||||
git checkout master
|
||||
|
||||
# Восстановить файлы
|
||||
cp wyoming_satellite/satellite.py.backup wyoming_satellite/satellite.py
|
||||
cp wyoming_satellite/settings.py.backup wyoming_satellite/settings.py
|
||||
cp wyoming_satellite/__main__.py.backup wyoming_satellite/__main__.py
|
||||
|
||||
# Перезапустить сервисы
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl restart wyoming-satelite-vosk.service
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Контрольный список
|
||||
|
||||
### ✅ Этап 1: Подготовка (выполнено)
|
||||
|
||||
- [x] Ветка создана — `satellite-dev`
|
||||
- [x] Окружение настроено — `.venv/` в корне проекта
|
||||
- [x] `setup_dev.sh` создан
|
||||
- [x] Лишние файлы удалены (Docker, test.wav, старые скрипты)
|
||||
- [x] `python3 -c "from wyoming_satellite.satellite import SatelliteBase; print('OK')"` работает
|
||||
|
||||
### 🔄 Этап WS-1: settings.py (в процессе)
|
||||
|
||||
- [ ] `websocket_enabled: bool` добавлено
|
||||
- [ ] `websocket_host: str` добавлено
|
||||
- [ ] `websocket_port: int` добавлено
|
||||
- [ ] `python3 -c "from wyoming_satellite.settings import EventSettings; print(EventSettings.websocket_enabled)"` работает
|
||||
|
||||
### ⏳ Этап WS-2: satellite.py (ожидается)
|
||||
|
||||
- [ ] `_websocket_server: Optional[asyncio.Server]` добавлено
|
||||
- [ ] `_websocket_clients: Set[...]` добавлено
|
||||
- [ ] `_websocket_lock` добавлено
|
||||
- [ ] Метод `_broadcast_to_websocket()` реализован
|
||||
- [ ] Метод `start_websocket_server()` реализован
|
||||
- [ ] Метод `stop_websocket_server()` реализован
|
||||
- [ ] Интеграция в `_start()` выполнена
|
||||
- [ ] Интеграция в `_stop()` выполнена
|
||||
- [ ] `python3 -m py_compile wyoming_satellite/satellite.py` проходит
|
||||
|
||||
### ⏳ Этап WS-3: __main__.py (ожидается)
|
||||
|
||||
- [ ] `--websocket-enabled` аргумент добавлен
|
||||
- [ ] `--websocket-host` аргумент добавлен
|
||||
- [ ] `--websocket-port` аргумент добавлен
|
||||
- [ ] Передача настроек в `EventSettings()` настроена
|
||||
- [ ] `python3 -m wyoming_satellite --help` показывает новые аргументы
|
||||
|
||||
### ⏳ Этап WS-4: Тестирование (ожидается)
|
||||
|
||||
- [ ] Satellite запускается с `--websocket-enabled`
|
||||
- [ ] WebSocket клиент подключается к порту 8675
|
||||
- [ ] Все клиенты получают события
|
||||
- [ ] Home Assistant работает (порт 10700)
|
||||
- [ ] wyoming-led.py работает (порт 10500)
|
||||
- [ ] При отключении клиента satellite не падает
|
||||
- [ ] Утечек памяти нет (через 10 минут работы)
|
||||
|
||||
### ⏳ Этап WS-5: Документация (ожидается)
|
||||
|
||||
- [ ] `docs/integration/mqtt-led.md` обновлена
|
||||
- [ ] Примеры в документации работают
|
||||
|
||||
### ⏳ Перед merge
|
||||
|
||||
- [ ] Все тесты пройдены
|
||||
- [ ] Документация актуальна
|
||||
- [ ] Ветка называется `satellite-dev`
|
||||
|
||||
---
|
||||
|
||||
## Приложения
|
||||
|
||||
### A. Пример события в WebSocket клиенте
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "voice-started",
|
||||
"data": {}
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "voice-stopped",
|
||||
"data": {}
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "transcript",
|
||||
"data": {
|
||||
"text": "привет дроид"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### B. Диагностика
|
||||
|
||||
```bash
|
||||
# Проверка портов
|
||||
lsof -i :8675
|
||||
lsof -i :10700
|
||||
lsof -i :10500
|
||||
|
||||
# Проверка подключений
|
||||
netstat -tlnp | grep python
|
||||
|
||||
# Логи satellite
|
||||
journalctl -u wyoming-satelite-vosk.service -f
|
||||
|
||||
# Тест подключения
|
||||
telnet 127.0.0.1 8675
|
||||
```
|
||||
|
||||
### C. Сравнение подходов
|
||||
|
||||
| Аспект | Старый (отдельный сервис) | Новый (встроенный) |
|
||||
|--------|---------------------------|--------------------|
|
||||
| Процессы | 2 (satellite + websocket-service) | 1 (satellite) |
|
||||
| Подключения | satellite → websocket → clients | clients → satellite |
|
||||
| Отказоустойчивость | Падение websocket → переподключение | Падение client → satellite работает |
|
||||
| Масштабируемость | Ограничено | Неограниченно клиентов |
|
||||
| Сложность | Выше (два сервиса) | Ниже (один сервис) |
|
||||
| Обратная совместимость | ✅ Работает через event.uri | ✅ Работает через event.uri |
|
||||
|
||||
---
|
||||
|
||||
**Конец документа**
|
||||
Reference in New Issue
Block a user