import { Config } from '../conf/config'; export function openTaskSocket(taskId, onMessage) { try { const base = Config.API_URL || window.location.origin; const wsBase = base.replace(/^http/i, 'ws'); const url = `${wsBase}/ws/tasks/${taskId}`; const ws = new WebSocket(url); ws.onmessage = (evt) => { try { onMessage && onMessage(JSON.parse(evt.data)); } catch (error) { console.error('Ошибка подключения', error); } }; return ws; } catch (error) { console.error(error); return null; } } export const connectToTable = (tableId, userId, options = {}) => { const { onError, onClose } = options; const baseURL = Config.API_URL.replace('http://', 'ws://').replace( 'https://', 'wss://', ); const wsURL = `${baseURL}/api/v1/ws/${tableId}?user_id=${userId}`; const ws = new WebSocket(wsURL); const eventHandlers = { cell_edit_start: [], cell_edit_end: [], cell_updated: [], row_added: [], row_deleted: [], formula_updated: [], formula_manual: [], formula_recalculate: [], }; ws.onerror = (error) => { console.error('Ошибка WebSocket:', error); if (onError) { onError(error); } }; ws.onclose = (event) => { console.log( `Отключено от таблицы ${tableId}. Код: ${event.code}, причина: ${event.reason}`, ); if (onClose) { onClose(event); } }; ws.onmessage = (event) => { const raw = event.data; let message; try { message = JSON.parse(raw); } catch (_err) { try { let fixed = raw .replace(/'/g, '"') .replace(/\bNone\b/g, 'null') .replace(/\bTrue\b/g, 'true') .replace(/\bFalse\b/g, 'false'); if (fixed.includes('BasicFormulaDependancy')) { fixed = fixed.replace( /"dependancies"\s*:\s*\[\[[\s\S]*?\]\]/, '"dependancies":[[]]', ); } message = JSON.parse(fixed); } catch (error) { console.error('Ошибка парсинга сообщения WebSocket:', error, raw); return; } } const { event: eventName, data, error, result } = message; if (eventHandlers[eventName]) { const base = data || {}; const payload = { ...base, ...(result !== undefined ? { result } : {}), ...(error !== undefined ? { error } : {}), }; eventHandlers[eventName].forEach((handler) => handler(payload)); } }; return { ws, disconnect: () => { ws.close(); }, // Начало редактирования ячейки startEditCell: (cellKey) => { if (ws.readyState === WebSocket.OPEN) { const message = JSON.stringify({ event: 'cell_edit_start', data: { cell_key: cellKey, user_id: userId, }, }); ws.send(message); } }, // Завершение редактирования ячейки endEditCell: (cellKey) => { if (ws.readyState === WebSocket.OPEN) { const message = JSON.stringify({ event: 'cell_edit_end', data: { cell_key: cellKey, user_id: userId, }, }); ws.send(message); } }, // Подписка на событие начала редактирования ячейки другим пользователем onCellEditStart: (callback) => { eventHandlers.cell_edit_start.push(callback); }, offCellEditStart: (callback) => { eventHandlers.cell_edit_start = eventHandlers.cell_edit_start.filter( (cb) => cb !== callback, ); }, // Подписка на событие завершения редактирования ячейки другим пользователем onCellEditEnd: (callback) => { eventHandlers.cell_edit_end.push(callback); }, offCellEditEnd: (callback) => { eventHandlers.cell_edit_end = eventHandlers.cell_edit_end.filter( (cb) => cb !== callback, ); }, // Обновление значения ячейки (отправка нового значения другим пользователям) updateCellValue: (cellKey, newValue, cellType, cellColor) => { const [columnId, rowId] = cellKey.split('_'); if (ws.readyState === WebSocket.OPEN) { const message = JSON.stringify({ event: 'cell_updated', data: { row: Number(rowId) + 1, header_id: Number(columnId), cell_key: cellKey, color: cellColor, value: newValue, type: cellType, }, }); ws.send(message); } }, // Подписка на событие обновления значения ячейки другим пользователем onCellValueUpdated: (callback) => { eventHandlers.cell_updated.push(callback); }, offCellValueUpdated: (callback) => { eventHandlers.cell_updated = eventHandlers.cell_updated.filter( (cb) => cb !== callback, ); }, // Добавление строки (отправка события другим пользователям) addRow: (rowIndex) => { if (ws.readyState === WebSocket.OPEN) { const message = JSON.stringify({ event: 'row_added', data: { row_index: rowIndex, user_id: userId, }, }); ws.send(message); } }, // Подписка на событие добавления строки другим пользователем onRowAdded: (callback) => { eventHandlers.row_added.push(callback); }, offRowAdded: (callback) => { eventHandlers.row_added = eventHandlers.row_added.filter( (cb) => cb !== callback, ); }, // Удаление строки (отправка события другим пользователям) deleteRow: (rowIndex) => { if (ws.readyState === WebSocket.OPEN) { const message = JSON.stringify({ event: 'row_deleted', data: { row_index: rowIndex, user_id: userId, }, }); ws.send(message); } }, // Подписка на событие удаления строки другим пользователем onRowDeleted: (callback) => { eventHandlers.row_deleted.push(callback); }, offRowDeleted: (callback) => { eventHandlers.row_deleted = eventHandlers.row_deleted.filter( (cb) => cb !== callback, ); }, // Обновление цвета ячейки updateCellColor: (cellKey, color, cellType, cellValue) => { const [columnId, rowId] = cellKey.split('_'); if (ws.readyState === WebSocket.OPEN) { const message = JSON.stringify({ event: 'cell_updated', data: { row: Number(rowId) + 1, header_id: Number(columnId), cell_key: cellKey, color, type: cellType, value: cellValue, }, }); ws.send(message); } }, // Добавление/обновление формулы (отправка события другим пользователям) updateFormula: (cellKey, type, value, formula) => { const [columnId, rowId] = cellKey.split('_'); if (ws.readyState === WebSocket.OPEN) { const message = JSON.stringify({ event: 'formula_updated', data: { cell_key: cellKey, row: Number(rowId), header_id: Number(columnId), type, value, formula, user_id: userId, }, }); ws.send(message); } }, // Подписка на событие добавления/обновления формулы другим пользователем onFormulaUpdated: (callback) => { eventHandlers.formula_updated.push(callback); }, offFormulaUpdated: (callback) => { eventHandlers.formula_updated = eventHandlers.formula_updated.filter( (cb) => cb !== callback, ); }, // Ручное добавление формулы (отправка события другим пользователям) formulaManual: (formulaDatas) => { if (ws.readyState === WebSocket.OPEN) { const message = JSON.stringify({ event: 'formula_manual', data: { formula_datas: formulaDatas, }, }); ws.send(message); } }, // Подписка на результат ручного добавления формулы onFormulaManual: (callback) => { eventHandlers.formula_manual.push(callback); }, offFormulaManual: (callback) => { eventHandlers.formula_manual = eventHandlers.formula_manual.filter( (cb) => cb !== callback, ); }, // Пересчёт формул (отправка события другим пользователям / на бэкенд) formulaRecalculate: (formulaDatas, cells) => { if (ws.readyState === WebSocket.OPEN) { const message = JSON.stringify({ event: 'formula_recalculate', data: { formula_datas: formulaDatas, cells, }, }); ws.send(message); } }, // Подписка на результат пересчёта формул onFormulaRecalculate: (callback) => { eventHandlers.formula_recalculate.push(callback); }, offFormulaRecalculate: (callback) => { eventHandlers.formula_recalculate = eventHandlers.formula_recalculate.filter((cb) => cb !== callback); }, }; };