- Клиентская часть Vue 3 + Vite - Серверная часть Node.js + WebSocket - Система авторизации и смен - Управление игровыми портами - Поддержка тем (светлая/темная) - Адаптивный дизайн 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
151 lines
6.0 KiB
JavaScript
151 lines
6.0 KiB
JavaScript
// Эмуляция SerialPort для разработки интерфейса
|
||
class MockSerialPort {
|
||
constructor(options) {
|
||
this.path = options.path;
|
||
this.baudRate = options.baudRate;
|
||
this.isOpen = false;
|
||
this.listeners = {};
|
||
this.lastPingTime = 0; // Добавляем отслеживание времени последнего ping
|
||
|
||
console.log(`[MOCK SERIAL] Создан порт ${this.path} со скоростью ${this.baudRate}`);
|
||
|
||
// Эмулируем открытие порта через небольшую задержку
|
||
setTimeout(() => {
|
||
this.isOpen = true;
|
||
this.emit('open');
|
||
console.log(`[MOCK SERIAL] Порт ${this.path} открыт`);
|
||
}, 100);
|
||
}
|
||
|
||
on(event, callback) {
|
||
if (!this.listeners[event]) {
|
||
this.listeners[event] = [];
|
||
}
|
||
this.listeners[event].push(callback);
|
||
}
|
||
|
||
write(data) {
|
||
console.log(`[MOCK SERIAL] Отправка: ${data.trim()}`);
|
||
|
||
// Проверяем частоту ping команд
|
||
if (data.includes('ping')) {
|
||
const now = Date.now();
|
||
const timeSinceLastPing = now - this.lastPingTime;
|
||
|
||
// Если ping отправляется слишком часто (менее 2 секунд), пропускаем
|
||
if (timeSinceLastPing < 2000) {
|
||
console.log(`[MOCK SERIAL] ⏱️ Ping отправлен слишком часто (${timeSinceLastPing}ms), пропускаем ответ`);
|
||
return true;
|
||
}
|
||
|
||
this.lastPingTime = now;
|
||
}
|
||
|
||
// Эмулируем ответы ESP через небольшую задержку
|
||
setTimeout(() => {
|
||
if (data.includes('ping')) {
|
||
// Отвечаем на ping
|
||
this.emit('data', 'pong\n');
|
||
console.log(`[MOCK SERIAL] ✅ Отвечаем на ping: pong`);
|
||
} else if (data.includes('start=')) {
|
||
// Эмулируем запуск игры
|
||
const match = data.match(/start=(\d+)\s+(\d+)/);
|
||
if (match) {
|
||
const line = match[1];
|
||
const patr = match[2];
|
||
// Отправляем полный ответ как ожидает сервер
|
||
this.emit('data', `start,${line},${patr}\n`);
|
||
console.log(`[MOCK SERIAL] ✅ Эмулируем УСПЕШНЫЙ запуск игры на линии ${line} с ${patr} патронами`);
|
||
}
|
||
} else if (data.includes('end=')) {
|
||
// Эмулируем завершение игры
|
||
const match = data.match(/end=(\d+)/);
|
||
if (match) {
|
||
const line = match[1];
|
||
this.emit('data', `end,${line}\n`);
|
||
console.log(`[MOCK SERIAL] ✅ Эмулируем завершение игры на линии ${line}`);
|
||
}
|
||
} else if (data.includes('move=')) {
|
||
// Эмулируем перемещение игры
|
||
const match = data.match(/move=(\d+)\s+(\d+)/);
|
||
if (match) {
|
||
const fromLine = match[1];
|
||
const toLine = match[2];
|
||
this.emit('data', `move,${fromLine},${toLine}\n`);
|
||
console.log(`[MOCK SERIAL] ✅ Эмулируем перемещение игры с линии ${fromLine} на ${toLine}`);
|
||
}
|
||
} else if (data.includes('pause;')) {
|
||
// Эмулируем установку паузы
|
||
this.emit('data', 'pause,\n');
|
||
console.log(`[MOCK SERIAL] ✅ Эмулируем установку системы на паузу`);
|
||
} else if (data.includes('resume;')) {
|
||
// Эмулируем снятие паузы
|
||
this.emit('data', 'resume,\n');
|
||
console.log(`[MOCK SERIAL] ✅ Эмулируем снятие системы с паузы`);
|
||
}
|
||
}, 200);
|
||
|
||
return true;
|
||
}
|
||
|
||
pipe(parser) {
|
||
this.parser = parser;
|
||
return parser;
|
||
}
|
||
|
||
emit(event, data) {
|
||
// Уведомляем слушателей порта
|
||
if (this.listeners[event]) {
|
||
this.listeners[event].forEach(callback => {
|
||
try {
|
||
callback(data);
|
||
} catch (error) {
|
||
console.error(`[MOCK SERIAL] Ошибка в обработчике ${event}:`, error);
|
||
}
|
||
});
|
||
}
|
||
|
||
// Также уведомляем parser, если это событие data
|
||
if (this.parser && event === 'data') {
|
||
this.parser.emit('data', data);
|
||
}
|
||
}
|
||
|
||
close(callback) {
|
||
this.isOpen = false;
|
||
if (callback) callback();
|
||
console.log(`[MOCK SERIAL] Порт ${this.path} закрыт`);
|
||
}
|
||
}
|
||
|
||
class MockReadlineParser {
|
||
constructor(options) {
|
||
this.delimiter = options.delimiter || '\n';
|
||
this.listeners = {};
|
||
console.log(`[MOCK PARSER] Создан парсер с разделителем: ${JSON.stringify(this.delimiter)}`);
|
||
}
|
||
|
||
on(event, callback) {
|
||
if (!this.listeners[event]) {
|
||
this.listeners[event] = [];
|
||
}
|
||
this.listeners[event].push(callback);
|
||
}
|
||
|
||
emit(event, data) {
|
||
if (this.listeners[event]) {
|
||
this.listeners[event].forEach(callback => {
|
||
try {
|
||
callback(data);
|
||
} catch (error) {
|
||
console.error(`[MOCK PARSER] Ошибка в обработчике ${event}:`, error);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
module.exports = {
|
||
SerialPort: MockSerialPort,
|
||
ReadlineParser: MockReadlineParser
|
||
};
|