Files
vue-pult/docs/CONFIG_LOGIC_ANALYSIS.md
2025-10-07 10:18:02 +03:00

415 lines
23 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 🔍 Анализ логики настроек ESP - Детальная проверка
## ✅ Проверенные компоненты
### 1. **Frontend (Client)**
#### 📄 [client/src/composables/config/useConfigESP.js](../client/src/composables/config/useConfigESP.js)
**Статус:** ✅ Логика корректна
**Проверенные аспекты:**
- ✅ Валидация параметров перед отправкой (строки 93-113)
- ✅ Загрузка настроек через `cfg-esp-get` (строки 118-143)
- ✅ Сохранение параметра через `cfg-esp` (строки 148-190)
- ✅ Откат значения при ошибке (строки 176, 183)
- ✅ Обработка ответа `error` от сервера (строки 174-177)
- ✅ Отслеживание изменений через `hasChanges` (строки 79-88)
**Ключевые моменты:**
```javascript
// Валидация
const validation = validateParam(paramName, config.value[paramName])
if (!validation.valid) {
error.value = validation.error
return { success: false, error: validation.error }
}
// Откат при ошибке
if (response.do === 'error') {
config.value[paramName] = originalConfig.value[paramName]
throw new Error(response.message || 'Ошибка сохранения')
}
```
---
#### 📄 [client/src/pages/ConfigPage.vue](../client/src/pages/ConfigPage.vue)
**Статус:** ✅ Логика корректна (исправлена)
**Проверенные аспекты:**
- ✅ Проверка прав доступа: `user.taccess === 'technics'` или `'admins'` (строка 163)
- ✅ Загрузка настроек при монтировании (строки 188-192)
- ✅ Визуальная индикация изменений
- ✅ Предупреждение при выходе с несохранёнными изменениями (строки 178-186)
**Исправления:**
```javascript
// БЫЛО (неправильно):
return role === 'technic' || role === 'admin' || user.group === 3
// СТАЛО (правильно):
return user.taccess === 'technics' || user.taccess === 'admins' || user.group === 3
```
---
#### 📄 [client/src/composables/useWebSocket.js](../client/src/composables/useWebSocket.js)
**Статус:** ✅ Логика корректна (добавлена обработка)
**Добавленная обработка (строки 71-80):**
```javascript
// Обрабатываем ответы настроек ESP и ошибки через promise
if (data.do === 'cfg-esp-get' || data.do === 'cfg-esp' || data.do === 'error') {
const promiseKeys = Object.keys(pendingPromises)
if (promiseKeys.length > 0) {
const promiseId = promiseKeys[promiseKeys.length - 1]
pendingPromises[promiseId].resolve(data)
delete pendingPromises[promiseId]
return
}
}
```
**Зачем это нужно:**
- Без этого кода ответы `cfg-esp-get`, `cfg-esp` и `error` не попадали бы в promise
- Promise висел бы в pending состоянии до timeout
- UI не получал бы ответ от сервера
---
### 2. **Backend (Server)**
#### 📄 [server/ws.js](../server/ws.js)
**Статус:** ✅ Логика корректна (добавлена поддержка mock режима)
**Обработчик `cfg-esp-get` (строки 952-972):**
```javascript
case "cfg-esp-get":
try {
const espConfig = JSON.parse(await fs.readFile(path.join(__dirname, 'data/esp.ini'), 'utf8'));
sendToClient(wsClient, {
do: "cfg-esp-get",
cfg: espConfig
});
} catch (error) {
sendToClient(wsClient, {
do: "error",
message: "Не удалось загрузить настройки ESP",
type: "esp_config_read_error"
});
}
break;
```
**Обработчик `cfg-esp` (строки 974-1038):**
**Ключевые исправления:**
```javascript
// БЫЛО (неправильно для Windows):
if (result.success) {
await fs.writeFile(configPath, JSON.stringify(espConfig, null, 2));
// ...
}
// СТАЛО (правильно):
const isMockMode = result.error && result.error.includes('mock mode');
if (result.success || isMockMode) {
await fs.writeFile(configPath, JSON.stringify(espConfig, null, 2));
// ...
if (isMockMode) {
console.log(`[WS CFG-ESP] ⚠️ MOCK РЕЖИМ: Параметр сохранён без отправки на ESP`);
}
}
```
**Зачем это нужно:**
- В Windows режиме разработки ESP не подключена (mock режим)
- `game.safeWrite()` возвращает `{ success: false, error: 'ESP disconnected (mock mode)' }`
- Без проверки на `isMockMode` настройки НЕ сохранялись бы в файл
- Теперь в mock режиме настройки сохраняются, но с предупреждением
---
## 🔄 Полный поток данных
### Сценарий 1: Загрузка настроек
```
┌────────────────────────────────────────────────────────────┐
│ 1. ConfigPage.vue (onMounted) │
│ └─> loadConfig() │
└────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────┐
│ 2. useConfigESP.js │
│ └─> socket.sendMessage({ do: 'cfg-esp-get' }) │
└────────────────────────────────────────────────────────────┘
↓ WebSocket
┌────────────────────────────────────────────────────────────┐
│ 3. server/ws.js:952 │
│ └─> Читает data/esp.ini │
│ └─> Отправляет {do:"cfg-esp-get", cfg:{...}} │
└────────────────────────────────────────────────────────────┘
↓ WebSocket
┌────────────────────────────────────────────────────────────┐
│ 4. useWebSocket.js:72 │
│ └─> Обнаруживает data.do === 'cfg-esp-get' │
│ └─> Резолвит promise │
└────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────┐
│ 5. useConfigESP.js:128 │
│ └─> config.value = { ...response.cfg } │
│ └─> originalConfig.value = { ...response.cfg } │
└────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────┐
│ 6. ConfigPage.vue │
│ └─> Отображает настройки в UI │
└────────────────────────────────────────────────────────────┘
```
---
### Сценарий 2: Сохранение параметра (УСПЕХ)
```
┌────────────────────────────────────────────────────────────┐
│ 1. ConfigPage.vue │
│ └─> Пользователь изменяет hz с 14000 на 15000 │
│ └─> Кликает "Применить" │
│ └─> saveParam('hz') │
└────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────┐
│ 2. useConfigESP.js:148 │
│ └─> Валидация: 9999 ≤ 15000 ≤ 100000 ✅ │
│ └─> socket.sendMessage({ │
│ do: 'cfg-esp', │
│ cfg: 'hz', │
│ value: 15000 │
│ }) │
└────────────────────────────────────────────────────────────┘
↓ WebSocket
┌────────────────────────────────────────────────────────────┐
│ 3. server/ws.js:974 │
│ └─> Читает текущий esp.ini │
│ └─> Сохраняет previousValue = 14000 │
│ └─> Обновляет espConfig.hz = 15000 │
│ └─> game.safeWrite("hz=15000;\n") │
└────────────────────────────────────────────────────────────┘
↓ Serial Port
┌────────────────────────────────────────────────────────────┐
│ 4. game.js:127 (safeWrite) │
│ └─> Проверяет port.isOpen │
│ └─> Production: отправляет на ESP │
│ └─> Mock (Windows): return {success:false, error:...} │
└────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────┐
│ 5. server/ws.js:1000 │
│ └─> const isMockMode = result.error?.includes('mock') │
│ └─> if (result.success || isMockMode) │
│ └─> Сохраняет в esp.ini │
│ └─> sendToClient({do:"cfg-esp", cfg:"hz", value:15000})│
└────────────────────────────────────────────────────────────┘
↓ WebSocket
┌────────────────────────────────────────────────────────────┐
│ 6. useWebSocket.js:72 │
│ └─> Обнаруживает data.do === 'cfg-esp' │
│ └─> Резолвит promise │
└────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────┐
│ 7. useConfigESP.js:169 │
│ └─> originalConfig.value.hz = 15000 │
│ └─> return { success: true } │
└────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────┐
│ 8. ConfigPage.vue │
│ └─> Кнопка "Применить" исчезает │
│ └─> Показывается "✓ Сохранено" │
└────────────────────────────────────────────────────────────┘
```
---
### Сценарий 3: Сохранение параметра (ОШИБКА ESP)
```
┌────────────────────────────────────────────────────────────┐
│ 1-3. Аналогично успешному сценарию │
└────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────┐
│ 4. game.js:127 (safeWrite) │
│ └─> ESP не отвечает / ошибка отправки │
│ └─> return { success: false, error: "timeout" } │
└────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────┐
│ 5. server/ws.js:1018 │
│ └─> result.success === false │
│ └─> isMockMode === false (реальная ошибка) │
│ └─> espConfig.hz = previousValue (откат к 14000) │
│ └─> sendToClient({ │
│ do: "error", │
│ message: "Ошибка настройки ESP: timeout", │
│ type: "esp_config_failed", │
│ cfg: "hz" │
│ }) │
└────────────────────────────────────────────────────────────┘
↓ WebSocket
┌────────────────────────────────────────────────────────────┐
│ 6. useWebSocket.js:72 │
│ └─> Обнаруживает data.do === 'error' │
│ └─> Резолвит promise с error │
└────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────┐
│ 7. useConfigESP.js:174 │
│ └─> response.do === 'error' │
│ └─> config.value.hz = originalConfig.value.hz (14000) │
│ └─> throw new Error(response.message) │
└────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────┐
│ 8. useConfigESP.js:181 (catch) │
│ └─> config.value.hz = originalConfig.value.hz (14000) │
│ └─> error.value = err.message │
│ └─> return { success: false, error: err.message } │
└────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────┐
│ 9. ConfigPage.vue │
│ └─> Значение откатывается к 14000 │
│ └─> Показывается ошибка "❌ Не удалось сохранить" │
└────────────────────────────────────────────────────────────┘
```
---
## 🛡️ Проверки безопасности
### 1. **Валидация на клиенте**
```javascript
validateParam(paramName, value) {
const schema = ESP_CONFIG_SCHEMA[paramName]
const numValue = Number(value)
if (isNaN(numValue)) {
return { valid: false, error: 'Значение должно быть числом' }
}
if (numValue < schema.min || numValue > schema.max) {
return { valid: false, error: `Значение должно быть от ${schema.min} до ${schema.max}` }
}
return { valid: true, error: null }
}
```
### 2. **Проверка прав доступа**
```javascript
const hasAccess = computed(() => {
return user.taccess === 'technics' || user.taccess === 'admins' || user.group === 3
})
```
### 3. **Откат при ошибках**
- **Клиент:** Откат `config.value` к `originalConfig.value`
- **Сервер:** Откат `espConfig` к `previousValue`
- **Файл:** Сохранение только при успехе
---
## ⚠️ Найденные и исправленные проблемы
### Проблема 1: Обработка WebSocket ответов
**Проблема:** Ответы `cfg-esp-get`, `cfg-esp`, `error` не обрабатывались в `useWebSocket.js`
**Решение:** Добавлена специальная обработка в `onmessage` (строки 71-80)
---
### Проблема 2: Mock режим Windows
**Проблема:** В Windows (mock режим) настройки НЕ сохранялись
**Решение:** Добавлена проверка `isMockMode` для разрешения сохранения без ESP
---
### Проблема 3: Проверка прав доступа
**Проблема:** Неправильные значения ролей (`technic` вместо `technics`)
**Решение:** Исправлено на `user.taccess === 'technics'` и `'admins'`
---
## ✅ Итоговая оценка
### Что работает ПРАВИЛЬНО:
✅ Загрузка настроек ESP
✅ Сохранение параметров
✅ Валидация диапазонов
✅ Откат при ошибках
✅ Обработка mock режима (Windows)
✅ Проверка прав доступа
✅ Визуальная индикация изменений
✅ Предупреждение о несохранённых изменениях
✅ WebSocket promise система
✅ Детальное логирование
---
## 🚀 Рекомендации для тестирования
### 1. **Тест загрузки настроек**
```
1. Открыть /config
2. Проверить, что отображаются текущие значения из esp.ini
3. Проверить логи: "[WS CFG-ESP-GET] ✅ Настройки ESP отправлены"
```
### 2. **Тест сохранения (успех)**
```
1. Изменить hz на 15000
2. Нажать "Применить"
3. Проверить, что кнопка исчезла
4. Проверить, что esp.ini обновлён
5. Проверить логи: "[WS CFG-ESP] ✅ Параметр hz успешно сохранён"
```
### 3. **Тест валидации**
```
1. Изменить hz на 999999 (вне диапазона)
2. Нажать "Применить"
3. Проверить ошибку: "Значение должно быть от 9999 до 100000"
```
### 4. **Тест прав доступа**
```
1. Войти как operator
2. Открыть /config
3. Проверить сообщение "Нет доступа"
```
### 5. **Тест несохранённых изменений**
```
1. Изменить hz (НЕ нажимать "Применить")
2. Нажать "Назад"
3. Проверить подтверждение "Есть несохранённые изменения..."
```
---
*Анализ завершён: 2025-01-06*
*Все критические проблемы найдены и исправлены*