solver-sdk 2.8.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +200 -368
- package/dist/cjs/api/chat-api/index.js +23 -49
- package/dist/cjs/api/chat-api/index.js.map +1 -1
- package/dist/cjs/api/chat-api/interfaces.js +1 -0
- package/dist/cjs/api/chat-api/interfaces.js.map +1 -1
- package/dist/cjs/api/context-api.js +6 -1
- package/dist/cjs/api/context-api.js.map +1 -1
- package/dist/cjs/api/models-api.js +43 -60
- package/dist/cjs/api/models-api.js.map +1 -1
- package/dist/cjs/api/projects-api.js +63 -293
- package/dist/cjs/api/projects-api.js.map +1 -1
- package/dist/cjs/api/search-api.js +131 -8
- package/dist/cjs/api/search-api.js.map +1 -1
- package/dist/cjs/code-solver-sdk.js +68 -322
- package/dist/cjs/code-solver-sdk.js.map +1 -1
- package/dist/cjs/index.js +3 -19
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/utils/logger.js +4 -4
- package/dist/cjs/utils/logger.js.map +1 -1
- package/dist/esm/api/chat-api/index.js +22 -48
- package/dist/esm/api/chat-api/index.js.map +1 -1
- package/dist/esm/api/chat-api/interfaces.js +1 -0
- package/dist/esm/api/chat-api/interfaces.js.map +1 -1
- package/dist/esm/api/context-api.js +6 -1
- package/dist/esm/api/context-api.js.map +1 -1
- package/dist/esm/api/models-api.js +43 -60
- package/dist/esm/api/models-api.js.map +1 -1
- package/dist/esm/api/projects-api.js +63 -293
- package/dist/esm/api/projects-api.js.map +1 -1
- package/dist/esm/api/search-api.js +131 -8
- package/dist/esm/api/search-api.js.map +1 -1
- package/dist/esm/code-solver-sdk.js +68 -322
- package/dist/esm/code-solver-sdk.js.map +1 -1
- package/dist/esm/index.js +2 -18
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/utils/logger.js +3 -3
- package/dist/esm/utils/logger.js.map +1 -1
- package/dist/types/api/chat-api/index.d.ts +1 -13
- package/dist/types/api/chat-api/index.d.ts.map +1 -1
- package/dist/types/api/chat-api/interfaces.d.ts +6 -54
- package/dist/types/api/chat-api/interfaces.d.ts.map +1 -1
- package/dist/types/api/chat-api/models.d.ts +3 -26
- package/dist/types/api/chat-api/models.d.ts.map +1 -1
- package/dist/types/api/context-api.d.ts.map +1 -1
- package/dist/types/api/models-api.d.ts +31 -62
- package/dist/types/api/models-api.d.ts.map +1 -1
- package/dist/types/api/projects-api.d.ts +47 -126
- package/dist/types/api/projects-api.d.ts.map +1 -1
- package/dist/types/api/search-api.d.ts +147 -6
- package/dist/types/api/search-api.d.ts.map +1 -1
- package/dist/types/code-solver-sdk.d.ts +36 -86
- package/dist/types/code-solver-sdk.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -14
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/interfaces/sdk-options.d.ts +18 -66
- package/dist/types/interfaces/sdk-options.d.ts.map +1 -1
- package/dist/types/utils/logger.d.ts +3 -3
- package/dist/types/utils/logger.d.ts.map +1 -1
- package/docs/README.md +53 -37
- package/docs/VSCODE_INTEGRATION.md +208 -371
- package/docs/indexing/INDEXING.md +658 -335
- package/package.json +26 -23
- package/dist/cjs/api/agents-api.js +0 -94
- package/dist/cjs/api/agents-api.js.map +0 -1
- package/dist/cjs/api/chat-api/websocket-helpers.js +0 -211
- package/dist/cjs/api/chat-api/websocket-helpers.js.map +0 -1
- package/dist/cjs/api/dependencies-api.js +0 -286
- package/dist/cjs/api/dependencies-api.js.map +0 -1
- package/dist/cjs/constants/websocket-events.constants.js +0 -170
- package/dist/cjs/constants/websocket-events.constants.js.map +0 -1
- package/dist/cjs/constants/websocket-namespaces.constants.js +0 -22
- package/dist/cjs/constants/websocket-namespaces.constants.js.map +0 -1
- package/dist/cjs/interfaces/websocket/callbacks.interfaces.js +0 -3
- package/dist/cjs/interfaces/websocket/callbacks.interfaces.js.map +0 -1
- package/dist/cjs/interfaces/websocket/client-options.interfaces.js +0 -3
- package/dist/cjs/interfaces/websocket/client-options.interfaces.js.map +0 -1
- package/dist/cjs/interfaces/websocket/events.interfaces.js +0 -3
- package/dist/cjs/interfaces/websocket/events.interfaces.js.map +0 -1
- package/dist/cjs/interfaces/websocket/vscode-command.interfaces.js +0 -42
- package/dist/cjs/interfaces/websocket/vscode-command.interfaces.js.map +0 -1
- package/dist/cjs/simple-indexing-client.js +0 -138
- package/dist/cjs/simple-indexing-client.js.map +0 -1
- package/dist/cjs/utils/code-solver-websocket-client.js +0 -497
- package/dist/cjs/utils/code-solver-websocket-client.js.map +0 -1
- package/dist/cjs/utils/connection-state-manager.js +0 -133
- package/dist/cjs/utils/connection-state-manager.js.map +0 -1
- package/dist/cjs/utils/indexing-websocket-client.js +0 -107
- package/dist/cjs/utils/indexing-websocket-client.js.map +0 -1
- package/dist/cjs/utils/session-manager.js +0 -114
- package/dist/cjs/utils/session-manager.js.map +0 -1
- package/dist/cjs/utils/simple-connection-monitor.js +0 -52
- package/dist/cjs/utils/simple-connection-monitor.js.map +0 -1
- package/dist/cjs/utils/websocket-client.js +0 -638
- package/dist/cjs/utils/websocket-client.js.map +0 -1
- package/dist/cjs/ws/base-ws-client.js +0 -280
- package/dist/cjs/ws/base-ws-client.js.map +0 -1
- package/dist/cjs/ws/dependencies-ws-client.js +0 -11
- package/dist/cjs/ws/dependencies-ws-client.js.map +0 -1
- package/dist/cjs/ws/file-editing-ws-client.js +0 -162
- package/dist/cjs/ws/file-editing-ws-client.js.map +0 -1
- package/dist/cjs/ws/filesystem-ws-client.js +0 -305
- package/dist/cjs/ws/filesystem-ws-client.js.map +0 -1
- package/dist/cjs/ws/indexing-ws-client.js +0 -275
- package/dist/cjs/ws/indexing-ws-client.js.map +0 -1
- package/dist/cjs/ws/notifications-ws-client.js +0 -12
- package/dist/cjs/ws/notifications-ws-client.js.map +0 -1
- package/dist/esm/api/agents-api.js +0 -90
- package/dist/esm/api/agents-api.js.map +0 -1
- package/dist/esm/api/chat-api/websocket-helpers.js +0 -205
- package/dist/esm/api/chat-api/websocket-helpers.js.map +0 -1
- package/dist/esm/api/dependencies-api.js +0 -282
- package/dist/esm/api/dependencies-api.js.map +0 -1
- package/dist/esm/constants/websocket-events.constants.js +0 -167
- package/dist/esm/constants/websocket-events.constants.js.map +0 -1
- package/dist/esm/constants/websocket-namespaces.constants.js +0 -19
- package/dist/esm/constants/websocket-namespaces.constants.js.map +0 -1
- package/dist/esm/interfaces/websocket/callbacks.interfaces.js +0 -2
- package/dist/esm/interfaces/websocket/callbacks.interfaces.js.map +0 -1
- package/dist/esm/interfaces/websocket/client-options.interfaces.js +0 -2
- package/dist/esm/interfaces/websocket/client-options.interfaces.js.map +0 -1
- package/dist/esm/interfaces/websocket/events.interfaces.js +0 -2
- package/dist/esm/interfaces/websocket/events.interfaces.js.map +0 -1
- package/dist/esm/interfaces/websocket/vscode-command.interfaces.js +0 -39
- package/dist/esm/interfaces/websocket/vscode-command.interfaces.js.map +0 -1
- package/dist/esm/simple-indexing-client.js +0 -134
- package/dist/esm/simple-indexing-client.js.map +0 -1
- package/dist/esm/utils/code-solver-websocket-client.js +0 -492
- package/dist/esm/utils/code-solver-websocket-client.js.map +0 -1
- package/dist/esm/utils/connection-state-manager.js +0 -129
- package/dist/esm/utils/connection-state-manager.js.map +0 -1
- package/dist/esm/utils/indexing-websocket-client.js +0 -103
- package/dist/esm/utils/indexing-websocket-client.js.map +0 -1
- package/dist/esm/utils/session-manager.js +0 -109
- package/dist/esm/utils/session-manager.js.map +0 -1
- package/dist/esm/utils/simple-connection-monitor.js +0 -48
- package/dist/esm/utils/simple-connection-monitor.js.map +0 -1
- package/dist/esm/utils/websocket-client.js +0 -634
- package/dist/esm/utils/websocket-client.js.map +0 -1
- package/dist/esm/ws/base-ws-client.js +0 -276
- package/dist/esm/ws/base-ws-client.js.map +0 -1
- package/dist/esm/ws/dependencies-ws-client.js +0 -7
- package/dist/esm/ws/dependencies-ws-client.js.map +0 -1
- package/dist/esm/ws/file-editing-ws-client.js +0 -158
- package/dist/esm/ws/file-editing-ws-client.js.map +0 -1
- package/dist/esm/ws/filesystem-ws-client.js +0 -301
- package/dist/esm/ws/filesystem-ws-client.js.map +0 -1
- package/dist/esm/ws/indexing-ws-client.js +0 -271
- package/dist/esm/ws/indexing-ws-client.js.map +0 -1
- package/dist/esm/ws/notifications-ws-client.js +0 -8
- package/dist/esm/ws/notifications-ws-client.js.map +0 -1
- package/dist/types/api/agents-api.d.ts +0 -141
- package/dist/types/api/agents-api.d.ts.map +0 -1
- package/dist/types/api/chat-api/websocket-helpers.d.ts +0 -40
- package/dist/types/api/chat-api/websocket-helpers.d.ts.map +0 -1
- package/dist/types/api/dependencies-api.d.ts +0 -109
- package/dist/types/api/dependencies-api.d.ts.map +0 -1
- package/dist/types/constants/websocket-events.constants.d.ts +0 -144
- package/dist/types/constants/websocket-events.constants.d.ts.map +0 -1
- package/dist/types/constants/websocket-namespaces.constants.d.ts +0 -17
- package/dist/types/constants/websocket-namespaces.constants.d.ts.map +0 -1
- package/dist/types/interfaces/websocket/callbacks.interfaces.d.ts +0 -30
- package/dist/types/interfaces/websocket/callbacks.interfaces.d.ts.map +0 -1
- package/dist/types/interfaces/websocket/client-options.interfaces.d.ts +0 -51
- package/dist/types/interfaces/websocket/client-options.interfaces.d.ts.map +0 -1
- package/dist/types/interfaces/websocket/events.interfaces.d.ts +0 -165
- package/dist/types/interfaces/websocket/events.interfaces.d.ts.map +0 -1
- package/dist/types/interfaces/websocket/vscode-command.interfaces.d.ts +0 -56
- package/dist/types/interfaces/websocket/vscode-command.interfaces.d.ts.map +0 -1
- package/dist/types/simple-indexing-client.d.ts +0 -66
- package/dist/types/simple-indexing-client.d.ts.map +0 -1
- package/dist/types/utils/code-solver-websocket-client.d.ts +0 -144
- package/dist/types/utils/code-solver-websocket-client.d.ts.map +0 -1
- package/dist/types/utils/connection-state-manager.d.ts +0 -94
- package/dist/types/utils/connection-state-manager.d.ts.map +0 -1
- package/dist/types/utils/indexing-websocket-client.d.ts +0 -123
- package/dist/types/utils/indexing-websocket-client.d.ts.map +0 -1
- package/dist/types/utils/session-manager.d.ts +0 -98
- package/dist/types/utils/session-manager.d.ts.map +0 -1
- package/dist/types/utils/simple-connection-monitor.d.ts +0 -26
- package/dist/types/utils/simple-connection-monitor.d.ts.map +0 -1
- package/dist/types/utils/websocket-client.d.ts +0 -233
- package/dist/types/utils/websocket-client.d.ts.map +0 -1
- package/dist/types/ws/base-ws-client.d.ts +0 -119
- package/dist/types/ws/base-ws-client.d.ts.map +0 -1
- package/dist/types/ws/dependencies-ws-client.d.ts +0 -6
- package/dist/types/ws/dependencies-ws-client.d.ts.map +0 -1
- package/dist/types/ws/file-editing-ws-client.d.ts +0 -85
- package/dist/types/ws/file-editing-ws-client.d.ts.map +0 -1
- package/dist/types/ws/filesystem-ws-client.d.ts +0 -201
- package/dist/types/ws/filesystem-ws-client.d.ts.map +0 -1
- package/dist/types/ws/indexing-ws-client.d.ts +0 -94
- package/dist/types/ws/indexing-ws-client.d.ts.map +0 -1
- package/dist/types/ws/notifications-ws-client.d.ts +0 -5
- package/dist/types/ws/notifications-ws-client.d.ts.map +0 -1
- package/docs/ARCHITECTURE.md +0 -268
- package/docs/QUICK_START.md +0 -126
- package/docs/WEBSOCKET.md +0 -472
|
@@ -1,634 +0,0 @@
|
|
|
1
|
-
// Импортируем Socket.IO клиент
|
|
2
|
-
import { io } from 'socket.io-client';
|
|
3
|
-
/**
|
|
4
|
-
* Базовый класс для WebSocket клиентов, реализованный на базе Socket.IO
|
|
5
|
-
*/
|
|
6
|
-
export class WebSocketClient {
|
|
7
|
-
/**
|
|
8
|
-
* Создает новый WebSocket клиент
|
|
9
|
-
* @param {string} url URL для подключения
|
|
10
|
-
* @param {WebSocketClientOptions} [options] Опции клиента
|
|
11
|
-
*/
|
|
12
|
-
constructor(url, options = {}) {
|
|
13
|
-
/** Экземпляр Socket.IO */
|
|
14
|
-
this.socket = null;
|
|
15
|
-
/** Счетчик попыток переподключения */
|
|
16
|
-
this.retryCount = 0;
|
|
17
|
-
/** Флаг, указывающий, что соединение было закрыто намеренно */
|
|
18
|
-
this.intentionallyClosed = false;
|
|
19
|
-
/** Таймер переподключения */
|
|
20
|
-
this.reconnectTimer = null;
|
|
21
|
-
/** Таймер таймаута соединения */
|
|
22
|
-
this.connectionTimeoutTimer = null;
|
|
23
|
-
/** Обработчики событий */
|
|
24
|
-
this.eventHandlers = {};
|
|
25
|
-
/** Очередь сообщений для отправки после подключения */
|
|
26
|
-
this.messageQueue = [];
|
|
27
|
-
/** Состояние соединения */
|
|
28
|
-
this.connected = false;
|
|
29
|
-
/** Аутентифицировано ли соединение */
|
|
30
|
-
this.authenticated = false;
|
|
31
|
-
/** ID сокета */
|
|
32
|
-
this.socketId = null;
|
|
33
|
-
/** Хранилище ожидающих callback-функций */
|
|
34
|
-
this._pendingCallbacks = new Map();
|
|
35
|
-
/** Таймер проверки состояния соединения */
|
|
36
|
-
this.healthCheckTimer = null;
|
|
37
|
-
/** Время последнего полученного pong */
|
|
38
|
-
this.lastPongTimestamp = 0;
|
|
39
|
-
/** Интервал проверки здоровья соединения */
|
|
40
|
-
this.healthCheckInterval = 10000;
|
|
41
|
-
/**
|
|
42
|
-
* Тип для хранения отложенных обработчиков событий
|
|
43
|
-
* @private
|
|
44
|
-
*/
|
|
45
|
-
this._pendingCallbackHandlers = new Map();
|
|
46
|
-
this.url = url;
|
|
47
|
-
this.options = {
|
|
48
|
-
headers: options.headers || {},
|
|
49
|
-
connectionTimeout: options.connectionTimeout || 30000,
|
|
50
|
-
protocols: options.protocols || [],
|
|
51
|
-
maxRetries: options.maxRetries || 5,
|
|
52
|
-
retryDelay: options.retryDelay || 1000,
|
|
53
|
-
maxRetryDelay: options.maxRetryDelay || 30000,
|
|
54
|
-
autoReconnect: options.autoReconnect !== undefined ? options.autoReconnect : true,
|
|
55
|
-
rejectUnauthorized: options.rejectUnauthorized !== undefined ? options.rejectUnauthorized : true,
|
|
56
|
-
apiKey: options.apiKey || '',
|
|
57
|
-
namespace: options.namespace || '',
|
|
58
|
-
logger: options.logger,
|
|
59
|
-
pingInterval: options.pingInterval || 25000,
|
|
60
|
-
pingTimeout: options.pingTimeout || 60000,
|
|
61
|
-
debug: options.debug || false
|
|
62
|
-
};
|
|
63
|
-
// Определяем среду выполнения
|
|
64
|
-
this.isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';
|
|
65
|
-
// Инициализируем пространство имен
|
|
66
|
-
this.namespace = this.options.namespace || '';
|
|
67
|
-
// Если namespace не начинается с /, добавляем его
|
|
68
|
-
if (this.namespace && !this.namespace.startsWith('/')) {
|
|
69
|
-
this.namespace = '/' + this.namespace;
|
|
70
|
-
}
|
|
71
|
-
// Инициализируем логгер
|
|
72
|
-
this.logger = this.options.logger || ((level, message, data) => {
|
|
73
|
-
if (level === 'error') {
|
|
74
|
-
console.error(`[WebSocketClient] ${message}`, data);
|
|
75
|
-
}
|
|
76
|
-
else if (level === 'warn') {
|
|
77
|
-
console.warn(`[WebSocketClient] ${message}`, data);
|
|
78
|
-
}
|
|
79
|
-
else if (level === 'info') {
|
|
80
|
-
console.info(`[WebSocketClient] ${message}`, data);
|
|
81
|
-
}
|
|
82
|
-
else if (level === 'debug' && process.env.NODE_ENV === 'development') {
|
|
83
|
-
console.debug(`[WebSocketClient] ${message}`, data);
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
// Логирование конфигурации при создании клиента
|
|
87
|
-
this.logger('info', 'Создан WebSocket клиент', {
|
|
88
|
-
url: this.url,
|
|
89
|
-
namespace: this.namespace,
|
|
90
|
-
hasApiKey: !!this.options.apiKey,
|
|
91
|
-
apiKeyLength: this.options.apiKey ? this.options.apiKey.length : 0,
|
|
92
|
-
connectionTimeout: this.options.connectionTimeout,
|
|
93
|
-
autoReconnect: this.options.autoReconnect,
|
|
94
|
-
maxRetries: this.options.maxRetries
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Получает WebSocket URL из HTTP URL
|
|
99
|
-
* @returns {string} WebSocket URL
|
|
100
|
-
* @private
|
|
101
|
-
*/
|
|
102
|
-
getWebSocketURL() {
|
|
103
|
-
let wsUrl = this.url;
|
|
104
|
-
// Замена протокола
|
|
105
|
-
if (wsUrl.startsWith('http://')) {
|
|
106
|
-
wsUrl = wsUrl.replace('http://', 'ws://');
|
|
107
|
-
}
|
|
108
|
-
else if (wsUrl.startsWith('https://')) {
|
|
109
|
-
wsUrl = wsUrl.replace('https://', 'wss://');
|
|
110
|
-
}
|
|
111
|
-
else if (!wsUrl.startsWith('ws://') && !wsUrl.startsWith('wss://')) {
|
|
112
|
-
// Если URL не содержит протокол, добавляем ws://
|
|
113
|
-
wsUrl = 'ws://' + wsUrl;
|
|
114
|
-
}
|
|
115
|
-
// Удаляем слеш в конце URL если он есть
|
|
116
|
-
if (wsUrl.endsWith('/')) {
|
|
117
|
-
wsUrl = wsUrl.slice(0, -1);
|
|
118
|
-
}
|
|
119
|
-
return wsUrl;
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Подключается к WebSocket серверу используя Socket.IO клиент
|
|
123
|
-
* @returns {Promise<void>}
|
|
124
|
-
*/
|
|
125
|
-
connect() {
|
|
126
|
-
// Если соединение уже установлено, возвращаем Promise.resolve
|
|
127
|
-
if (this.isConnected()) {
|
|
128
|
-
this.logger('debug', 'Соединение уже установлено, пропускаем повторное подключение');
|
|
129
|
-
return Promise.resolve();
|
|
130
|
-
}
|
|
131
|
-
// Сбрасываем таймер reconnect
|
|
132
|
-
if (this.reconnectTimer) {
|
|
133
|
-
clearTimeout(this.reconnectTimer);
|
|
134
|
-
this.reconnectTimer = null;
|
|
135
|
-
}
|
|
136
|
-
return new Promise((resolve, reject) => {
|
|
137
|
-
try {
|
|
138
|
-
// Получаем WebSocket URL из http/https URL
|
|
139
|
-
const wsUrl = this.getWebSocketURL();
|
|
140
|
-
const namespaceStr = this.options.namespace || '';
|
|
141
|
-
this.logger('debug', `Подключение к ${wsUrl}${namespaceStr}`);
|
|
142
|
-
// Настройки для Socket.IO клиента
|
|
143
|
-
const socketOptions = {
|
|
144
|
-
path: '/socket.io', // Устанавливаем путь без слеша в конце
|
|
145
|
-
transports: ['websocket', 'polling'], // Поддерживаем оба транспорта
|
|
146
|
-
reconnection: this.options.autoReconnect, // Автоматическое переподключение
|
|
147
|
-
reconnectionAttempts: this.options.maxRetries, // Количество попыток
|
|
148
|
-
reconnectionDelay: this.options.retryDelay, // Задержка между попытками
|
|
149
|
-
timeout: this.options.connectionTimeout, // Таймаут соединения
|
|
150
|
-
forceNew: true, // Создавать новое соединение
|
|
151
|
-
extraHeaders: this.options.headers, // HTTP заголовки
|
|
152
|
-
rejectUnauthorized: this.options.rejectUnauthorized, // Проверка сертификатов
|
|
153
|
-
pingTimeout: this.options.pingTimeout, // Явно устанавливаем таймаут для ping
|
|
154
|
-
pingInterval: this.options.pingInterval, // Явно устанавливаем интервал ping
|
|
155
|
-
debug: this.options.debug
|
|
156
|
-
};
|
|
157
|
-
// Если указан API ключ, добавляем его в query и auth
|
|
158
|
-
if (this.options.apiKey) {
|
|
159
|
-
socketOptions.auth = { token: this.options.apiKey };
|
|
160
|
-
socketOptions.query = { token: this.options.apiKey };
|
|
161
|
-
}
|
|
162
|
-
// Создаем Socket.IO клиент с namespace
|
|
163
|
-
this.socket = io(wsUrl + namespaceStr, socketOptions);
|
|
164
|
-
// Устанавливаем таймаут соединения
|
|
165
|
-
this.connectionTimeoutTimer = setTimeout(() => {
|
|
166
|
-
if (this.socket && !this.socket.connected) {
|
|
167
|
-
const error = new Error('Таймаут подключения WebSocket');
|
|
168
|
-
this.logger('error', 'Превышен таймаут подключения', { timeout: this.options.connectionTimeout });
|
|
169
|
-
reject(error);
|
|
170
|
-
this.close();
|
|
171
|
-
}
|
|
172
|
-
}, this.options.connectionTimeout);
|
|
173
|
-
// Обработчик успешного подключения
|
|
174
|
-
this.socket.on('connect', () => {
|
|
175
|
-
clearTimeout(this.connectionTimeoutTimer);
|
|
176
|
-
this.retryCount = 0;
|
|
177
|
-
this.connected = true;
|
|
178
|
-
this.socketId = this.socket?.id || null;
|
|
179
|
-
this.logger('info', 'WebSocket соединение установлено', { socketId: this.socketId });
|
|
180
|
-
// Отладка Socket.IO handshake
|
|
181
|
-
const engine = this.socket ? this.socket.io?.engine : null;
|
|
182
|
-
if (engine) {
|
|
183
|
-
this.logger('debug', 'Socket.IO engine настройки:', {
|
|
184
|
-
pingInterval: engine.pingInterval,
|
|
185
|
-
pingTimeout: engine.pingTimeout,
|
|
186
|
-
transport: engine.transport?.name
|
|
187
|
-
});
|
|
188
|
-
// Отслеживаем ping-pong обмен
|
|
189
|
-
engine.on('ping', () => {
|
|
190
|
-
this.logger('debug', 'Socket.IO engine отправил ping');
|
|
191
|
-
// Явно пытаемся стимулировать ответ pong от сервера
|
|
192
|
-
if (this.socket && this.socket.connected) {
|
|
193
|
-
// Отправляем простое эхо-событие, чтобы сервер отреагировал
|
|
194
|
-
this.socket.emit('_ping_check', { timestamp: Date.now() });
|
|
195
|
-
}
|
|
196
|
-
});
|
|
197
|
-
engine.on('pong', () => {
|
|
198
|
-
this.logger('debug', 'Socket.IO engine получил pong');
|
|
199
|
-
// Сбрасываем флаг неактивности
|
|
200
|
-
this.lastPongTimestamp = Date.now();
|
|
201
|
-
});
|
|
202
|
-
// Ловим ошибки транспорта
|
|
203
|
-
if (engine.transport) {
|
|
204
|
-
engine.transport.on('error', (err) => {
|
|
205
|
-
this.logger('error', `Socket.IO transport ошибка: ${err.message}`, err);
|
|
206
|
-
});
|
|
207
|
-
// При смене транспорта
|
|
208
|
-
engine.on('upgrade', (transport) => {
|
|
209
|
-
this.logger('info', `Socket.IO transport обновлен до ${transport.name}`);
|
|
210
|
-
});
|
|
211
|
-
// При отключении по таймауту
|
|
212
|
-
engine.on('close', (reason) => {
|
|
213
|
-
this.logger('warn', `Socket.IO engine закрыт по причине: ${reason}`);
|
|
214
|
-
if (reason === 'ping timeout') {
|
|
215
|
-
this.logger('error', 'Соединение потеряно из-за таймаута ping-pong обмена!');
|
|
216
|
-
// Запускаем процесс переподключения, если это необходимо
|
|
217
|
-
if (this.options.autoReconnect && !this.intentionallyClosed) {
|
|
218
|
-
this.reconnect();
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
// Отслеживаем серверные события ping/pong
|
|
225
|
-
if (this.socket) {
|
|
226
|
-
this.socket.on('_ping', (data, callback) => {
|
|
227
|
-
this.logger('debug', 'Получен _ping от сервера');
|
|
228
|
-
if (typeof callback === 'function') {
|
|
229
|
-
callback({ pong: true, clientTime: Date.now() });
|
|
230
|
-
}
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
// Устанавливаем поллинг для проверки состояния соединения
|
|
234
|
-
this.setupConnectionHealthCheck();
|
|
235
|
-
// Отправляем сообщения из очереди
|
|
236
|
-
while (this.messageQueue.length > 0) {
|
|
237
|
-
const message = this.messageQueue.shift();
|
|
238
|
-
if (message && this.socket && this.socket.connected) {
|
|
239
|
-
if (typeof message === 'object' && message.event) {
|
|
240
|
-
this.socket.emit(message.event, message.data);
|
|
241
|
-
}
|
|
242
|
-
else {
|
|
243
|
-
// Поддержка старого формата сообщений
|
|
244
|
-
this.socket.send(message);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
resolve();
|
|
249
|
-
this.dispatchEvent('open', {});
|
|
250
|
-
});
|
|
251
|
-
// Обработчик ошибок соединения
|
|
252
|
-
this.socket.on('connect_error', (error) => {
|
|
253
|
-
clearTimeout(this.connectionTimeoutTimer);
|
|
254
|
-
this.logger('error', 'Ошибка соединения WebSocket', {
|
|
255
|
-
message: error.message,
|
|
256
|
-
name: error.name,
|
|
257
|
-
stack: error.stack
|
|
258
|
-
});
|
|
259
|
-
this.dispatchEvent('error', error);
|
|
260
|
-
if (!this.connected) {
|
|
261
|
-
reject(new Error('Ошибка подключения WebSocket'));
|
|
262
|
-
}
|
|
263
|
-
});
|
|
264
|
-
// Обработчик закрытия соединения
|
|
265
|
-
this.socket.on('disconnect', (reason) => {
|
|
266
|
-
clearTimeout(this.connectionTimeoutTimer);
|
|
267
|
-
this.connected = false;
|
|
268
|
-
this.logger('info', `WebSocket соединение закрыто: ${reason}`);
|
|
269
|
-
// Формируем объект события для совместимости с WebSocket API
|
|
270
|
-
const closeEvent = {
|
|
271
|
-
code: this.getCloseCodeFromReason(reason),
|
|
272
|
-
reason: reason
|
|
273
|
-
};
|
|
274
|
-
this.dispatchEvent('close', closeEvent);
|
|
275
|
-
// Если соединение было закрыто намеренно, не пытаемся переподключиться
|
|
276
|
-
if (this.intentionallyClosed) {
|
|
277
|
-
return;
|
|
278
|
-
}
|
|
279
|
-
});
|
|
280
|
-
// Обработчик всех сообщений, используем 'message' для совместимости
|
|
281
|
-
this.socket.onAny((eventName, ...args) => {
|
|
282
|
-
// Отправляем в обработчик события по имени события
|
|
283
|
-
this.dispatchEvent(eventName, args.length === 1 ? args[0] : args);
|
|
284
|
-
// Также отправляем событие message для совместимости
|
|
285
|
-
this.dispatchEvent('message', {
|
|
286
|
-
event: eventName,
|
|
287
|
-
data: args.length === 1 ? args[0] : args
|
|
288
|
-
});
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
|
-
catch (error) {
|
|
292
|
-
clearTimeout(this.connectionTimeoutTimer);
|
|
293
|
-
this.logger('error', 'Ошибка при создании Socket.IO клиента', error);
|
|
294
|
-
reject(error);
|
|
295
|
-
}
|
|
296
|
-
});
|
|
297
|
-
}
|
|
298
|
-
/**
|
|
299
|
-
* Получает код закрытия WebSocket из строки причины Socket.IO
|
|
300
|
-
* @param {string} reason Причина закрытия Socket.IO
|
|
301
|
-
* @returns {number} Код закрытия WebSocket
|
|
302
|
-
* @private
|
|
303
|
-
*/
|
|
304
|
-
getCloseCodeFromReason(reason) {
|
|
305
|
-
switch (reason) {
|
|
306
|
-
case 'io server disconnect':
|
|
307
|
-
return 1000; // Нормальное закрытие соединения сервером
|
|
308
|
-
case 'io client disconnect':
|
|
309
|
-
return 1000; // Нормальное закрытие соединения клиентом
|
|
310
|
-
case 'ping timeout':
|
|
311
|
-
return 1001; // Выход из соединения по таймауту
|
|
312
|
-
case 'transport close':
|
|
313
|
-
return 1006; // Аномальное закрытие соединения
|
|
314
|
-
case 'transport error':
|
|
315
|
-
return 1002; // Протокольная ошибка
|
|
316
|
-
default:
|
|
317
|
-
return 1000; // По умолчанию - нормальное закрытие
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
/**
|
|
321
|
-
* Настраивает проверку состояния соединения для обнаружения "зависших" подключений
|
|
322
|
-
* @private
|
|
323
|
-
*/
|
|
324
|
-
setupConnectionHealthCheck() {
|
|
325
|
-
// Очищаем предыдущий таймер, если он был
|
|
326
|
-
if (this.healthCheckTimer) {
|
|
327
|
-
clearInterval(this.healthCheckTimer);
|
|
328
|
-
this.healthCheckTimer = null;
|
|
329
|
-
}
|
|
330
|
-
// Устанавливаем начальное время pong
|
|
331
|
-
this.lastPongTimestamp = Date.now();
|
|
332
|
-
// Создаем новый таймер для регулярной проверки
|
|
333
|
-
this.healthCheckTimer = setInterval(() => {
|
|
334
|
-
if (!this.socket || !this.connected)
|
|
335
|
-
return;
|
|
336
|
-
const now = Date.now();
|
|
337
|
-
const lastPongAge = now - this.lastPongTimestamp;
|
|
338
|
-
// Если прошло больше 2*pingInterval мс с последнего pong, возможно соединение зависло
|
|
339
|
-
if (lastPongAge > 2 * (this.options.pingInterval || 25000)) {
|
|
340
|
-
this.logger('warn', `Возможно зависшее соединение: ${lastPongAge}ms с последнего pong`);
|
|
341
|
-
// Отправляем тестовое сообщение для проверки соединения
|
|
342
|
-
const socket = this.socket; // Сохраняем ссылку на сокет в переменную
|
|
343
|
-
if (socket && socket.connected) {
|
|
344
|
-
socket.emit('_health_check', { timestamp: now }, (response) => {
|
|
345
|
-
if (response && response.success) {
|
|
346
|
-
this.logger('debug', 'Соединение активно, получен ответ на _health_check');
|
|
347
|
-
this.lastPongTimestamp = Date.now();
|
|
348
|
-
}
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
}, this.healthCheckInterval);
|
|
353
|
-
}
|
|
354
|
-
/**
|
|
355
|
-
* Останавливает проверку состояния соединения
|
|
356
|
-
* @private
|
|
357
|
-
*/
|
|
358
|
-
stopConnectionHealthCheck() {
|
|
359
|
-
if (this.healthCheckTimer) {
|
|
360
|
-
clearInterval(this.healthCheckTimer);
|
|
361
|
-
this.healthCheckTimer = null;
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
/**
|
|
365
|
-
* Закрывает соединение WebSocket
|
|
366
|
-
* @param {number} code Код закрытия
|
|
367
|
-
* @param {string} reason Причина закрытия
|
|
368
|
-
*/
|
|
369
|
-
close(code = 1000, reason = 'Closed by client') {
|
|
370
|
-
this.intentionallyClosed = true;
|
|
371
|
-
// Останавливаем проверку здоровья соединения
|
|
372
|
-
this.stopConnectionHealthCheck();
|
|
373
|
-
// Очищаем таймеры
|
|
374
|
-
if (this.reconnectTimer) {
|
|
375
|
-
clearTimeout(this.reconnectTimer);
|
|
376
|
-
this.reconnectTimer = null;
|
|
377
|
-
}
|
|
378
|
-
if (this.connectionTimeoutTimer) {
|
|
379
|
-
clearTimeout(this.connectionTimeoutTimer);
|
|
380
|
-
this.connectionTimeoutTimer = null;
|
|
381
|
-
}
|
|
382
|
-
// Закрываем соединение
|
|
383
|
-
if (this.socket) {
|
|
384
|
-
this.logger('info', 'Закрытие WebSocket соединения', { code, reason });
|
|
385
|
-
if (this.socket.connected) {
|
|
386
|
-
this.socket.disconnect();
|
|
387
|
-
}
|
|
388
|
-
this.connected = false;
|
|
389
|
-
this.socket = null;
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
/**
|
|
393
|
-
* Отправляет сообщение в WebSocket
|
|
394
|
-
* @param {any} data Данные для отправки
|
|
395
|
-
* @returns {boolean} Успешно ли отправлено сообщение
|
|
396
|
-
*/
|
|
397
|
-
send(data) {
|
|
398
|
-
try {
|
|
399
|
-
// Если соединение еще не установлено, добавляем сообщение в очередь
|
|
400
|
-
if (!this.socket || !this.socket.connected) {
|
|
401
|
-
this.messageQueue.push(data);
|
|
402
|
-
return true;
|
|
403
|
-
}
|
|
404
|
-
// Обработка разных типов сообщений для совместимости
|
|
405
|
-
if (typeof data === 'object') {
|
|
406
|
-
if (data.event) {
|
|
407
|
-
// Формат { event: 'event_name', data: {} }
|
|
408
|
-
this.socket.emit(data.event, data.data);
|
|
409
|
-
}
|
|
410
|
-
else if (data.type && data.type === '2' && data.data && Array.isArray(data.data)) {
|
|
411
|
-
// Socket.IO тип пакета '2' - событие с данными
|
|
412
|
-
// Формат { type: '2', nsp: '/namespace', data: ['event_name', {}] }
|
|
413
|
-
const eventName = data.data[0];
|
|
414
|
-
const eventData = data.data.length > 1 ? data.data[1] : null;
|
|
415
|
-
this.socket.emit(eventName, eventData);
|
|
416
|
-
}
|
|
417
|
-
else {
|
|
418
|
-
// Обычные объекты отправляем через 'message'
|
|
419
|
-
this.socket.emit('message', data);
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
else {
|
|
423
|
-
// Строки, бинарные данные и т.д.
|
|
424
|
-
this.socket.send(data);
|
|
425
|
-
}
|
|
426
|
-
return true;
|
|
427
|
-
}
|
|
428
|
-
catch (error) {
|
|
429
|
-
this.logger('error', 'Ошибка при отправке сообщения', error);
|
|
430
|
-
return false;
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
/**
|
|
434
|
-
* Отправляет событие с данными и ожидает ответа с помощью Promise
|
|
435
|
-
* @param {string} event Название события
|
|
436
|
-
* @param {any} data Данные события
|
|
437
|
-
* @param {number} [timeout=5000] Таймаут ожидания ответа в мс
|
|
438
|
-
* @returns {Promise<any>} Promise с ответом
|
|
439
|
-
*/
|
|
440
|
-
emitWithAck(event, data, timeout = 5000) {
|
|
441
|
-
return new Promise((resolve, reject) => {
|
|
442
|
-
if (!this.socket || !this.socket.connected) {
|
|
443
|
-
reject(new Error('WebSocket не подключен'));
|
|
444
|
-
return;
|
|
445
|
-
}
|
|
446
|
-
try {
|
|
447
|
-
// Используем встроенный механизм acknowledgements в Socket.IO
|
|
448
|
-
this.socket.timeout(timeout).emit(event, data, (err, response) => {
|
|
449
|
-
if (err) {
|
|
450
|
-
reject(err);
|
|
451
|
-
}
|
|
452
|
-
else {
|
|
453
|
-
resolve(response);
|
|
454
|
-
}
|
|
455
|
-
});
|
|
456
|
-
}
|
|
457
|
-
catch (error) {
|
|
458
|
-
reject(error);
|
|
459
|
-
}
|
|
460
|
-
});
|
|
461
|
-
}
|
|
462
|
-
/**
|
|
463
|
-
* Добавляет обработчик события
|
|
464
|
-
* @param {string} eventType Тип события
|
|
465
|
-
* @param {WebSocketEventHandler} handler Обработчик события
|
|
466
|
-
*/
|
|
467
|
-
on(eventType, handler) {
|
|
468
|
-
if (!this.eventHandlers[eventType]) {
|
|
469
|
-
this.eventHandlers[eventType] = [];
|
|
470
|
-
}
|
|
471
|
-
this.eventHandlers[eventType].push(handler);
|
|
472
|
-
// Если соединение уже установлено, добавляем обработчик для Socket.IO
|
|
473
|
-
if (this.socket && this.socket.connected && eventType !== 'open' && eventType !== 'close') {
|
|
474
|
-
// Не добавляем обработчики для 'open' и 'close', так как они обрабатываются
|
|
475
|
-
// через 'connect' и 'disconnect' в методе connect()
|
|
476
|
-
this.socket.on(eventType, handler);
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
/**
|
|
480
|
-
* Удаляет обработчик события
|
|
481
|
-
* @param {string} eventType Тип события
|
|
482
|
-
* @param {WebSocketEventHandler} [handler] Обработчик события (если не указан, удаляются все обработчики)
|
|
483
|
-
*/
|
|
484
|
-
off(eventType, handler) {
|
|
485
|
-
if (!this.eventHandlers[eventType]) {
|
|
486
|
-
return;
|
|
487
|
-
}
|
|
488
|
-
if (handler) {
|
|
489
|
-
// Удаляем конкретный обработчик
|
|
490
|
-
const index = this.eventHandlers[eventType].indexOf(handler);
|
|
491
|
-
if (index !== -1) {
|
|
492
|
-
this.eventHandlers[eventType].splice(index, 1);
|
|
493
|
-
}
|
|
494
|
-
// Также удаляем обработчик из Socket.IO, если соединение установлено
|
|
495
|
-
if (this.socket && this.socket.connected) {
|
|
496
|
-
this.socket.off(eventType, handler);
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
else {
|
|
500
|
-
// Удаляем все обработчики для данного типа события
|
|
501
|
-
delete this.eventHandlers[eventType];
|
|
502
|
-
// Также удаляем все обработчики из Socket.IO, если соединение установлено
|
|
503
|
-
if (this.socket && this.socket.connected) {
|
|
504
|
-
this.socket.off(eventType);
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
/**
|
|
509
|
-
* Отправляет событие в обработчики
|
|
510
|
-
* @param {string} eventType Тип события
|
|
511
|
-
* @param {any} data Данные события
|
|
512
|
-
* @private
|
|
513
|
-
*/
|
|
514
|
-
dispatchEvent(eventType, data) {
|
|
515
|
-
if (!this.eventHandlers[eventType]) {
|
|
516
|
-
return;
|
|
517
|
-
}
|
|
518
|
-
for (const handler of this.eventHandlers[eventType]) {
|
|
519
|
-
try {
|
|
520
|
-
handler(data);
|
|
521
|
-
}
|
|
522
|
-
catch (error) {
|
|
523
|
-
this.logger('error', `Ошибка в обработчике события '${eventType}'`, error);
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
/**
|
|
528
|
-
* Возвращает текущий статус соединения
|
|
529
|
-
* @returns {boolean} Подключен ли клиент
|
|
530
|
-
*/
|
|
531
|
-
isConnected() {
|
|
532
|
-
return this.socket !== null && this.socket.connected;
|
|
533
|
-
}
|
|
534
|
-
/**
|
|
535
|
-
* Выполняет принудительное переподключение
|
|
536
|
-
* @returns {Promise<void>} Promise без результата
|
|
537
|
-
*/
|
|
538
|
-
async reconnect() {
|
|
539
|
-
// Если соединение уже установлено, сначала закрываем его
|
|
540
|
-
if (this.socket && this.socket.connected) {
|
|
541
|
-
this.close();
|
|
542
|
-
}
|
|
543
|
-
// Сбрасываем флаг намеренного закрытия для возможности переподключения
|
|
544
|
-
this.intentionallyClosed = false;
|
|
545
|
-
// Устанавливаем новое соединение
|
|
546
|
-
return this.connect();
|
|
547
|
-
}
|
|
548
|
-
/**
|
|
549
|
-
* Отправляет событие (алиас для более удобного использования)
|
|
550
|
-
* @param {string} eventName Название события
|
|
551
|
-
* @param {any} data Данные события
|
|
552
|
-
* @returns {boolean} Успешно ли отправлено событие
|
|
553
|
-
*/
|
|
554
|
-
emit(eventName, data) {
|
|
555
|
-
return this.send({ event: eventName, data });
|
|
556
|
-
}
|
|
557
|
-
/**
|
|
558
|
-
* Возвращает ID сокета, если соединение установлено
|
|
559
|
-
* @returns {string|null} ID сокета или null, если соединение не установлено
|
|
560
|
-
*/
|
|
561
|
-
getSocketId() {
|
|
562
|
-
return this.socket?.id || null;
|
|
563
|
-
}
|
|
564
|
-
/**
|
|
565
|
-
* Устанавливает функцию логирования
|
|
566
|
-
* @param {Function} loggerFn Функция для логирования
|
|
567
|
-
*/
|
|
568
|
-
setLogger(loggerFn) {
|
|
569
|
-
this.logger = loggerFn;
|
|
570
|
-
}
|
|
571
|
-
/**
|
|
572
|
-
* Регистрирует обработчик события, который будет вызван один раз и удален
|
|
573
|
-
* @param {string} event Название события
|
|
574
|
-
* @param {WebSocketEventHandler} handler Обработчик события
|
|
575
|
-
* @returns {void}
|
|
576
|
-
*/
|
|
577
|
-
once(event, handler) {
|
|
578
|
-
// Если есть нативная реализация в Socket.IO, используем её
|
|
579
|
-
if (this.socket && this.socket.connected) {
|
|
580
|
-
this.socket.once(event, handler);
|
|
581
|
-
return;
|
|
582
|
-
}
|
|
583
|
-
// Создаем обертку, которая удалит обработчик после первого вызова
|
|
584
|
-
const wrapperHandler = (data) => {
|
|
585
|
-
// Удаляем обработчик
|
|
586
|
-
this.off(event, wrapperHandler);
|
|
587
|
-
// Вызываем оригинальный обработчик
|
|
588
|
-
handler(data);
|
|
589
|
-
};
|
|
590
|
-
// Регистрируем обертку
|
|
591
|
-
this.on(event, wrapperHandler);
|
|
592
|
-
}
|
|
593
|
-
/**
|
|
594
|
-
* Отправляет событие Socket.IO через WebSocket соединение
|
|
595
|
-
* @param {string} event Имя события
|
|
596
|
-
* @param {any} data Данные события
|
|
597
|
-
* @param {(response: any) => void} [callback] Функция обратного вызова для получения ответа
|
|
598
|
-
* @param {string} [namespace=''] Namespace для Socket.IO
|
|
599
|
-
* @returns {boolean} Успешно ли отправлено сообщение
|
|
600
|
-
*/
|
|
601
|
-
sendSocketIOEvent(event, data, callback, namespace = '') {
|
|
602
|
-
// Если нет соединения, сразу возвращаем false
|
|
603
|
-
if (!this.socket || !this.socket.connected) {
|
|
604
|
-
this.logger('error', 'Нельзя отправить событие: WebSocket не подключен');
|
|
605
|
-
return false;
|
|
606
|
-
}
|
|
607
|
-
try {
|
|
608
|
-
// Проверяем, нужно ли использовать другой namespace
|
|
609
|
-
let targetSocket = this.socket;
|
|
610
|
-
// Если указан другой namespace, используем его
|
|
611
|
-
if (namespace && namespace !== this.namespace) {
|
|
612
|
-
const nsSocket = io(this.url + namespace, {
|
|
613
|
-
forceNew: false,
|
|
614
|
-
auth: { token: this.options.apiKey }
|
|
615
|
-
});
|
|
616
|
-
targetSocket = nsSocket;
|
|
617
|
-
}
|
|
618
|
-
// Отправляем событие с callback, если он указан
|
|
619
|
-
if (callback) {
|
|
620
|
-
targetSocket.emit(event, data, callback);
|
|
621
|
-
}
|
|
622
|
-
else {
|
|
623
|
-
targetSocket.emit(event, data);
|
|
624
|
-
}
|
|
625
|
-
this.logger('debug', `Отправлено Socket.IO событие ${event}`, { hasData: !!data, namespace });
|
|
626
|
-
return true;
|
|
627
|
-
}
|
|
628
|
-
catch (error) {
|
|
629
|
-
this.logger('error', `Ошибка при отправке Socket.IO события ${event}`, error);
|
|
630
|
-
return false;
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
//# sourceMappingURL=websocket-client.js.map
|