@resolveio/server-lib 22.1.18 → 22.1.20
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/managers/websocket.manager.d.ts +4 -0
- package/managers/websocket.manager.js +21 -0
- package/managers/websocket.manager.js.map +1 -1
- package/methods/mongo-explorer.js +874 -29
- package/methods/mongo-explorer.js.map +1 -1
- package/methods.ts +14 -8
- package/package.json +1 -1
- package/server-app.d.ts +18 -0
- package/server-app.js +610 -280
- package/server-app.js.map +1 -1
package/server-app.js
CHANGED
|
@@ -145,6 +145,10 @@ var ResolveIOMainServer = /** @class */ (function () {
|
|
|
145
145
|
this._safeShutdown = false;
|
|
146
146
|
this._dynamicAppGatewayEnabled = false;
|
|
147
147
|
this._dynamicAppGatewayCache = new Map();
|
|
148
|
+
this._socketTier = '';
|
|
149
|
+
this._maxClientSockets = 0;
|
|
150
|
+
this._singleIpPerUser = false;
|
|
151
|
+
this._socketPolicyUpgradeUrl = '';
|
|
148
152
|
this._clientHeartbeatIntervalMs = 20000;
|
|
149
153
|
this._clientHeartbeatInitialDelayMs = 5000;
|
|
150
154
|
this._clientHeartbeatBackpressureBytes = 5 * 1024 * 1024;
|
|
@@ -189,6 +193,17 @@ var ResolveIOMainServer = /** @class */ (function () {
|
|
|
189
193
|
this._timerDebugLogLimit = this.resolveTimerDebugLogLimit();
|
|
190
194
|
this._aiWorkerDebug = this.parseDebugFlag(process.env.AI_ASSISTANT_WORKER_DEBUG);
|
|
191
195
|
this._dynamicAppGatewayEnabled = this.resolveDynamicAppGatewayEnabled();
|
|
196
|
+
this._socketTier = this.resolveSocketTier();
|
|
197
|
+
this._maxClientSockets = this.resolveMaxClientSockets(this._socketTier);
|
|
198
|
+
this._singleIpPerUser = this.resolveSingleIpPerUserPolicy(this._socketTier);
|
|
199
|
+
this._socketPolicyUpgradeUrl = this.resolveSocketPolicyUpgradeUrl();
|
|
200
|
+
if (this._maxClientSockets > 0 || this._singleIpPerUser) {
|
|
201
|
+
console.info(new Date(), '[Socket Policy] configured', {
|
|
202
|
+
tier: this._socketTier || 'none',
|
|
203
|
+
maxClientSockets: this._maxClientSockets,
|
|
204
|
+
singleIpPerUser: this._singleIpPerUser
|
|
205
|
+
});
|
|
206
|
+
}
|
|
192
207
|
_a = this;
|
|
193
208
|
return [4 /*yield*/, monitor_manager_1.MonitorManager.create()];
|
|
194
209
|
case 1:
|
|
@@ -1137,36 +1152,44 @@ var ResolveIOMainServer = /** @class */ (function () {
|
|
|
1137
1152
|
}
|
|
1138
1153
|
else {
|
|
1139
1154
|
jwt.verify(token, resolveio_server_app_1.ResolveIOServer.getServerConfig()['JWT_SECRET'], function (err, decoded) { return __awaiter(_this, void 0, void 0, function () {
|
|
1140
|
-
var user, _a;
|
|
1155
|
+
var user, socketAdmission, _a;
|
|
1141
1156
|
return __generator(this, function (_b) {
|
|
1142
1157
|
switch (_b.label) {
|
|
1143
1158
|
case 0:
|
|
1144
1159
|
if (!err) return [3 /*break*/, 1];
|
|
1145
1160
|
cb(false, 401, 'Unauthorized');
|
|
1146
|
-
return [3 /*break*/,
|
|
1161
|
+
return [3 /*break*/, 8];
|
|
1147
1162
|
case 1:
|
|
1148
1163
|
info.req['id_user'] = decoded['id_user'];
|
|
1149
1164
|
_b.label = 2;
|
|
1150
1165
|
case 2:
|
|
1151
|
-
_b.trys.push([2,
|
|
1166
|
+
_b.trys.push([2, 7, , 8]);
|
|
1152
1167
|
return [4 /*yield*/, user_collection_1.Users.findById(decoded['id_user'])];
|
|
1153
1168
|
case 3:
|
|
1154
1169
|
user = _b.sent();
|
|
1155
|
-
if (user)
|
|
1156
|
-
|
|
1157
|
-
info.req['user_readonly'] = user.readonly || false;
|
|
1158
|
-
info.req['doc_user'] = user;
|
|
1159
|
-
cb(true);
|
|
1160
|
-
}
|
|
1161
|
-
else {
|
|
1162
|
-
cb(false);
|
|
1163
|
-
}
|
|
1164
|
-
return [3 /*break*/, 5];
|
|
1170
|
+
if (!user) return [3 /*break*/, 5];
|
|
1171
|
+
return [4 /*yield*/, this.evaluateClientSocketAdmission(decoded['id_user'], info.req)];
|
|
1165
1172
|
case 4:
|
|
1173
|
+
socketAdmission = _b.sent();
|
|
1174
|
+
if (!socketAdmission.allowed) {
|
|
1175
|
+
cb(false, socketAdmission.statusCode, socketAdmission.message || 'Socket connection rejected.');
|
|
1176
|
+
return [2 /*return*/];
|
|
1177
|
+
}
|
|
1178
|
+
info.req['user'] = user.fullname;
|
|
1179
|
+
info.req['user_readonly'] = user.readonly || false;
|
|
1180
|
+
info.req['doc_user'] = user;
|
|
1181
|
+
info.req['client_ip'] = socketAdmission.clientIp;
|
|
1182
|
+
cb(true);
|
|
1183
|
+
return [3 /*break*/, 6];
|
|
1184
|
+
case 5:
|
|
1185
|
+
cb(false);
|
|
1186
|
+
_b.label = 6;
|
|
1187
|
+
case 6: return [3 /*break*/, 8];
|
|
1188
|
+
case 7:
|
|
1166
1189
|
_a = _b.sent();
|
|
1167
1190
|
cb(false);
|
|
1168
|
-
return [3 /*break*/,
|
|
1169
|
-
case
|
|
1191
|
+
return [3 /*break*/, 8];
|
|
1192
|
+
case 8: return [2 /*return*/];
|
|
1170
1193
|
}
|
|
1171
1194
|
});
|
|
1172
1195
|
}); });
|
|
@@ -1185,284 +1208,330 @@ var ResolveIOMainServer = /** @class */ (function () {
|
|
|
1185
1208
|
this._serverHTTP.listen(this._portHTTP, host, function () {
|
|
1186
1209
|
console.log('Running HTTP/WS server on port %s', _this._portHTTP);
|
|
1187
1210
|
});
|
|
1188
|
-
this._serverWSS.on('connection', function (ws, req) {
|
|
1189
|
-
var
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
var rootUrl = resolveio_server_app_1.ResolveIOServer.getServerConfig()['ROOT_URL'] || 'http://localhost';
|
|
1199
|
-
try {
|
|
1200
|
-
var requestUrl = new url_1.URL(req.url, rootUrl);
|
|
1201
|
-
workerIndex = requestUrl.searchParams.get('workerIndex');
|
|
1202
|
-
workerInstance = requestUrl.searchParams.get('workerInstance');
|
|
1203
|
-
}
|
|
1204
|
-
catch (_c) {
|
|
1211
|
+
this._serverWSS.on('connection', function (ws, req) { return __awaiter(_this, void 0, void 0, function () {
|
|
1212
|
+
var workerId_1, workerIndex, workerInstance, rootUrl, requestUrl, workerIndexForLog, workerInstanceForLog, interval_1, lastComm_1, missedPongs_1, heartbeatIntervalMs, maxMissedPongs_1, maxSilenceMs_1, socketAdmission, socketPolicyError_1;
|
|
1213
|
+
var _this = this;
|
|
1214
|
+
var _a;
|
|
1215
|
+
return __generator(this, function (_b) {
|
|
1216
|
+
switch (_b.label) {
|
|
1217
|
+
case 0:
|
|
1218
|
+
if (!(req.url && req.url.includes('workerToken='))) return [3 /*break*/, 1];
|
|
1219
|
+
workerId_1 = (0, common_1.objectIdHexString)();
|
|
1220
|
+
ws['id_worker'] = workerId_1;
|
|
1205
1221
|
workerIndex = null;
|
|
1206
1222
|
workerInstance = null;
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
ws['workerInstance'] = workerInstance;
|
|
1220
|
-
}
|
|
1221
|
-
var workerIndexForLog = ws['workerIndex'] || 'UNKNOWN';
|
|
1222
|
-
var workerInstanceForLog = ws['workerInstance'] || 'UNKNOWN';
|
|
1223
|
-
console.log(new Date(), 'Worker Connected', workerIndexForLog, workerInstanceForLog);
|
|
1224
|
-
_this._workerDispatcherManager.addWorker(ws);
|
|
1225
|
-
var interval_1 = null;
|
|
1226
|
-
var lastComm_1 = new Date();
|
|
1227
|
-
var missedPongs_1 = 0;
|
|
1228
|
-
var heartbeatIntervalMs = 30000;
|
|
1229
|
-
var maxMissedPongs_1 = 2;
|
|
1230
|
-
var maxSilenceMs_1 = heartbeatIntervalMs * (maxMissedPongs_1 + 1);
|
|
1231
|
-
_this._workerDispatcherManager.sendWorkerPayload(ws, 'ping');
|
|
1232
|
-
interval_1 = setInterval(function () {
|
|
1233
|
-
var now = Date.now();
|
|
1234
|
-
var last = lastComm_1 ? lastComm_1.getTime() : 0;
|
|
1235
|
-
var silenceMs = last ? now - last : maxSilenceMs_1 + 1;
|
|
1236
|
-
if (silenceMs > maxSilenceMs_1 || missedPongs_1 > maxMissedPongs_1) {
|
|
1237
|
-
_this._workerDispatcherManager.disconnectWorker(ws['id_worker']);
|
|
1238
|
-
ws.close();
|
|
1239
|
-
return;
|
|
1240
|
-
}
|
|
1241
|
-
missedPongs_1 += 1;
|
|
1242
|
-
_this._workerDispatcherManager.sendWorkerPayload(ws, 'ping');
|
|
1243
|
-
}, heartbeatIntervalMs);
|
|
1244
|
-
ws.on('message', function (message) {
|
|
1245
|
-
lastComm_1 = new Date();
|
|
1246
|
-
if (typeof message === 'string') {
|
|
1247
|
-
if (message === 'ping') {
|
|
1248
|
-
_this._workerDispatcherManager.sendWorkerPayload(ws, 'pong');
|
|
1249
|
-
}
|
|
1250
|
-
else if (message === 'pong') {
|
|
1251
|
-
missedPongs_1 = 0;
|
|
1223
|
+
ws['supportsBinary'] = true;
|
|
1224
|
+
if (req.url) {
|
|
1225
|
+
rootUrl = resolveio_server_app_1.ResolveIOServer.getServerConfig()['ROOT_URL'] || 'http://localhost';
|
|
1226
|
+
try {
|
|
1227
|
+
requestUrl = new url_1.URL(req.url, rootUrl);
|
|
1228
|
+
workerIndex = requestUrl.searchParams.get('workerIndex');
|
|
1229
|
+
workerInstance = requestUrl.searchParams.get('workerInstance');
|
|
1230
|
+
}
|
|
1231
|
+
catch (_c) {
|
|
1232
|
+
workerIndex = null;
|
|
1233
|
+
workerInstance = null;
|
|
1234
|
+
}
|
|
1252
1235
|
}
|
|
1253
|
-
|
|
1254
|
-
|
|
1236
|
+
if (!workerIndex && req['workerIndex']) {
|
|
1237
|
+
workerIndex = req['workerIndex'];
|
|
1255
1238
|
}
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
var buffer;
|
|
1259
|
-
if (Buffer.isBuffer(message)) {
|
|
1260
|
-
buffer = message;
|
|
1261
|
-
}
|
|
1262
|
-
else if (Array.isArray(message)) {
|
|
1263
|
-
var chunks = message;
|
|
1264
|
-
buffer = Buffer.concat(chunks);
|
|
1265
|
-
}
|
|
1266
|
-
else if (message instanceof ArrayBuffer) {
|
|
1267
|
-
buffer = Buffer.from(message);
|
|
1268
|
-
}
|
|
1269
|
-
else if (ArrayBuffer.isView(message)) {
|
|
1270
|
-
var view = message;
|
|
1271
|
-
buffer = Buffer.from(view.buffer, view.byteOffset, view.byteLength);
|
|
1272
|
-
}
|
|
1273
|
-
else {
|
|
1274
|
-
buffer = Buffer.from(message);
|
|
1275
|
-
}
|
|
1276
|
-
if (buffer.length === 4) {
|
|
1277
|
-
var heartbeat = buffer.toString('utf8');
|
|
1278
|
-
if (heartbeat === 'ping') {
|
|
1279
|
-
_this._workerDispatcherManager.sendWorkerPayload(ws, 'pong');
|
|
1280
|
-
return;
|
|
1239
|
+
if (!workerInstance && req['workerInstance']) {
|
|
1240
|
+
workerInstance = req['workerInstance'];
|
|
1281
1241
|
}
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
return;
|
|
1242
|
+
if (workerIndex !== null && workerIndex !== undefined) {
|
|
1243
|
+
ws['workerIndex'] = workerIndex;
|
|
1285
1244
|
}
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
origin: (_b = req === null || req === void 0 ? void 0 : req.headers) === null || _b === void 0 ? void 0 : _b.origin
|
|
1318
|
-
});
|
|
1319
|
-
setTimeout(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1320
|
-
return __generator(this, function (_a) {
|
|
1321
|
-
switch (_a.label) {
|
|
1322
|
-
case 0: return [4 /*yield*/, this.triggerClientHeartbeat(ws)];
|
|
1323
|
-
case 1:
|
|
1324
|
-
_a.sent();
|
|
1325
|
-
return [2 /*return*/];
|
|
1326
|
-
}
|
|
1327
|
-
});
|
|
1328
|
-
}); }, _this._clientHeartbeatInitialDelayMs);
|
|
1329
|
-
if (_this.LOGGER === 'DEBUG') {
|
|
1330
|
-
console.log('Connection from user: ' + req['user']);
|
|
1331
|
-
}
|
|
1332
|
-
ws['isAlive'] = true;
|
|
1333
|
-
ws['retryCnt'] = 0;
|
|
1334
|
-
ws.on('pong', function () {
|
|
1335
|
-
ws['isAlive'] = true;
|
|
1336
|
-
ws['pongTime'] = new Date();
|
|
1337
|
-
if (ws['pingTime']) {
|
|
1338
|
-
ws['latency'] = moment.duration(moment(ws['pongTime']).diff(ws['pingTime'])).asMilliseconds();
|
|
1339
|
-
_this._subscriptionManager.loggedInLatency(ws);
|
|
1340
|
-
}
|
|
1341
|
-
});
|
|
1342
|
-
ws.on('message', function (message) { return __awaiter(_this, void 0, void 0, function () {
|
|
1343
|
-
var socketData, usedBinary, bufferPayload, decodeResult, decodeResult, decodeResult, view, decodeResult, e_6, correlationId, context;
|
|
1344
|
-
return __generator(this, function (_a) {
|
|
1345
|
-
switch (_a.label) {
|
|
1346
|
-
case 0:
|
|
1347
|
-
this._debugMsgRecv += 1;
|
|
1348
|
-
socketData = [];
|
|
1349
|
-
usedBinary = false;
|
|
1350
|
-
_a.label = 1;
|
|
1351
|
-
case 1:
|
|
1352
|
-
_a.trys.push([1, 2, , 4]);
|
|
1353
|
-
if (typeof message === 'string') {
|
|
1354
|
-
if (message === 'ping' || message === 'pong') {
|
|
1355
|
-
socketData = message;
|
|
1356
|
-
}
|
|
1357
|
-
else {
|
|
1358
|
-
socketData = JSON.parse(message, common_1.dateReviver);
|
|
1359
|
-
}
|
|
1360
|
-
}
|
|
1361
|
-
else if (Buffer.isBuffer(message)) {
|
|
1362
|
-
bufferPayload = message;
|
|
1363
|
-
decodeResult = this.decodeBufferPayload(bufferPayload);
|
|
1364
|
-
socketData = decodeResult.data;
|
|
1365
|
-
usedBinary = decodeResult.usedBinary;
|
|
1245
|
+
if (workerInstance !== null && workerInstance !== undefined) {
|
|
1246
|
+
ws['workerInstance'] = workerInstance;
|
|
1247
|
+
}
|
|
1248
|
+
workerIndexForLog = ws['workerIndex'] || 'UNKNOWN';
|
|
1249
|
+
workerInstanceForLog = ws['workerInstance'] || 'UNKNOWN';
|
|
1250
|
+
console.log(new Date(), 'Worker Connected', workerIndexForLog, workerInstanceForLog);
|
|
1251
|
+
this._workerDispatcherManager.addWorker(ws);
|
|
1252
|
+
interval_1 = null;
|
|
1253
|
+
lastComm_1 = new Date();
|
|
1254
|
+
missedPongs_1 = 0;
|
|
1255
|
+
heartbeatIntervalMs = 30000;
|
|
1256
|
+
maxMissedPongs_1 = 2;
|
|
1257
|
+
maxSilenceMs_1 = heartbeatIntervalMs * (maxMissedPongs_1 + 1);
|
|
1258
|
+
this._workerDispatcherManager.sendWorkerPayload(ws, 'ping');
|
|
1259
|
+
interval_1 = setInterval(function () {
|
|
1260
|
+
var now = Date.now();
|
|
1261
|
+
var last = lastComm_1 ? lastComm_1.getTime() : 0;
|
|
1262
|
+
var silenceMs = last ? now - last : maxSilenceMs_1 + 1;
|
|
1263
|
+
if (silenceMs > maxSilenceMs_1 || missedPongs_1 > maxMissedPongs_1) {
|
|
1264
|
+
_this._workerDispatcherManager.disconnectWorker(ws['id_worker']);
|
|
1265
|
+
ws.close();
|
|
1266
|
+
return;
|
|
1267
|
+
}
|
|
1268
|
+
missedPongs_1 += 1;
|
|
1269
|
+
_this._workerDispatcherManager.sendWorkerPayload(ws, 'ping');
|
|
1270
|
+
}, heartbeatIntervalMs);
|
|
1271
|
+
ws.on('message', function (message) {
|
|
1272
|
+
lastComm_1 = new Date();
|
|
1273
|
+
if (typeof message === 'string') {
|
|
1274
|
+
if (message === 'ping') {
|
|
1275
|
+
_this._workerDispatcherManager.sendWorkerPayload(ws, 'pong');
|
|
1366
1276
|
}
|
|
1367
|
-
else if (
|
|
1368
|
-
|
|
1369
|
-
decodeResult = this.decodeBufferPayload(bufferPayload);
|
|
1370
|
-
socketData = decodeResult.data;
|
|
1371
|
-
usedBinary = decodeResult.usedBinary;
|
|
1277
|
+
else if (message === 'pong') {
|
|
1278
|
+
missedPongs_1 = 0;
|
|
1372
1279
|
}
|
|
1373
|
-
else
|
|
1374
|
-
|
|
1375
|
-
decodeResult = this.decodeBufferPayload(bufferPayload);
|
|
1376
|
-
socketData = decodeResult.data;
|
|
1377
|
-
usedBinary = decodeResult.usedBinary;
|
|
1280
|
+
else {
|
|
1281
|
+
_this._workerDispatcherManager.handleWorkerMessage(ws['id_worker'], message);
|
|
1378
1282
|
}
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1283
|
+
return;
|
|
1284
|
+
}
|
|
1285
|
+
var buffer;
|
|
1286
|
+
if (Buffer.isBuffer(message)) {
|
|
1287
|
+
buffer = message;
|
|
1288
|
+
}
|
|
1289
|
+
else if (Array.isArray(message)) {
|
|
1290
|
+
var chunks = message;
|
|
1291
|
+
buffer = Buffer.concat(chunks);
|
|
1292
|
+
}
|
|
1293
|
+
else if (message instanceof ArrayBuffer) {
|
|
1294
|
+
buffer = Buffer.from(message);
|
|
1295
|
+
}
|
|
1296
|
+
else if (ArrayBuffer.isView(message)) {
|
|
1297
|
+
var view = message;
|
|
1298
|
+
buffer = Buffer.from(view.buffer, view.byteOffset, view.byteLength);
|
|
1299
|
+
}
|
|
1300
|
+
else {
|
|
1301
|
+
buffer = Buffer.from(message);
|
|
1302
|
+
}
|
|
1303
|
+
if (buffer.length === 4) {
|
|
1304
|
+
var heartbeat = buffer.toString('utf8');
|
|
1305
|
+
if (heartbeat === 'ping') {
|
|
1306
|
+
_this._workerDispatcherManager.sendWorkerPayload(ws, 'pong');
|
|
1307
|
+
return;
|
|
1385
1308
|
}
|
|
1386
|
-
else {
|
|
1387
|
-
|
|
1309
|
+
else if (heartbeat === 'pong') {
|
|
1310
|
+
missedPongs_1 = 0;
|
|
1311
|
+
return;
|
|
1388
1312
|
}
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1313
|
+
}
|
|
1314
|
+
_this._workerDispatcherManager.handleWorkerMessage(ws['id_worker'], buffer);
|
|
1315
|
+
});
|
|
1316
|
+
ws.on('close', function () {
|
|
1317
|
+
_this._workerDispatcherManager.disconnectWorker(ws['id_worker']);
|
|
1318
|
+
console.log(new Date(), 'Worker disconnected:', workerId_1);
|
|
1319
|
+
if (interval_1) {
|
|
1320
|
+
clearInterval(interval_1);
|
|
1321
|
+
}
|
|
1322
|
+
});
|
|
1323
|
+
ws.on('error', function (error) {
|
|
1324
|
+
_this._workerDispatcherManager.disconnectWorker(ws['id_worker']);
|
|
1325
|
+
console.error('Error on WS Worker', error);
|
|
1326
|
+
ws.close();
|
|
1327
|
+
});
|
|
1328
|
+
return [3 /*break*/, 6];
|
|
1329
|
+
case 1:
|
|
1330
|
+
// Normal client
|
|
1331
|
+
ws['id_socket'] = (0, common_1.objectIdHexString)();
|
|
1332
|
+
ws['supportsBinary'] = true;
|
|
1333
|
+
ws['id_user'] = req['id_user'];
|
|
1334
|
+
ws['user'] = req['user'];
|
|
1335
|
+
ws['user_readonly'] = req['user_readonly'];
|
|
1336
|
+
ws['doc_user'] = req['doc_user'];
|
|
1337
|
+
ws['client_ip'] = this.resolveClientIp(req);
|
|
1338
|
+
socketAdmission = void 0;
|
|
1339
|
+
_b.label = 2;
|
|
1340
|
+
case 2:
|
|
1341
|
+
_b.trys.push([2, 4, , 5]);
|
|
1342
|
+
return [4 /*yield*/, this.evaluateClientSocketAdmission(ws['id_user'], req)];
|
|
1343
|
+
case 3:
|
|
1344
|
+
socketAdmission = _b.sent();
|
|
1345
|
+
return [3 /*break*/, 5];
|
|
1346
|
+
case 4:
|
|
1347
|
+
socketPolicyError_1 = _b.sent();
|
|
1348
|
+
this.logConnectDebug('WS socket policy evaluation failed', {
|
|
1349
|
+
id_socket: ws['id_socket'],
|
|
1350
|
+
id_user: ws['id_user'],
|
|
1351
|
+
user: ws['user'],
|
|
1352
|
+
ip: ws['client_ip'],
|
|
1353
|
+
error: (socketPolicyError_1 === null || socketPolicyError_1 === void 0 ? void 0 : socketPolicyError_1.message) || socketPolicyError_1
|
|
1354
|
+
});
|
|
1355
|
+
try {
|
|
1356
|
+
ws.close(1011, 'Socket policy error');
|
|
1357
|
+
}
|
|
1358
|
+
catch (_d) { }
|
|
1359
|
+
return [2 /*return*/];
|
|
1360
|
+
case 5:
|
|
1361
|
+
if (!socketAdmission.allowed) {
|
|
1362
|
+
this.logConnectDebug('WS client rejected', {
|
|
1363
|
+
id_socket: ws['id_socket'],
|
|
1364
|
+
id_user: ws['id_user'],
|
|
1365
|
+
user: ws['user'],
|
|
1366
|
+
ip: ws['client_ip'],
|
|
1367
|
+
reason: socketAdmission.message
|
|
1368
|
+
});
|
|
1369
|
+
try {
|
|
1370
|
+
ws.close(1008, this.buildSocketLimitCloseReason());
|
|
1371
|
+
}
|
|
1372
|
+
catch (_e) { }
|
|
1373
|
+
return [2 /*return*/];
|
|
1374
|
+
}
|
|
1375
|
+
ws['client_ip'] = socketAdmission.clientIp || ws['client_ip'];
|
|
1376
|
+
this._websocketManager.addWebSocket(ws);
|
|
1377
|
+
this.logConnectDebug('WS client connected', {
|
|
1378
|
+
id_socket: ws['id_socket'],
|
|
1379
|
+
id_user: ws['id_user'],
|
|
1380
|
+
user: ws['user'],
|
|
1381
|
+
url: req === null || req === void 0 ? void 0 : req.url,
|
|
1382
|
+
ip: ws['client_ip'],
|
|
1383
|
+
origin: (_a = req === null || req === void 0 ? void 0 : req.headers) === null || _a === void 0 ? void 0 : _a.origin
|
|
1384
|
+
});
|
|
1385
|
+
setTimeout(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1386
|
+
return __generator(this, function (_a) {
|
|
1387
|
+
switch (_a.label) {
|
|
1388
|
+
case 0: return [4 /*yield*/, this.triggerClientHeartbeat(ws)];
|
|
1389
|
+
case 1:
|
|
1390
|
+
_a.sent();
|
|
1391
|
+
return [2 /*return*/];
|
|
1406
1392
|
}
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
_a.sent();
|
|
1412
|
-
return [2 /*return*/];
|
|
1413
|
-
}
|
|
1414
|
-
});
|
|
1415
|
-
}); })
|
|
1416
|
-
.on('end', function () {
|
|
1417
|
-
ws.close();
|
|
1418
|
-
})
|
|
1419
|
-
.on('error', function () {
|
|
1420
|
-
ws.close();
|
|
1421
|
-
})
|
|
1422
|
-
.on('close', function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1423
|
-
return __generator(this, function (_a) {
|
|
1424
|
-
switch (_a.label) {
|
|
1425
|
-
case 0:
|
|
1426
|
-
this.logConnectDebug('WS client closed', {
|
|
1427
|
-
id_socket: ws['id_socket'],
|
|
1428
|
-
id_user: ws['id_user'],
|
|
1429
|
-
user: ws['user']
|
|
1430
|
-
});
|
|
1431
|
-
return [4 /*yield*/, this.unsubscribeWS(ws)];
|
|
1432
|
-
case 1:
|
|
1433
|
-
_a.sent();
|
|
1434
|
-
return [2 /*return*/];
|
|
1435
|
-
}
|
|
1436
|
-
});
|
|
1437
|
-
}); });
|
|
1438
|
-
// Do not block message handler registration on DB write; this avoids losing
|
|
1439
|
-
// very-early subscription messages sent immediately after websocket open.
|
|
1440
|
-
setTimeout(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1441
|
-
var error_5;
|
|
1442
|
-
return __generator(this, function (_a) {
|
|
1443
|
-
switch (_a.label) {
|
|
1444
|
-
case 0:
|
|
1445
|
-
_a.trys.push([0, 2, , 3]);
|
|
1446
|
-
return [4 /*yield*/, this._subscriptionManager.createLoggedInUser(ws['id_socket'])];
|
|
1447
|
-
case 1:
|
|
1448
|
-
_a.sent();
|
|
1449
|
-
return [3 /*break*/, 3];
|
|
1450
|
-
case 2:
|
|
1451
|
-
error_5 = _a.sent();
|
|
1452
|
-
console.error(new Date(), 'Error creating logged-in user', ws['id_socket'], error_5);
|
|
1453
|
-
this.logConnectDebug('Create logged-in user failed', {
|
|
1454
|
-
id_socket: ws['id_socket'],
|
|
1455
|
-
id_user: ws['id_user'],
|
|
1456
|
-
user: ws['user'],
|
|
1457
|
-
error: (error_5 === null || error_5 === void 0 ? void 0 : error_5.message) || error_5
|
|
1458
|
-
});
|
|
1459
|
-
return [3 /*break*/, 3];
|
|
1460
|
-
case 3: return [2 /*return*/];
|
|
1393
|
+
});
|
|
1394
|
+
}); }, this._clientHeartbeatInitialDelayMs);
|
|
1395
|
+
if (this.LOGGER === 'DEBUG') {
|
|
1396
|
+
console.log('Connection from user: ' + req['user']);
|
|
1461
1397
|
}
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1398
|
+
ws['isAlive'] = true;
|
|
1399
|
+
ws['retryCnt'] = 0;
|
|
1400
|
+
ws.on('pong', function () {
|
|
1401
|
+
ws['isAlive'] = true;
|
|
1402
|
+
ws['pongTime'] = new Date();
|
|
1403
|
+
if (ws['pingTime']) {
|
|
1404
|
+
ws['latency'] = moment.duration(moment(ws['pongTime']).diff(ws['pingTime'])).asMilliseconds();
|
|
1405
|
+
_this._subscriptionManager.loggedInLatency(ws);
|
|
1406
|
+
}
|
|
1407
|
+
});
|
|
1408
|
+
ws.on('message', function (message) { return __awaiter(_this, void 0, void 0, function () {
|
|
1409
|
+
var socketData, usedBinary, bufferPayload, decodeResult, decodeResult, decodeResult, view, decodeResult, e_6, correlationId, context;
|
|
1410
|
+
return __generator(this, function (_a) {
|
|
1411
|
+
switch (_a.label) {
|
|
1412
|
+
case 0:
|
|
1413
|
+
this._debugMsgRecv += 1;
|
|
1414
|
+
socketData = [];
|
|
1415
|
+
usedBinary = false;
|
|
1416
|
+
_a.label = 1;
|
|
1417
|
+
case 1:
|
|
1418
|
+
_a.trys.push([1, 2, , 4]);
|
|
1419
|
+
if (typeof message === 'string') {
|
|
1420
|
+
if (message === 'ping' || message === 'pong') {
|
|
1421
|
+
socketData = message;
|
|
1422
|
+
}
|
|
1423
|
+
else {
|
|
1424
|
+
socketData = JSON.parse(message, common_1.dateReviver);
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
else if (Buffer.isBuffer(message)) {
|
|
1428
|
+
bufferPayload = message;
|
|
1429
|
+
decodeResult = this.decodeBufferPayload(bufferPayload);
|
|
1430
|
+
socketData = decodeResult.data;
|
|
1431
|
+
usedBinary = decodeResult.usedBinary;
|
|
1432
|
+
}
|
|
1433
|
+
else if (Array.isArray(message)) {
|
|
1434
|
+
bufferPayload = Buffer.concat(message);
|
|
1435
|
+
decodeResult = this.decodeBufferPayload(bufferPayload);
|
|
1436
|
+
socketData = decodeResult.data;
|
|
1437
|
+
usedBinary = decodeResult.usedBinary;
|
|
1438
|
+
}
|
|
1439
|
+
else if (message instanceof ArrayBuffer) {
|
|
1440
|
+
bufferPayload = Buffer.from(message);
|
|
1441
|
+
decodeResult = this.decodeBufferPayload(bufferPayload);
|
|
1442
|
+
socketData = decodeResult.data;
|
|
1443
|
+
usedBinary = decodeResult.usedBinary;
|
|
1444
|
+
}
|
|
1445
|
+
else if (ArrayBuffer.isView(message)) {
|
|
1446
|
+
view = message;
|
|
1447
|
+
bufferPayload = Buffer.from(view.buffer, view.byteOffset, view.byteLength);
|
|
1448
|
+
decodeResult = this.decodeBufferPayload(bufferPayload);
|
|
1449
|
+
socketData = decodeResult.data;
|
|
1450
|
+
usedBinary = decodeResult.usedBinary;
|
|
1451
|
+
}
|
|
1452
|
+
else {
|
|
1453
|
+
throw new Error('Unsupported WebSocket message type: ' + typeof message);
|
|
1454
|
+
}
|
|
1455
|
+
return [3 /*break*/, 4];
|
|
1456
|
+
case 2:
|
|
1457
|
+
e_6 = _a.sent();
|
|
1458
|
+
console.log('Error - WS message parse', e_6);
|
|
1459
|
+
correlationId = (0, common_1.objectIdHexString)();
|
|
1460
|
+
context = {
|
|
1461
|
+
rawBinary: bufferPayload ? bufferPayload.toString('base64') : undefined,
|
|
1462
|
+
rawMessage: typeof message === 'string' ? message : undefined,
|
|
1463
|
+
error: e_6 instanceof Error ? { name: e_6.name, message: e_6.message, stack: e_6.stack } : e_6
|
|
1464
|
+
};
|
|
1465
|
+
return [4 /*yield*/, this.reportServerError('SERVER - JSON Parse Error - ' + resolveio_server_app_1.ResolveIOServer.getServerConfig()['CLIENT_NAME'], correlationId, context, { context: 'websocket-message-parse' }, 'error', e_6 instanceof Error ? e_6.stack : undefined)];
|
|
1466
|
+
case 3:
|
|
1467
|
+
_a.sent();
|
|
1468
|
+
return [2 /*return*/];
|
|
1469
|
+
case 4:
|
|
1470
|
+
if (usedBinary) {
|
|
1471
|
+
ws['supportsBinary'] = true;
|
|
1472
|
+
}
|
|
1473
|
+
// call our existing processSocketMessage
|
|
1474
|
+
return [4 /*yield*/, this.processSocketMessage(ws, socketData)];
|
|
1475
|
+
case 5:
|
|
1476
|
+
// call our existing processSocketMessage
|
|
1477
|
+
_a.sent();
|
|
1478
|
+
return [2 /*return*/];
|
|
1479
|
+
}
|
|
1480
|
+
});
|
|
1481
|
+
}); })
|
|
1482
|
+
.on('end', function () {
|
|
1483
|
+
ws.close();
|
|
1484
|
+
})
|
|
1485
|
+
.on('error', function () {
|
|
1486
|
+
ws.close();
|
|
1487
|
+
})
|
|
1488
|
+
.on('close', function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1489
|
+
return __generator(this, function (_a) {
|
|
1490
|
+
switch (_a.label) {
|
|
1491
|
+
case 0:
|
|
1492
|
+
this.logConnectDebug('WS client closed', {
|
|
1493
|
+
id_socket: ws['id_socket'],
|
|
1494
|
+
id_user: ws['id_user'],
|
|
1495
|
+
user: ws['user']
|
|
1496
|
+
});
|
|
1497
|
+
return [4 /*yield*/, this.unsubscribeWS(ws)];
|
|
1498
|
+
case 1:
|
|
1499
|
+
_a.sent();
|
|
1500
|
+
return [2 /*return*/];
|
|
1501
|
+
}
|
|
1502
|
+
});
|
|
1503
|
+
}); });
|
|
1504
|
+
// Do not block message handler registration on DB write; this avoids losing
|
|
1505
|
+
// very-early subscription messages sent immediately after websocket open.
|
|
1506
|
+
setTimeout(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1507
|
+
var error_5;
|
|
1508
|
+
return __generator(this, function (_a) {
|
|
1509
|
+
switch (_a.label) {
|
|
1510
|
+
case 0:
|
|
1511
|
+
_a.trys.push([0, 2, , 3]);
|
|
1512
|
+
return [4 /*yield*/, this._subscriptionManager.createLoggedInUser(ws['id_socket'])];
|
|
1513
|
+
case 1:
|
|
1514
|
+
_a.sent();
|
|
1515
|
+
return [3 /*break*/, 3];
|
|
1516
|
+
case 2:
|
|
1517
|
+
error_5 = _a.sent();
|
|
1518
|
+
console.error(new Date(), 'Error creating logged-in user', ws['id_socket'], error_5);
|
|
1519
|
+
this.logConnectDebug('Create logged-in user failed', {
|
|
1520
|
+
id_socket: ws['id_socket'],
|
|
1521
|
+
id_user: ws['id_user'],
|
|
1522
|
+
user: ws['user'],
|
|
1523
|
+
error: (error_5 === null || error_5 === void 0 ? void 0 : error_5.message) || error_5
|
|
1524
|
+
});
|
|
1525
|
+
return [3 /*break*/, 3];
|
|
1526
|
+
case 3: return [2 /*return*/];
|
|
1527
|
+
}
|
|
1528
|
+
});
|
|
1529
|
+
}); }, 0);
|
|
1530
|
+
_b.label = 6;
|
|
1531
|
+
case 6: return [2 /*return*/];
|
|
1532
|
+
}
|
|
1533
|
+
});
|
|
1534
|
+
}); });
|
|
1466
1535
|
// Keep alive timer
|
|
1467
1536
|
setInterval(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1468
1537
|
var _a, _b, ws, e_7_1;
|
|
@@ -1982,6 +2051,267 @@ var ResolveIOMainServer = /** @class */ (function () {
|
|
|
1982
2051
|
}
|
|
1983
2052
|
return false;
|
|
1984
2053
|
};
|
|
2054
|
+
ResolveIOMainServer.prototype.parseOptionalBoolean = function (value) {
|
|
2055
|
+
if (value === null || value === undefined) {
|
|
2056
|
+
return null;
|
|
2057
|
+
}
|
|
2058
|
+
var normalized = "".concat(value).trim();
|
|
2059
|
+
if (!normalized) {
|
|
2060
|
+
return null;
|
|
2061
|
+
}
|
|
2062
|
+
return this.parseDebugFlag(normalized);
|
|
2063
|
+
};
|
|
2064
|
+
ResolveIOMainServer.prototype.parseNonNegativeInt = function (value, fallback) {
|
|
2065
|
+
var parsed = parseInt("".concat(value !== null && value !== void 0 ? value : ''), 10);
|
|
2066
|
+
if (Number.isNaN(parsed) || parsed < 0) {
|
|
2067
|
+
return fallback;
|
|
2068
|
+
}
|
|
2069
|
+
return parsed;
|
|
2070
|
+
};
|
|
2071
|
+
ResolveIOMainServer.prototype.resolveSocketTier = function () {
|
|
2072
|
+
var config = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
|
|
2073
|
+
return "".concat(process.env.AI_CODER_PLAN_TIER || config['AI_CODER_PLAN_TIER'] || '').trim().toLowerCase();
|
|
2074
|
+
};
|
|
2075
|
+
ResolveIOMainServer.prototype.resolveSocketTierKeySuffix = function (planTier) {
|
|
2076
|
+
return "".concat(planTier || '')
|
|
2077
|
+
.trim()
|
|
2078
|
+
.toUpperCase()
|
|
2079
|
+
.replace(/[^A-Z0-9]+/g, '_');
|
|
2080
|
+
};
|
|
2081
|
+
ResolveIOMainServer.prototype.resolveMaxClientSockets = function (planTier) {
|
|
2082
|
+
var _a, _b, _c;
|
|
2083
|
+
var config = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
|
|
2084
|
+
var explicitLimit = this.parseNonNegativeInt((_a = config['AI_CODER_MAX_SOCKETS']) !== null && _a !== void 0 ? _a : process.env.AI_CODER_MAX_SOCKETS, -1);
|
|
2085
|
+
if (explicitLimit >= 0) {
|
|
2086
|
+
return explicitLimit;
|
|
2087
|
+
}
|
|
2088
|
+
var normalizedTier = "".concat(planTier || '').trim().toLowerCase();
|
|
2089
|
+
var tierKeySuffix = this.resolveSocketTierKeySuffix(normalizedTier);
|
|
2090
|
+
if (tierKeySuffix) {
|
|
2091
|
+
var tierLimitKey = "AI_CODER_MAX_SOCKETS_".concat(tierKeySuffix);
|
|
2092
|
+
var tierLimit = this.parseNonNegativeInt((_b = config[tierLimitKey]) !== null && _b !== void 0 ? _b : process.env[tierLimitKey], -1);
|
|
2093
|
+
if (tierLimit >= 0) {
|
|
2094
|
+
return tierLimit;
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
var maxUsers = this.parseNonNegativeInt((_c = config['AI_CODER_MAX_USERS']) !== null && _c !== void 0 ? _c : process.env.AI_CODER_MAX_USERS, -1);
|
|
2098
|
+
if (maxUsers > 0) {
|
|
2099
|
+
return maxUsers === 1 ? 1 : maxUsers * 2;
|
|
2100
|
+
}
|
|
2101
|
+
if (normalizedTier === 'tool') {
|
|
2102
|
+
return 1;
|
|
2103
|
+
}
|
|
2104
|
+
if (normalizedTier === 'small') {
|
|
2105
|
+
return 10;
|
|
2106
|
+
}
|
|
2107
|
+
if (normalizedTier === 'medium') {
|
|
2108
|
+
return 50;
|
|
2109
|
+
}
|
|
2110
|
+
if (normalizedTier === 'large') {
|
|
2111
|
+
return 200;
|
|
2112
|
+
}
|
|
2113
|
+
if (normalizedTier === 'enterprise') {
|
|
2114
|
+
return 0;
|
|
2115
|
+
}
|
|
2116
|
+
return 0;
|
|
2117
|
+
};
|
|
2118
|
+
ResolveIOMainServer.prototype.resolveSingleIpPerUserPolicy = function (planTier) {
|
|
2119
|
+
var _a, _b;
|
|
2120
|
+
var config = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
|
|
2121
|
+
var normalizedTier = "".concat(planTier || '').trim().toLowerCase();
|
|
2122
|
+
var tierKeySuffix = this.resolveSocketTierKeySuffix(normalizedTier);
|
|
2123
|
+
if (tierKeySuffix) {
|
|
2124
|
+
var tierPolicyKey = "AI_CODER_SINGLE_IP_PER_USER_".concat(tierKeySuffix);
|
|
2125
|
+
var tierPolicy = this.parseOptionalBoolean((_a = config[tierPolicyKey]) !== null && _a !== void 0 ? _a : process.env[tierPolicyKey]);
|
|
2126
|
+
if (tierPolicy !== null) {
|
|
2127
|
+
return tierPolicy;
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
var policy = this.parseOptionalBoolean((_b = config['AI_CODER_SINGLE_IP_PER_USER']) !== null && _b !== void 0 ? _b : process.env.AI_CODER_SINGLE_IP_PER_USER);
|
|
2131
|
+
if (policy !== null) {
|
|
2132
|
+
return policy;
|
|
2133
|
+
}
|
|
2134
|
+
return !!normalizedTier;
|
|
2135
|
+
};
|
|
2136
|
+
ResolveIOMainServer.prototype.resolveSocketPolicyUpgradeUrl = function () {
|
|
2137
|
+
var config = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
|
|
2138
|
+
var direct = "".concat(config['AI_CODER_SOCKET_UPGRADE_URL'] || process.env.AI_CODER_SOCKET_UPGRADE_URL || '').trim();
|
|
2139
|
+
if (direct) {
|
|
2140
|
+
return direct.replace(/\/$/, '');
|
|
2141
|
+
}
|
|
2142
|
+
var dashboard = "".concat(config['AI_CODER_CLIENT_DASHBOARD_URL'] || process.env.AI_CODER_CLIENT_DASHBOARD_URL || '').trim();
|
|
2143
|
+
if (dashboard) {
|
|
2144
|
+
return dashboard.replace(/\/$/, '');
|
|
2145
|
+
}
|
|
2146
|
+
var root = "".concat(config['AI_CODER_ROOT_URL'] || process.env.AI_CODER_ROOT_URL || config['ROOT_URL'] || process.env.ROOT_URL || '').trim();
|
|
2147
|
+
if (!root) {
|
|
2148
|
+
return '';
|
|
2149
|
+
}
|
|
2150
|
+
return "".concat(root.replace(/\/$/, ''), "/dashboard/client");
|
|
2151
|
+
};
|
|
2152
|
+
ResolveIOMainServer.prototype.resolveSocketUpgradeUrlWithAppId = function () {
|
|
2153
|
+
var base = "".concat(this._socketPolicyUpgradeUrl || '').trim();
|
|
2154
|
+
if (!base) {
|
|
2155
|
+
return '';
|
|
2156
|
+
}
|
|
2157
|
+
var appId = "".concat(process.env.AI_CODER_APP_ID || '').trim();
|
|
2158
|
+
if (!appId) {
|
|
2159
|
+
return base;
|
|
2160
|
+
}
|
|
2161
|
+
var separator = base.includes('?') ? '&' : '?';
|
|
2162
|
+
return "".concat(base).concat(separator, "appId=").concat(encodeURIComponent(appId));
|
|
2163
|
+
};
|
|
2164
|
+
ResolveIOMainServer.prototype.normalizeIpAddress = function (value) {
|
|
2165
|
+
var ip = "".concat(value || '').trim();
|
|
2166
|
+
if (!ip) {
|
|
2167
|
+
return '';
|
|
2168
|
+
}
|
|
2169
|
+
if (ip.includes(',')) {
|
|
2170
|
+
ip = ip.split(',')[0].trim();
|
|
2171
|
+
}
|
|
2172
|
+
if (ip.startsWith('::ffff:')) {
|
|
2173
|
+
ip = ip.slice(7);
|
|
2174
|
+
}
|
|
2175
|
+
if (/^\d+\.\d+\.\d+\.\d+:\d+$/.test(ip)) {
|
|
2176
|
+
ip = ip.split(':')[0].trim();
|
|
2177
|
+
}
|
|
2178
|
+
if (ip === '::1') {
|
|
2179
|
+
return '127.0.0.1';
|
|
2180
|
+
}
|
|
2181
|
+
return ip.toLowerCase();
|
|
2182
|
+
};
|
|
2183
|
+
ResolveIOMainServer.prototype.resolveClientIp = function (req) {
|
|
2184
|
+
var _a, _b, _c, _d;
|
|
2185
|
+
var forwardedFor = this.normalizeHeaderValue((_a = req === null || req === void 0 ? void 0 : req.headers) === null || _a === void 0 ? void 0 : _a['x-forwarded-for']);
|
|
2186
|
+
if (forwardedFor) {
|
|
2187
|
+
return this.normalizeIpAddress(forwardedFor);
|
|
2188
|
+
}
|
|
2189
|
+
var realIp = this.normalizeHeaderValue((_b = req === null || req === void 0 ? void 0 : req.headers) === null || _b === void 0 ? void 0 : _b['x-real-ip']);
|
|
2190
|
+
if (realIp) {
|
|
2191
|
+
return this.normalizeIpAddress(realIp);
|
|
2192
|
+
}
|
|
2193
|
+
var socketIp = ((_c = req === null || req === void 0 ? void 0 : req.socket) === null || _c === void 0 ? void 0 : _c.remoteAddress) || ((_d = req === null || req === void 0 ? void 0 : req.connection) === null || _d === void 0 ? void 0 : _d.remoteAddress) || (req === null || req === void 0 ? void 0 : req.ip) || '';
|
|
2194
|
+
return this.normalizeIpAddress(socketIp);
|
|
2195
|
+
};
|
|
2196
|
+
ResolveIOMainServer.prototype.buildSocketLimitMessage = function (activeSockets) {
|
|
2197
|
+
var tierLabel = this._socketTier ? this._socketTier[0].toUpperCase() + this._socketTier.slice(1) : 'Current';
|
|
2198
|
+
var upgradeUrl = this.resolveSocketUpgradeUrlWithAppId();
|
|
2199
|
+
var base = "Socket connection limit reached (".concat(activeSockets, "/").concat(this._maxClientSockets, ") for the ").concat(tierLabel, " tier.");
|
|
2200
|
+
if (!upgradeUrl) {
|
|
2201
|
+
return "".concat(base, " Upgrade to increase capacity.");
|
|
2202
|
+
}
|
|
2203
|
+
return "".concat(base, " Upgrade at ").concat(upgradeUrl, ".");
|
|
2204
|
+
};
|
|
2205
|
+
ResolveIOMainServer.prototype.buildSocketLimitCloseReason = function () {
|
|
2206
|
+
return "Socket limit reached (".concat(this._maxClientSockets, ")");
|
|
2207
|
+
};
|
|
2208
|
+
ResolveIOMainServer.prototype.disconnectUserSocketsFromDifferentIps = function (idUser, incomingIp) {
|
|
2209
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
2210
|
+
var normalizedUser, normalizedIncomingIp, userSockets, disconnected, userSockets_1, userSockets_1_1, existingSocket, existingIp, e_9_1;
|
|
2211
|
+
var e_9, _a;
|
|
2212
|
+
return __generator(this, function (_b) {
|
|
2213
|
+
switch (_b.label) {
|
|
2214
|
+
case 0:
|
|
2215
|
+
if (!this._websocketManager) {
|
|
2216
|
+
return [2 /*return*/, 0];
|
|
2217
|
+
}
|
|
2218
|
+
normalizedUser = "".concat(idUser || '').trim();
|
|
2219
|
+
normalizedIncomingIp = this.normalizeIpAddress(incomingIp);
|
|
2220
|
+
if (!normalizedUser || !normalizedIncomingIp) {
|
|
2221
|
+
return [2 /*return*/, 0];
|
|
2222
|
+
}
|
|
2223
|
+
userSockets = this._websocketManager.getUserWebSockets(normalizedUser);
|
|
2224
|
+
disconnected = 0;
|
|
2225
|
+
_b.label = 1;
|
|
2226
|
+
case 1:
|
|
2227
|
+
_b.trys.push([1, 6, 7, 8]);
|
|
2228
|
+
userSockets_1 = __values(userSockets), userSockets_1_1 = userSockets_1.next();
|
|
2229
|
+
_b.label = 2;
|
|
2230
|
+
case 2:
|
|
2231
|
+
if (!!userSockets_1_1.done) return [3 /*break*/, 5];
|
|
2232
|
+
existingSocket = userSockets_1_1.value;
|
|
2233
|
+
existingIp = this.normalizeIpAddress(existingSocket === null || existingSocket === void 0 ? void 0 : existingSocket['client_ip']);
|
|
2234
|
+
if (!existingIp || existingIp === normalizedIncomingIp) {
|
|
2235
|
+
return [3 /*break*/, 4];
|
|
2236
|
+
}
|
|
2237
|
+
this.logConnectDebug('WS single-ip enforcement disconnect', {
|
|
2238
|
+
id_socket: existingSocket === null || existingSocket === void 0 ? void 0 : existingSocket['id_socket'],
|
|
2239
|
+
id_user: normalizedUser,
|
|
2240
|
+
existingIp: existingIp,
|
|
2241
|
+
incomingIp: normalizedIncomingIp
|
|
2242
|
+
});
|
|
2243
|
+
return [4 /*yield*/, this.unsubscribeWS(existingSocket)];
|
|
2244
|
+
case 3:
|
|
2245
|
+
_b.sent();
|
|
2246
|
+
if (existingSocket.readyState === WebSocket.OPEN || existingSocket.readyState === WebSocket.CONNECTING) {
|
|
2247
|
+
try {
|
|
2248
|
+
existingSocket.close(1008, 'Signed in from another IP');
|
|
2249
|
+
}
|
|
2250
|
+
catch (_c) { }
|
|
2251
|
+
}
|
|
2252
|
+
disconnected += 1;
|
|
2253
|
+
_b.label = 4;
|
|
2254
|
+
case 4:
|
|
2255
|
+
userSockets_1_1 = userSockets_1.next();
|
|
2256
|
+
return [3 /*break*/, 2];
|
|
2257
|
+
case 5: return [3 /*break*/, 8];
|
|
2258
|
+
case 6:
|
|
2259
|
+
e_9_1 = _b.sent();
|
|
2260
|
+
e_9 = { error: e_9_1 };
|
|
2261
|
+
return [3 /*break*/, 8];
|
|
2262
|
+
case 7:
|
|
2263
|
+
try {
|
|
2264
|
+
if (userSockets_1_1 && !userSockets_1_1.done && (_a = userSockets_1.return)) _a.call(userSockets_1);
|
|
2265
|
+
}
|
|
2266
|
+
finally { if (e_9) throw e_9.error; }
|
|
2267
|
+
return [7 /*endfinally*/];
|
|
2268
|
+
case 8: return [2 /*return*/, disconnected];
|
|
2269
|
+
}
|
|
2270
|
+
});
|
|
2271
|
+
});
|
|
2272
|
+
};
|
|
2273
|
+
ResolveIOMainServer.prototype.evaluateClientSocketAdmission = function (idUser, req) {
|
|
2274
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
2275
|
+
var normalizedUser, clientIp, activeSockets, message;
|
|
2276
|
+
return __generator(this, function (_a) {
|
|
2277
|
+
switch (_a.label) {
|
|
2278
|
+
case 0:
|
|
2279
|
+
normalizedUser = "".concat(idUser || '').trim();
|
|
2280
|
+
clientIp = this.resolveClientIp(req);
|
|
2281
|
+
if (!this._singleIpPerUser) return [3 /*break*/, 2];
|
|
2282
|
+
return [4 /*yield*/, this.disconnectUserSocketsFromDifferentIps(normalizedUser, clientIp)];
|
|
2283
|
+
case 1:
|
|
2284
|
+
_a.sent();
|
|
2285
|
+
_a.label = 2;
|
|
2286
|
+
case 2:
|
|
2287
|
+
if (this._maxClientSockets > 0 && this._websocketManager) {
|
|
2288
|
+
activeSockets = this._websocketManager.getActiveWebSocketCount();
|
|
2289
|
+
if (activeSockets >= this._maxClientSockets) {
|
|
2290
|
+
message = this.buildSocketLimitMessage(activeSockets);
|
|
2291
|
+
this.logConnectDebug('WS socket limit blocked', {
|
|
2292
|
+
id_user: normalizedUser,
|
|
2293
|
+
clientIp: clientIp,
|
|
2294
|
+
activeSockets: activeSockets,
|
|
2295
|
+
maxClientSockets: this._maxClientSockets
|
|
2296
|
+
});
|
|
2297
|
+
return [2 /*return*/, {
|
|
2298
|
+
allowed: false,
|
|
2299
|
+
statusCode: 429,
|
|
2300
|
+
message: message,
|
|
2301
|
+
clientIp: clientIp
|
|
2302
|
+
}];
|
|
2303
|
+
}
|
|
2304
|
+
}
|
|
2305
|
+
return [2 /*return*/, {
|
|
2306
|
+
allowed: true,
|
|
2307
|
+
statusCode: 200,
|
|
2308
|
+
message: '',
|
|
2309
|
+
clientIp: clientIp
|
|
2310
|
+
}];
|
|
2311
|
+
}
|
|
2312
|
+
});
|
|
2313
|
+
});
|
|
2314
|
+
};
|
|
1985
2315
|
ResolveIOMainServer.prototype.logConnectDebug = function (message, details) {
|
|
1986
2316
|
if (!this._wsConnectDebug) {
|
|
1987
2317
|
return;
|