const { gpt, gptweb } = require("./API/gpt");
const { dalle } = require("./API/dalle");
const { gpt4o } = require("./API/gpt4o");
const { gpt3 } = require("./API/gpt3.5");
const { prompts } = require("./API/gpt-prompts");
const { blackbox } = require("./API/blackbox");
const { qwen } = require("./API/qwen");
const { gemini } = require("./API/gemini");

const WebSocket = require('ws');

const Bottleneck = require('bottleneck');

// Объект для хранения действий и состояния каждого клиента
const clientActions = {};
// Объект для хранения ограничителей по каждому клиенту
const limiters = {}; 

const wss = new WebSocket.Server({ port: 3000 });

wss.on('connection', (ws, req) => {
	const urlParams = new URLSearchParams(req.url.split('?')[1]);
    const userId = urlParams.get('token'); // Получаем UUID из URL
	let isProcessing = false; // Флаг для отслеживания обработки текущего сообщения
    console.log('Client connected with user ID:', userId);
	
	// Инициализируем состояние клиента, если его еще нет
    if (!clientActions[userId]) {
      clientActions[userId] = {
        actions: [], // Массив для хранения действий
        connected: true, // Статус подключения
      };
	  
	  // Создаем экземпляр Bottleneck для каждого клиента
      limiters[userId] = new Bottleneck({
          maxConcurrent: 1, // Максимальное количество одновременных задач
          minTime: 1000 // Минимальное время между запросами в миллисекундах
      });
    }

    ws.on('message', (message) => {
		// Проверяем, является ли сообщение экземпляром Buffer
		if (Buffer.isBuffer(message))
			message = message.toString(); 
		
		try {
			// Преобразуем строку JSON обратно в объект
			message = JSON.parse(message); 
			
			//Получаем историю чата из запроса
			messages = message.messages;
			
			// Проверяем, идет ли уже обработка
            if (isProcessing) {
                const response = { code: 2, message: "Пожалуйста, подождите, ваш предыдущий запрос еще обрабатывается." };
                if (ws.readyState === WebSocket.OPEN) {
                    ws.send(JSON.stringify(response));
                }
                return; // Останавливаем выполнение
            }

            // Устанавливаем флаг на время обработки
            isProcessing = true;
			
			// Используем Bottleneck для управления количеством запросов
            limiters[userId].schedule(() => {
				// Отправка запроса на сервер чата
                return call(messages, ws).finally(() => {
                    isProcessing = false; // Сбрасываем флаг при завершении
                }); 
            }).catch(error => {
                console.error('Rate limit exceeded, message ignored:', error);
                const response = { code: 2, message: "Превышен лимит запросов. Пожалуйста, попробуйте позже." };
				
				if (ws.readyState === WebSocket.OPEN) {
					ws.send(JSON.stringify(response));
				}
				isProcessing = false; // Сбрасываем флаг, если есть ошибка
            });
			
		} catch (error) {
				console.error('Error parsing JSON:', error);
				const response = { code: 2, message: "Произошла ошибка. Попробуйте еще раз."};
				console.log(response);
				
				if (ws.readyState === WebSocket.OPEN) {
					ws.send(JSON.stringify(response));
				}
				isProcessing = false; // Сбрасываем флаг для обработки ошибки JSONParsing
		}
		
    });

    ws.on('close', () => {
		clientActions[userId].connected = false; // Обновление статуса подключения
		delete clientActions[userId]; // Удаление состояния клиента
		delete limiters[userId]; // Удаление ограничителя для данного клиента
        console.log('Client disconnected');
    });
});


async function call(userMessage, ws) {
    try {
        let fullResponse = ""; // Переменная для результата
		
		console.log('Запрос клиента:', userMessage); 
		//throw new Error("Намеренная ошибка для тестирования catch");
        gpt4o({
            messages: userMessage,
            markdown: false
        }, (result) => {
            if (!result.finish) {
                // Запоминаем только последний ответ чата (он будет полный, промежуточные ответы - это накопления)
                fullResponse = result.message || "";
				//console.log(result);
            } else {
                // Если завершено, выводим полный ответ
				let response = { code: 1, message: fullResponse};
				console.log('Ответ чата: ', response);
				// Отправка ответа клиенту
				if (ws.readyState === WebSocket.OPEN) {
					ws.send(JSON.stringify(response));
				} else {
					console.warn(`Trying to send message to a closed WebSocket connection.`);
				}
            }
        });
    } catch (error) {
        console.error('Error:', error);
		let response = { code: 2, message: "Произогла ошибка. Попробуйте еще раз."};
		if (ws.readyState === WebSocket.OPEN) {
			ws.send(JSON.stringify(response));
		} else {
			console.warn(`Trying to send message to a closed WebSocket connection.`);
		}
    }
}

console.log('WebSocket сервер запущен через порт 3000');


Оцени код