2026-05-18 17:33:45 +03:00

328 lines
9.7 KiB
JavaScript

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);
},
};
};