@iobroker/db-objects-jsonl 4.0.21 → 4.1.0-alpha.0-20220819-74ceeddc
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/build/index.d.ts +4 -0
- package/{index.js → build/index.js} +2 -0
- package/build/lib/objects/objectsInMemJsonlDB.d.ts +21 -0
- package/build/lib/objects/objectsInMemJsonlDB.d.ts.map +1 -0
- package/{lib → build/lib}/objects/objectsInMemJsonlDB.js +75 -55
- package/build/lib/objects/objectsInMemJsonlDB.js.map +1 -0
- package/build/lib/objects/objectsInMemServerClass.d.ts +14 -0
- package/build/lib/objects/objectsInMemServerClass.d.ts.map +1 -0
- package/{lib → build/lib}/objects/objectsInMemServerClass.js +1 -9
- package/build/lib/objects/objectsInMemServerClass.js.map +1 -0
- package/build/lib/objects/objectsInMemServerRedis.d.ts +89 -0
- package/build/lib/objects/objectsInMemServerRedis.d.ts.map +1 -0
- package/{lib → build/lib}/objects/objectsInMemServerRedis.js +222 -286
- package/build/lib/objects/objectsInMemServerRedis.js.map +1 -0
- package/package.json +14 -10
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Objects DB in memory - Server with Redis protocol
|
|
3
3
|
*
|
|
4
|
-
* Copyright 2013-
|
|
4
|
+
* Copyright 2013-2022 bluefox <dogafox@gmail.com>
|
|
5
5
|
*
|
|
6
6
|
* MIT License
|
|
7
7
|
*
|
|
8
8
|
*/
|
|
9
|
-
|
|
10
9
|
/** @module objectsInRedis */
|
|
11
|
-
|
|
12
10
|
/* jshint -W097 */
|
|
13
11
|
/* jshint strict:false */
|
|
14
12
|
/* jslint node: true */
|
|
@@ -19,10 +17,8 @@ const path = require('path');
|
|
|
19
17
|
const crypto = require('crypto');
|
|
20
18
|
const utils = require('@iobroker/db-objects-redis').objectsUtils;
|
|
21
19
|
const tools = require('@iobroker/db-base').tools;
|
|
22
|
-
|
|
23
|
-
const RedisHandler = require('@iobroker/db-base').redisHandler;
|
|
20
|
+
const { RedisHandler } = require('@iobroker/db-base');
|
|
24
21
|
const ObjectsInMemoryJsonlDB = require('./objectsInMemJsonlDB');
|
|
25
|
-
|
|
26
22
|
// settings = {
|
|
27
23
|
// change: function (id, state) {},
|
|
28
24
|
// connected: function (nameOfServer) {},
|
|
@@ -43,7 +39,6 @@ const ObjectsInMemoryJsonlDB = require('./objectsInMemJsonlDB');
|
|
|
43
39
|
// host: localhost
|
|
44
40
|
// };
|
|
45
41
|
//
|
|
46
|
-
|
|
47
42
|
/**
|
|
48
43
|
* This class inherits statesInMemoryJsonlDB class and adds redis communication layer
|
|
49
44
|
* to access the methods via redis protocol
|
|
@@ -55,52 +50,41 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
55
50
|
*/
|
|
56
51
|
constructor(settings) {
|
|
57
52
|
super(settings);
|
|
58
|
-
|
|
59
53
|
this.serverConnections = {};
|
|
60
54
|
this.namespaceObjects =
|
|
61
55
|
(this.settings.redisNamespace || (settings.connection && settings.connection.redisNamespace) || 'cfg') +
|
|
62
|
-
|
|
56
|
+
'.';
|
|
63
57
|
this.namespaceFile = this.namespaceObjects + 'f.';
|
|
64
58
|
this.namespaceObj = this.namespaceObjects + 'o.';
|
|
65
59
|
this.namespaceSet = this.namespaceObjects + 's.';
|
|
66
60
|
this.namespaceSetLen = this.namespaceSet.length;
|
|
67
|
-
|
|
68
61
|
// this.namespaceObjectsLen = this.namespaceObjects.length;
|
|
69
62
|
this.namespaceFileLen = this.namespaceFile.length;
|
|
70
63
|
this.namespaceObjLen = this.namespaceObj.length;
|
|
71
|
-
this.
|
|
72
|
-
this.
|
|
73
|
-
|
|
64
|
+
this.namespaceMeta = `${this.settings.namespaceMeta || 'meta'}.`;
|
|
65
|
+
this.namespaceMetaLen = this.namespaceMeta.length;
|
|
74
66
|
this.knownScripts = {};
|
|
75
|
-
|
|
76
67
|
this.normalizeFileRegex1 = new RegExp('^(.*)\\$%\\$(.*)\\$%\\$(meta|data)$');
|
|
77
68
|
this.normalizeFileRegex2 = new RegExp('^(.*)\\$%\\$(.*)\\/?\\*$');
|
|
78
|
-
|
|
79
69
|
this.open()
|
|
80
70
|
.then(() => {
|
|
81
|
-
|
|
82
|
-
|
|
71
|
+
return this._initRedisServer(this.settings.connection);
|
|
72
|
+
})
|
|
83
73
|
.then(() => {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
);
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
setImmediate(() => this.settings.connected());
|
|
94
|
-
}
|
|
95
|
-
})
|
|
74
|
+
this.log.debug(this.namespace +
|
|
75
|
+
' ' +
|
|
76
|
+
(settings.secure ? 'Secure ' : '') +
|
|
77
|
+
' Redis inMem-objects listening on port ' +
|
|
78
|
+
(settings.port || 9001));
|
|
79
|
+
if (typeof this.settings.connected === 'function') {
|
|
80
|
+
setImmediate(() => this.settings.connected());
|
|
81
|
+
}
|
|
82
|
+
})
|
|
96
83
|
.catch(e => {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
process.exit(24); // todo: replace it with exitcode
|
|
101
|
-
});
|
|
84
|
+
this.log.error(`${this.namespace} Cannot start inMem-objects on port ${settings.port || 9001}: ${e.message}`);
|
|
85
|
+
process.exit(24); // todo: replace it with exitcode
|
|
86
|
+
});
|
|
102
87
|
}
|
|
103
|
-
|
|
104
88
|
/**
|
|
105
89
|
* Separate Namespace from ID and return both
|
|
106
90
|
* @param idWithNamespace ID or Array of IDs containing a redis namespace and the real ID
|
|
@@ -121,15 +105,18 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
121
105
|
ns = namespace; // we ignore the pot. case from arrays with different namespaces
|
|
122
106
|
});
|
|
123
107
|
id = ids;
|
|
124
|
-
}
|
|
108
|
+
}
|
|
109
|
+
else if (typeof idWithNamespace === 'string') {
|
|
125
110
|
id = idWithNamespace;
|
|
126
111
|
if (idWithNamespace.startsWith(this.namespaceObjects)) {
|
|
127
112
|
let idx = -1;
|
|
128
113
|
if (idWithNamespace.startsWith(this.namespaceObj)) {
|
|
129
114
|
idx = this.namespaceObjLen;
|
|
130
|
-
}
|
|
115
|
+
}
|
|
116
|
+
else if (idWithNamespace.startsWith(this.namespaceFile)) {
|
|
131
117
|
idx = this.namespaceFileLen;
|
|
132
|
-
}
|
|
118
|
+
}
|
|
119
|
+
else if (idWithNamespace.startsWith(this.namespaceSet)) {
|
|
133
120
|
idx = this.namespaceSetLen;
|
|
134
121
|
}
|
|
135
122
|
if (idx !== -1) {
|
|
@@ -142,20 +129,23 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
142
129
|
id = fileIdDetails[1];
|
|
143
130
|
name = fileIdDetails[2] || '';
|
|
144
131
|
isMeta = fileIdDetails[3] === 'meta';
|
|
145
|
-
}
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
146
134
|
fileIdDetails = id.match(this.normalizeFileRegex2);
|
|
147
135
|
if (fileIdDetails) {
|
|
148
136
|
id = fileIdDetails[1];
|
|
149
137
|
name = fileIdDetails[2] || '';
|
|
150
138
|
isMeta = undefined;
|
|
151
|
-
}
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
152
141
|
name = '';
|
|
153
142
|
isMeta = undefined;
|
|
154
143
|
}
|
|
155
144
|
}
|
|
156
145
|
}
|
|
157
|
-
}
|
|
158
|
-
|
|
146
|
+
}
|
|
147
|
+
else if (idWithNamespace.startsWith(this.namespaceMeta)) {
|
|
148
|
+
const idx = this.namespaceMetaLen;
|
|
159
149
|
if (idx !== -1) {
|
|
160
150
|
ns = idWithNamespace.substr(0, idx);
|
|
161
151
|
id = idWithNamespace.substr(idx);
|
|
@@ -164,31 +154,37 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
164
154
|
}
|
|
165
155
|
return { id, namespace: ns, name, isMeta };
|
|
166
156
|
}
|
|
167
|
-
|
|
168
157
|
/**
|
|
169
158
|
* Publish a subscribed value to one of the redis connections in redis format
|
|
170
159
|
* @param client Instance of RedisHandler
|
|
171
160
|
* @param type Type of subscribed key
|
|
172
161
|
* @param id Subscribed ID
|
|
173
162
|
* @param obj Object to publish
|
|
174
|
-
* @returns {number} Publish counter 0 or 1 depending if send out or not
|
|
163
|
+
* @returns {number} Publish counter 0 or 1 depending on if send out or not
|
|
175
164
|
*/
|
|
176
165
|
publishToClients(client, type, id, obj) {
|
|
177
166
|
if (!client._subscribe || !client._subscribe[type]) {
|
|
178
167
|
return 0;
|
|
179
168
|
}
|
|
180
169
|
const s = client._subscribe[type];
|
|
181
|
-
|
|
182
170
|
const found = s.find(sub => sub.regex.test(id));
|
|
183
171
|
if (found) {
|
|
184
172
|
if (type === 'meta') {
|
|
185
173
|
this.log.silly(`${this.namespace} Redis Publish Meta ${id}=${obj}`);
|
|
186
|
-
const sendPattern = this.
|
|
187
|
-
const sendId = this.
|
|
174
|
+
const sendPattern = this.namespaceMeta + found.pattern;
|
|
175
|
+
const sendId = this.namespaceMeta + id;
|
|
188
176
|
client.sendArray(null, ['pmessage', sendPattern, sendId, obj]);
|
|
189
|
-
}
|
|
177
|
+
}
|
|
178
|
+
else if (type === 'files') {
|
|
190
179
|
const objString = JSON.stringify(obj);
|
|
191
|
-
this.log.silly(this.namespace
|
|
180
|
+
this.log.silly(`${this.namespace} Redis Publish File ${id}=${objString}`);
|
|
181
|
+
const sendPattern = this.namespaceFile + found.pattern;
|
|
182
|
+
const sendId = this.namespaceFile + id;
|
|
183
|
+
client.sendArray(null, ['pmessage', sendPattern, sendId, objString]);
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
const objString = JSON.stringify(obj);
|
|
187
|
+
this.log.silly(`${this.namespace} Redis Publish Object ${id}=${objString}`);
|
|
192
188
|
const sendPattern = (type === 'objects' ? '' : this.namespaceObjects) + found.pattern;
|
|
193
189
|
const sendId = (type === 'objects' ? this.namespaceObj : this.namespaceObjects) + id;
|
|
194
190
|
client.sendArray(null, ['pmessage', sendPattern, sendId, objString]);
|
|
@@ -197,7 +193,6 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
197
193
|
}
|
|
198
194
|
return 0;
|
|
199
195
|
}
|
|
200
|
-
|
|
201
196
|
/**
|
|
202
197
|
* Generate ID for a File
|
|
203
198
|
* @param id ID of the File
|
|
@@ -210,15 +205,14 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
210
205
|
if (id.endsWith('.admin')) {
|
|
211
206
|
if (name.startsWith('admin/')) {
|
|
212
207
|
name = name.replace(/^admin\//, '');
|
|
213
|
-
}
|
|
208
|
+
}
|
|
209
|
+
else if (name.match(/^iobroker.[-\d\w]\/admin\//i)) {
|
|
214
210
|
// e.g. ekey.admin and iobroker.ekey/admin/ekey.png
|
|
215
211
|
name = name.replace(/^iobroker.[-\d\w]\/admin\//i, '');
|
|
216
212
|
}
|
|
217
213
|
}
|
|
218
|
-
|
|
219
214
|
return this.namespaceFile + id + '$%$' + name + (isMeta !== undefined ? (isMeta ? '$%$meta' : '$%$data') : '');
|
|
220
215
|
}
|
|
221
|
-
|
|
222
216
|
/**
|
|
223
217
|
* Register all event listeners for Handler and implement the relevant logic
|
|
224
218
|
* @param handler RedisHandler instance
|
|
@@ -227,7 +221,6 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
227
221
|
_socketEvents(handler) {
|
|
228
222
|
let connectionName = null;
|
|
229
223
|
let namespaceLog = this.namespace;
|
|
230
|
-
|
|
231
224
|
// Handle Redis "INFO" request
|
|
232
225
|
handler.on('info', (_data, responseId) => {
|
|
233
226
|
let infoString = '# Server\r\n';
|
|
@@ -240,17 +233,15 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
240
233
|
infoString += '# CPU\r\n';
|
|
241
234
|
infoString += '# Cluster\r\n';
|
|
242
235
|
infoString += '# Keyspace\r\n';
|
|
243
|
-
infoString +=
|
|
236
|
+
infoString += `db0:keys=${Object.keys(this.dataset).length},expires=0,avg_ttl=98633637897`;
|
|
244
237
|
handler.sendBulk(responseId, infoString);
|
|
245
238
|
});
|
|
246
|
-
|
|
247
239
|
// Handle Redis "QUIT" request
|
|
248
240
|
handler.on('quit', (_data, responseId) => {
|
|
249
241
|
this.log.silly(namespaceLog + ' Redis QUIT received, close connection');
|
|
250
242
|
handler.sendString(responseId, 'OK');
|
|
251
243
|
handler.close();
|
|
252
244
|
});
|
|
253
|
-
|
|
254
245
|
// Handle Redis "SCRIPT" request
|
|
255
246
|
handler.on('script', (data, responseId) => {
|
|
256
247
|
data[0] = data[0].toLowerCase();
|
|
@@ -259,12 +250,12 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
259
250
|
const scripts = [];
|
|
260
251
|
data.forEach(checksum => scripts.push(this.knownScripts[checksum] ? 1 : 0));
|
|
261
252
|
handler.sendArray(responseId, scripts);
|
|
262
|
-
}
|
|
253
|
+
}
|
|
254
|
+
else if (data[0] === 'load') {
|
|
263
255
|
const shasum = crypto.createHash('sha1');
|
|
264
256
|
const buf = Buffer.from(data[1]);
|
|
265
257
|
shasum.update(buf);
|
|
266
258
|
const scriptChecksum = shasum.digest('hex');
|
|
267
|
-
|
|
268
259
|
const scriptDesign = data[1].match(/^-- design: ([a-z0-9A-Z-.]+)\s/m);
|
|
269
260
|
const scriptFunc = data[1].match(/^-- func: (.+)$/m);
|
|
270
261
|
if (scriptDesign && scriptDesign[1]) {
|
|
@@ -274,49 +265,39 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
274
265
|
if (scriptSearch && scriptSearch[1]) {
|
|
275
266
|
search = scriptSearch[1];
|
|
276
267
|
}
|
|
277
|
-
|
|
278
268
|
this.knownScripts[scriptChecksum] = { design: design, search: search };
|
|
279
269
|
if (this.settings.connection.enhancedLogging) {
|
|
280
|
-
this.log.silly(
|
|
281
|
-
`${namespaceLog} Register View LUA Script: ${scriptChecksum} = ${JSON.stringify(
|
|
282
|
-
this.knownScripts[scriptChecksum]
|
|
283
|
-
)}`
|
|
284
|
-
);
|
|
270
|
+
this.log.silly(`${namespaceLog} Register View LUA Script: ${scriptChecksum} = ${JSON.stringify(this.knownScripts[scriptChecksum])}`);
|
|
285
271
|
}
|
|
286
272
|
handler.sendBulk(responseId, scriptChecksum);
|
|
287
|
-
}
|
|
273
|
+
}
|
|
274
|
+
else if (scriptFunc && scriptFunc[1]) {
|
|
288
275
|
this.knownScripts[scriptChecksum] = { func: scriptFunc[1] };
|
|
289
276
|
if (this.settings.connection.enhancedLogging) {
|
|
290
|
-
this.log.silly(
|
|
291
|
-
`${namespaceLog} Register Func LUA Script: ${scriptChecksum} = ${JSON.stringify(
|
|
292
|
-
this.knownScripts[scriptChecksum]
|
|
293
|
-
)}`
|
|
294
|
-
);
|
|
277
|
+
this.log.silly(`${namespaceLog} Register Func LUA Script: ${scriptChecksum} = ${JSON.stringify(this.knownScripts[scriptChecksum])}`);
|
|
295
278
|
}
|
|
296
279
|
handler.sendBulk(responseId, scriptChecksum);
|
|
297
|
-
}
|
|
280
|
+
}
|
|
281
|
+
else if (data[1].includes('-- REDLOCK SCRIPT')) {
|
|
298
282
|
// redlock scripts are currently not needed for Simulator
|
|
299
283
|
this.knownScripts[scriptChecksum] = { redlock: true };
|
|
300
284
|
if (this.settings.connection.enhancedLogging) {
|
|
301
|
-
this.log.silly(
|
|
302
|
-
`${namespaceLog} Register Func LUA Script: ${scriptChecksum} = ${JSON.stringify(
|
|
303
|
-
this.knownScripts[scriptChecksum]
|
|
304
|
-
)}`
|
|
305
|
-
);
|
|
285
|
+
this.log.silly(`${namespaceLog} Register Func LUA Script: ${scriptChecksum} = ${JSON.stringify(this.knownScripts[scriptChecksum])}`);
|
|
306
286
|
}
|
|
307
287
|
handler.sendBulk(responseId, scriptChecksum);
|
|
308
|
-
}
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
309
290
|
handler.sendError(responseId, new Error(`Unknown LUA script ${data[1]}`));
|
|
310
291
|
}
|
|
311
|
-
}
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
312
294
|
handler.sendError(responseId, new Error(`Unsupported Script command ${data[0]}`));
|
|
313
295
|
}
|
|
314
296
|
});
|
|
315
|
-
|
|
316
297
|
// Handle Redis "EVALSHA" request
|
|
317
298
|
handler.on('evalsha', (data, responseId) => {
|
|
318
299
|
if (!this.knownScripts[data[0]]) {
|
|
319
|
-
return void handler.sendError(responseId, new Error(
|
|
300
|
+
return void handler.sendError(responseId, new Error(`Unknown Script ${data[0]}`));
|
|
320
301
|
}
|
|
321
302
|
if (this.knownScripts[data[0]].design) {
|
|
322
303
|
const scriptDesign = this.knownScripts[data[0]].design;
|
|
@@ -329,9 +310,7 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
329
310
|
scriptSearch = 'state';
|
|
330
311
|
}
|
|
331
312
|
if (this.settings.connection.enhancedLogging) {
|
|
332
|
-
this.log.silly(
|
|
333
|
-
`${namespaceLog} Script transformed into getObjectView: design=${scriptDesign}, search=${scriptSearch}`
|
|
334
|
-
);
|
|
313
|
+
this.log.silly(`${namespaceLog} Script transformed into getObjectView: design=${scriptDesign}, search=${scriptSearch}`);
|
|
335
314
|
}
|
|
336
315
|
let objs;
|
|
337
316
|
try {
|
|
@@ -340,17 +319,15 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
340
319
|
endkey: data[4],
|
|
341
320
|
include_docs: true
|
|
342
321
|
});
|
|
343
|
-
} catch (err) {
|
|
344
|
-
return void handler.sendError(
|
|
345
|
-
responseId,
|
|
346
|
-
new Error(`_getObjectView Error for ${scriptDesign}/${scriptSearch}: ${err.message}`)
|
|
347
|
-
);
|
|
348
322
|
}
|
|
349
|
-
|
|
323
|
+
catch (err) {
|
|
324
|
+
return void handler.sendError(responseId, new Error(`_getObjectView Error for ${scriptDesign}/${scriptSearch}: ${err.message}`));
|
|
325
|
+
}
|
|
350
326
|
const res = objs.rows.map(obj => JSON.stringify(this.dataset[obj.value._id || obj.id]));
|
|
351
327
|
handler.sendArray(responseId, res);
|
|
352
328
|
}
|
|
353
|
-
}
|
|
329
|
+
}
|
|
330
|
+
else if (this.knownScripts[data[0]].func && data.length > 4) {
|
|
354
331
|
const scriptFunc = { map: this.knownScripts[data[0]].func.replace('%1', data[5]) };
|
|
355
332
|
if (this.settings.connection.enhancedLogging) {
|
|
356
333
|
this.log.silly(`${namespaceLog} Script transformed into _applyView: func=${scriptFunc.map}`);
|
|
@@ -361,44 +338,41 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
361
338
|
include_docs: true
|
|
362
339
|
});
|
|
363
340
|
const res = objs.rows.map(obj => JSON.stringify(this.dataset[obj.value._id || obj.id]));
|
|
364
|
-
|
|
365
341
|
return void handler.sendArray(responseId, res);
|
|
366
|
-
}
|
|
342
|
+
}
|
|
343
|
+
else if (this.knownScripts[data[0]].redlock) {
|
|
367
344
|
// just return a dummy
|
|
368
345
|
return void handler.sendArray(responseId, [0]);
|
|
369
|
-
}
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
370
348
|
handler.sendError(responseId, new Error(`Unknown LUA script eval call ${JSON.stringify(data)}`));
|
|
371
349
|
}
|
|
372
350
|
});
|
|
373
|
-
|
|
374
351
|
// Handle Redis "PUBLISH" request
|
|
375
352
|
handler.on('publish', (data, responseId) => {
|
|
376
353
|
const { id, namespace } = this._normalizeId(data[0]);
|
|
377
|
-
|
|
378
|
-
|
|
354
|
+
if (namespace === this.namespaceObj ||
|
|
355
|
+
namespace === this.namespaceMeta ||
|
|
356
|
+
namespace === this.namespaceFile) {
|
|
379
357
|
// a "set" always comes afterwards, so do not publish
|
|
380
358
|
return void handler.sendInteger(responseId, 0); // do not publish for now
|
|
381
359
|
}
|
|
382
360
|
const publishCount = this.publishAll(namespace.substr(0, namespace.length - 1), id, JSON.parse(data[1]));
|
|
383
361
|
handler.sendInteger(responseId, publishCount);
|
|
384
362
|
});
|
|
385
|
-
|
|
386
363
|
// Handle Redis "MGET" requests
|
|
387
364
|
handler.on('mget', (data, responseId) => {
|
|
388
365
|
if (!data || !data.length) {
|
|
389
366
|
return void handler.sendArray(responseId, []);
|
|
390
367
|
}
|
|
391
368
|
const { namespace, isMeta } = this._normalizeId(data[0]);
|
|
392
|
-
|
|
393
369
|
if (namespace === this.namespaceObj) {
|
|
394
370
|
const keys = [];
|
|
395
371
|
data.forEach(dataId => {
|
|
396
372
|
const { id, namespace } = this._normalizeId(dataId);
|
|
397
373
|
if (namespace !== this.namespaceObj) {
|
|
398
374
|
keys.push(null);
|
|
399
|
-
this.log.warn(
|
|
400
|
-
`${namespaceLog} Got MGET request for non Object-ID in Objects-ID chunk for ${namespace} / ${dataId}`
|
|
401
|
-
);
|
|
375
|
+
this.log.warn(`${namespaceLog} Got MGET request for non Object-ID in Objects-ID chunk for ${namespace} / ${dataId}`);
|
|
402
376
|
return;
|
|
403
377
|
}
|
|
404
378
|
keys.push(id);
|
|
@@ -406,12 +380,14 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
406
380
|
let result;
|
|
407
381
|
try {
|
|
408
382
|
result = this._getObjects(keys);
|
|
409
|
-
}
|
|
383
|
+
}
|
|
384
|
+
catch (err) {
|
|
410
385
|
return void handler.sendError(responseId, new Error('ERROR _getObjects: ' + err.message));
|
|
411
386
|
}
|
|
412
387
|
result = result.map(el => (el ? JSON.stringify(el) : null));
|
|
413
388
|
handler.sendArray(responseId, result);
|
|
414
|
-
}
|
|
389
|
+
}
|
|
390
|
+
else if (namespace === this.namespaceFile) {
|
|
415
391
|
// Handle request for Meta data for files
|
|
416
392
|
if (isMeta) {
|
|
417
393
|
const response = [];
|
|
@@ -419,9 +395,7 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
419
395
|
const { id, namespace, name } = this._normalizeId(dataId);
|
|
420
396
|
if (namespace !== this.namespaceFile) {
|
|
421
397
|
response.push(null);
|
|
422
|
-
this.log.warn(
|
|
423
|
-
`${namespaceLog} Got MGET request for non File ID in File-ID chunk for ${dataId}`
|
|
424
|
-
);
|
|
398
|
+
this.log.warn(`${namespaceLog} Got MGET request for non File ID in File-ID chunk for ${dataId}`);
|
|
425
399
|
return;
|
|
426
400
|
}
|
|
427
401
|
this._loadFileSettings(id);
|
|
@@ -433,11 +407,10 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
433
407
|
try {
|
|
434
408
|
// @ts-ignore
|
|
435
409
|
obj.stats = fs.statSync(path.join(this.objectsDir, id, name));
|
|
436
|
-
}
|
|
410
|
+
}
|
|
411
|
+
catch (err) {
|
|
437
412
|
if (!name.endsWith('/_data.json')) {
|
|
438
|
-
this.log.warn(
|
|
439
|
-
`${namespaceLog} Got MGET request for non existing file ${dataId}, err: ${err.message}`
|
|
440
|
-
);
|
|
413
|
+
this.log.warn(`${namespaceLog} Got MGET request for non existing file ${dataId}, err: ${err.message}`);
|
|
441
414
|
}
|
|
442
415
|
response.push(null);
|
|
443
416
|
return;
|
|
@@ -445,65 +418,58 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
445
418
|
response.push(JSON.stringify(obj));
|
|
446
419
|
});
|
|
447
420
|
handler.sendArray(responseId, response);
|
|
448
|
-
}
|
|
421
|
+
}
|
|
422
|
+
else {
|
|
449
423
|
// Handle request for File data
|
|
450
424
|
handler.sendError(responseId, new Error('MGET-UNSUPPORTED for file data'));
|
|
451
425
|
}
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
new Error('MGET-UNSUPPORTED for namespace ' + namespace + ': Data=' + JSON.stringify(data))
|
|
456
|
-
);
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
handler.sendError(responseId, new Error(`MGET-UNSUPPORTED for namespace ${namespace}: Data=${JSON.stringify(data)}`));
|
|
457
429
|
}
|
|
458
430
|
});
|
|
459
|
-
|
|
460
431
|
// Handle Redis "GET" requests
|
|
461
432
|
handler.on('get', (data, responseId) => {
|
|
462
433
|
const { id, namespace, name, isMeta } = this._normalizeId(data[0]);
|
|
463
|
-
|
|
464
434
|
if (namespace === this.namespaceObj) {
|
|
465
435
|
const result = this._getObject(id);
|
|
466
436
|
if (!result) {
|
|
467
437
|
handler.sendNull(responseId);
|
|
468
|
-
}
|
|
438
|
+
}
|
|
439
|
+
else {
|
|
469
440
|
handler.sendBulk(responseId, JSON.stringify(result));
|
|
470
441
|
}
|
|
471
|
-
}
|
|
442
|
+
}
|
|
443
|
+
else if (namespace === this.namespaceFile) {
|
|
472
444
|
// Handle request for Meta data for files
|
|
473
445
|
if (isMeta) {
|
|
474
446
|
let stats;
|
|
475
447
|
try {
|
|
476
448
|
stats = fs.statSync(path.join(this.objectsDir, id, name));
|
|
477
|
-
}
|
|
449
|
+
}
|
|
450
|
+
catch {
|
|
478
451
|
return void handler.sendNull(responseId);
|
|
479
452
|
}
|
|
480
453
|
if (stats.isDirectory()) {
|
|
481
|
-
return void handler.sendBulk(
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
isDir: true
|
|
487
|
-
})
|
|
488
|
-
);
|
|
454
|
+
return void handler.sendBulk(responseId, JSON.stringify({
|
|
455
|
+
file: name,
|
|
456
|
+
stats: {},
|
|
457
|
+
isDir: true
|
|
458
|
+
}));
|
|
489
459
|
}
|
|
490
460
|
this._loadFileSettings(id);
|
|
491
461
|
if (!this.fileOptions[id] || !this.fileOptions[id][name]) {
|
|
492
462
|
return void handler.sendNull(responseId);
|
|
493
463
|
}
|
|
494
|
-
|
|
495
464
|
let obj = this._clone(this.fileOptions[id][name]);
|
|
496
465
|
if (typeof obj !== 'object') {
|
|
497
466
|
obj = {
|
|
498
467
|
mimeType: obj,
|
|
499
468
|
acl: {
|
|
500
|
-
owner:
|
|
501
|
-
|
|
502
|
-
ownerGroup:
|
|
503
|
-
(this.defaultNewAcl && this.defaultNewAcl.ownerGroup) ||
|
|
469
|
+
owner: (this.defaultNewAcl && this.defaultNewAcl.owner) || utils.CONSTS.SYSTEM_ADMIN_USER,
|
|
470
|
+
ownerGroup: (this.defaultNewAcl && this.defaultNewAcl.ownerGroup) ||
|
|
504
471
|
utils.CONSTS.SYSTEM_ADMIN_GROUP,
|
|
505
|
-
permissions:
|
|
506
|
-
(this.defaultNewAcl && this.defaultNewAcl.file.permissions) ||
|
|
472
|
+
permissions: (this.defaultNewAcl && this.defaultNewAcl.file.permissions) ||
|
|
507
473
|
utils.CONSTS.ACCESS_USER_ALL |
|
|
508
474
|
utils.CONSTS.ACCESS_GROUP_ALL |
|
|
509
475
|
utils.CONSTS.ACCESS_EVERY_ALL // 777
|
|
@@ -512,12 +478,14 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
512
478
|
}
|
|
513
479
|
obj.stats = stats;
|
|
514
480
|
handler.sendBulk(responseId, JSON.stringify(obj));
|
|
515
|
-
}
|
|
481
|
+
}
|
|
482
|
+
else {
|
|
516
483
|
// Handle request for File data
|
|
517
484
|
let data;
|
|
518
485
|
try {
|
|
519
486
|
data = this._readFile(id, name);
|
|
520
|
-
}
|
|
487
|
+
}
|
|
488
|
+
catch {
|
|
521
489
|
return void handler.sendNull(responseId);
|
|
522
490
|
}
|
|
523
491
|
if (data.fileContent === undefined || data.fileContent === null) {
|
|
@@ -527,308 +495,290 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
527
495
|
if (!Buffer.isBuffer(fileData) && tools.isObject(fileData)) {
|
|
528
496
|
// if its an invalid object, stringify it and log warning
|
|
529
497
|
fileData = JSON.stringify(fileData);
|
|
530
|
-
this.log.warn(
|
|
531
|
-
`${namespaceLog} Data of "${id}/${name}" has invalid structure at file data request: ${fileData}`
|
|
532
|
-
);
|
|
498
|
+
this.log.warn(`${namespaceLog} Data of "${id}/${name}" has invalid structure at file data request: ${fileData}`);
|
|
533
499
|
}
|
|
534
500
|
handler.sendBufBulk(responseId, Buffer.from(fileData));
|
|
535
501
|
}
|
|
536
|
-
}
|
|
502
|
+
}
|
|
503
|
+
else if (namespace === this.namespaceMeta) {
|
|
537
504
|
// special handling for the primaryHost
|
|
538
505
|
if (id === 'objects.primaryHost') {
|
|
539
506
|
// we are the server -> we are primary
|
|
540
507
|
handler.sendString(this.settings.hostname);
|
|
541
|
-
}
|
|
508
|
+
}
|
|
509
|
+
else {
|
|
542
510
|
const result = this.getMeta(id);
|
|
543
511
|
if (result === undefined || result === null) {
|
|
544
512
|
handler.sendNull(responseId);
|
|
545
|
-
}
|
|
513
|
+
}
|
|
514
|
+
else {
|
|
546
515
|
handler.sendBulk(responseId, result);
|
|
547
516
|
}
|
|
548
517
|
}
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
new Error('GET-UNSUPPORTED for namespace ' + namespace + ': Data=' + JSON.stringify(data))
|
|
553
|
-
);
|
|
518
|
+
}
|
|
519
|
+
else {
|
|
520
|
+
handler.sendError(responseId, new Error(`GET-UNSUPPORTED for namespace ${namespace}: Data=${JSON.stringify(data)}`));
|
|
554
521
|
}
|
|
555
522
|
});
|
|
556
|
-
|
|
557
523
|
// Handle Redis "SET" requests
|
|
558
524
|
handler.on('set', (data, responseId) => {
|
|
559
525
|
const { id, namespace, name, isMeta } = this._normalizeId(data[0]);
|
|
560
|
-
|
|
561
526
|
if (namespace === this.namespaceObj) {
|
|
562
527
|
try {
|
|
563
528
|
const obj = JSON.parse(data[1].toString('utf-8'));
|
|
564
529
|
this._setObjectDirect(id, obj);
|
|
565
|
-
}
|
|
530
|
+
}
|
|
531
|
+
catch (err) {
|
|
566
532
|
return void handler.sendError(responseId, new Error(`ERROR setObject id=${id}: ${err.message}`));
|
|
567
533
|
}
|
|
568
534
|
handler.sendString(responseId, 'OK');
|
|
569
|
-
}
|
|
570
|
-
|
|
535
|
+
}
|
|
536
|
+
else if (namespace === this.namespaceFile) {
|
|
537
|
+
// Handle request to set meta-data, we ignore it because
|
|
571
538
|
// will be set when data are written
|
|
572
539
|
if (isMeta) {
|
|
573
540
|
this._loadFileSettings(id);
|
|
574
|
-
|
|
575
541
|
try {
|
|
576
542
|
fs.ensureDirSync(path.join(this.objectsDir, id, path.dirname(name)));
|
|
577
|
-
|
|
578
|
-
// only set if the meta object is already/still existing
|
|
543
|
+
// only set if the meta-object is already/still existing
|
|
579
544
|
if (this.fileOptions[id]) {
|
|
580
545
|
this.fileOptions[id][name] = JSON.parse(data[1].toString('utf-8'));
|
|
581
|
-
fs.writeFileSync(
|
|
582
|
-
path.join(this.objectsDir, id, '_data.json'),
|
|
583
|
-
JSON.stringify(this.fileOptions[id])
|
|
584
|
-
);
|
|
546
|
+
fs.writeFileSync(path.join(this.objectsDir, id, '_data.json'), JSON.stringify(this.fileOptions[id]));
|
|
585
547
|
}
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
new Error(`ERROR writeFile-Meta id=${id}: ${err.message}`)
|
|
590
|
-
);
|
|
548
|
+
}
|
|
549
|
+
catch (err) {
|
|
550
|
+
return void handler.sendError(responseId, new Error(`ERROR writeFile-Meta id=${id}: ${err.message}`));
|
|
591
551
|
}
|
|
592
552
|
handler.sendString(responseId, 'OK');
|
|
593
|
-
}
|
|
553
|
+
}
|
|
554
|
+
else {
|
|
594
555
|
// Handle request to write the file
|
|
595
556
|
try {
|
|
596
557
|
this._writeFile(id, name, data[1]);
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
new Error(`ERROR writeFile id=${id}: ${err.message}`)
|
|
601
|
-
);
|
|
558
|
+
}
|
|
559
|
+
catch (err) {
|
|
560
|
+
return void handler.sendError(responseId, new Error(`ERROR writeFile id=${id}: ${err.message}`));
|
|
602
561
|
}
|
|
603
562
|
handler.sendString(responseId, 'OK');
|
|
604
563
|
}
|
|
605
|
-
}
|
|
564
|
+
}
|
|
565
|
+
else if (namespace === this.namespaceMeta) {
|
|
606
566
|
this.setMeta(id, data[1].toString('utf-8'));
|
|
607
567
|
handler.sendString(responseId, 'OK');
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
new Error(`SET-UNSUPPORTED for namespace ${namespace}: Data=${JSON.stringify(data)}`)
|
|
612
|
-
);
|
|
568
|
+
}
|
|
569
|
+
else {
|
|
570
|
+
handler.sendError(responseId, new Error(`SET-UNSUPPORTED for namespace ${namespace}: Data=${JSON.stringify(data)}`));
|
|
613
571
|
}
|
|
614
572
|
});
|
|
615
|
-
|
|
616
573
|
// Handle Redis "RENAME" requests
|
|
617
574
|
handler.on('rename', (data, responseId) => {
|
|
618
575
|
const oldDetails = this._normalizeId(data[0]);
|
|
619
576
|
const newDetails = this._normalizeId(data[1]);
|
|
620
|
-
|
|
621
577
|
if (oldDetails.namespace === this.namespaceFile) {
|
|
622
578
|
if (oldDetails.id !== newDetails.id) {
|
|
623
|
-
return void handler.sendError(
|
|
624
|
-
responseId,
|
|
625
|
-
new Error('ERROR renameObject: id needs to stay the same')
|
|
626
|
-
);
|
|
579
|
+
return void handler.sendError(responseId, new Error('ERROR renameObject: id needs to stay the same'));
|
|
627
580
|
}
|
|
628
|
-
|
|
629
581
|
// Handle request for Meta data for files
|
|
630
582
|
if (oldDetails.isMeta) {
|
|
631
583
|
handler.sendString(responseId, 'OK');
|
|
632
|
-
}
|
|
584
|
+
}
|
|
585
|
+
else {
|
|
633
586
|
// Handle request for File data
|
|
634
587
|
try {
|
|
635
588
|
this._rename(oldDetails.id, oldDetails.name, newDetails.name);
|
|
636
|
-
}
|
|
589
|
+
}
|
|
590
|
+
catch {
|
|
637
591
|
return void handler.sendNull(responseId);
|
|
638
592
|
}
|
|
639
593
|
handler.sendString(responseId, 'OK');
|
|
640
594
|
}
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
new Error(`RENAME-UNSUPPORTED for namespace ${oldDetails.namespace}: Data=${JSON.stringify(data)}`)
|
|
645
|
-
);
|
|
595
|
+
}
|
|
596
|
+
else {
|
|
597
|
+
handler.sendError(responseId, new Error(`RENAME-UNSUPPORTED for namespace ${oldDetails.namespace}: Data=${JSON.stringify(data)}`));
|
|
646
598
|
}
|
|
647
599
|
});
|
|
648
|
-
|
|
649
600
|
// Handle Redis "DEL" request for state and session namespace
|
|
650
601
|
handler.on('del', (data, responseId) => {
|
|
651
602
|
const { id, namespace, name, isMeta } = this._normalizeId(data[0]);
|
|
652
|
-
|
|
653
603
|
if (namespace === this.namespaceObj) {
|
|
654
604
|
try {
|
|
655
605
|
this._delObject(id);
|
|
656
|
-
}
|
|
606
|
+
}
|
|
607
|
+
catch (err) {
|
|
657
608
|
return void handler.sendError(responseId, err);
|
|
658
609
|
}
|
|
659
610
|
handler.sendInteger(responseId, 1);
|
|
660
|
-
}
|
|
661
|
-
|
|
611
|
+
}
|
|
612
|
+
else if (namespace === this.namespaceFile) {
|
|
613
|
+
// Handle request to delete meta-data, we ignore it because
|
|
662
614
|
// will be removed when data are deleted
|
|
663
615
|
if (isMeta) {
|
|
664
616
|
handler.sendString(responseId, 'OK');
|
|
665
|
-
}
|
|
617
|
+
}
|
|
618
|
+
else {
|
|
666
619
|
// Handle request to remove the file
|
|
667
620
|
try {
|
|
668
621
|
this._unlink(id, name);
|
|
669
|
-
}
|
|
622
|
+
}
|
|
623
|
+
catch (err) {
|
|
670
624
|
return void handler.sendError(responseId, err);
|
|
671
625
|
}
|
|
672
626
|
handler.sendString(responseId, 'OK');
|
|
673
627
|
}
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
new Error(`DEL-UNSUPPORTED for namespace ${namespace}: Data=${JSON.stringify(data)}`)
|
|
678
|
-
);
|
|
628
|
+
}
|
|
629
|
+
else {
|
|
630
|
+
handler.sendError(responseId, new Error(`DEL-UNSUPPORTED for namespace ${namespace}: Data=${JSON.stringify(data)}`));
|
|
679
631
|
}
|
|
680
632
|
});
|
|
681
|
-
|
|
682
633
|
handler.on('exists', (data, responseId) => {
|
|
683
634
|
if (!data || !data.length) {
|
|
684
635
|
return void handler.sendInteger(responseId, 0);
|
|
685
636
|
}
|
|
686
|
-
|
|
687
637
|
// Note: we only simulate single key existence check
|
|
688
638
|
const { id, namespace, name } = this._normalizeId(data[0]);
|
|
689
|
-
|
|
690
639
|
if (namespace === this.namespaceObj) {
|
|
691
640
|
let exists;
|
|
692
641
|
try {
|
|
693
642
|
exists = this._objectExists(id);
|
|
694
|
-
}
|
|
643
|
+
}
|
|
644
|
+
catch (e) {
|
|
695
645
|
return void handler.sendError(responseId, e);
|
|
696
646
|
}
|
|
697
647
|
handler.sendInteger(responseId, exists ? 1 : 0);
|
|
698
|
-
}
|
|
648
|
+
}
|
|
649
|
+
else if (namespace === this.namespaceFile) {
|
|
699
650
|
let exists;
|
|
700
651
|
try {
|
|
701
652
|
exists = this._fileExists(id, name);
|
|
702
|
-
}
|
|
653
|
+
}
|
|
654
|
+
catch (e) {
|
|
703
655
|
return void handler.sendError(responseId, e);
|
|
704
656
|
}
|
|
705
657
|
handler.sendInteger(responseId, exists ? 1 : 0);
|
|
706
|
-
}
|
|
658
|
+
}
|
|
659
|
+
else if (namespace === this.namespaceSet) {
|
|
707
660
|
// we are not using sets in simulator, so just say it exists
|
|
708
661
|
return void handler.sendInteger(responseId, 1);
|
|
709
|
-
}
|
|
662
|
+
}
|
|
663
|
+
else {
|
|
710
664
|
handler.sendError(responseId, new Error(`EXISTS-UNSUPPORTED for namespace ${namespace}`));
|
|
711
665
|
}
|
|
712
666
|
});
|
|
713
|
-
|
|
714
667
|
// handle Redis "SCAN" request for objects namespace
|
|
715
668
|
handler.on('scan', (data, responseId) => {
|
|
716
669
|
if (!data || data.length < 3) {
|
|
717
670
|
return void handler.sendArray(responseId, ['0', []]);
|
|
718
671
|
}
|
|
719
|
-
|
|
720
672
|
return this._handleScanOrKeys(handler, data[2], responseId, true);
|
|
721
673
|
});
|
|
722
|
-
|
|
723
674
|
// Handle Redis "KEYS" request for state namespace
|
|
724
675
|
handler.on('keys', (data, responseId) => {
|
|
725
676
|
if (!data || !data.length) {
|
|
726
677
|
return void handler.sendArray(responseId, []);
|
|
727
678
|
}
|
|
728
|
-
|
|
729
679
|
return this._handleScanOrKeys(handler, data[0], responseId);
|
|
730
680
|
});
|
|
731
|
-
|
|
732
681
|
// commands for redis SETS, just dummies
|
|
733
682
|
handler.on('sadd', (data, responseId) => {
|
|
734
683
|
return void handler.sendInteger(responseId, 1);
|
|
735
684
|
});
|
|
736
|
-
|
|
737
685
|
handler.on('srem', (data, responseId) => {
|
|
738
686
|
return void handler.sendInteger(responseId, 1);
|
|
739
687
|
});
|
|
740
|
-
|
|
741
688
|
handler.on('sscan', (data, responseId) => {
|
|
742
689
|
// for file DB it does the same as scan but data looks different
|
|
743
690
|
if (!data || data.length < 4) {
|
|
744
691
|
return void handler.sendArray(responseId, ['0', []]);
|
|
745
692
|
}
|
|
746
|
-
|
|
747
693
|
return this._handleScanOrKeys(handler, data[3], responseId, true);
|
|
748
694
|
});
|
|
749
|
-
|
|
750
695
|
// Handle Redis "PSUBSCRIBE" request for state, log and session namespace
|
|
751
696
|
handler.on('psubscribe', (data, responseId) => {
|
|
752
|
-
const { id, namespace } = this._normalizeId(data[0]);
|
|
753
|
-
|
|
697
|
+
const { id, namespace, name } = this._normalizeId(data[0]);
|
|
754
698
|
if (namespace === this.namespaceObj) {
|
|
755
699
|
this._subscribeConfigForClient(handler, id);
|
|
756
700
|
handler.sendArray(responseId, ['psubscribe', data[0], 1]);
|
|
757
|
-
}
|
|
701
|
+
}
|
|
702
|
+
else if (namespace === this.namespaceMeta) {
|
|
758
703
|
this._subscribeMeta(handler, id);
|
|
759
704
|
handler.sendArray(responseId, ['psubscribe', data[0], 1]);
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
705
|
+
}
|
|
706
|
+
else if (namespace === this.namespaceFile) {
|
|
707
|
+
this._subscribeFileForClient(handler, id, name);
|
|
708
|
+
handler.sendArray(responseId, ['psubscribe', data[0], 1]);
|
|
709
|
+
}
|
|
710
|
+
else {
|
|
711
|
+
handler.sendError(responseId, new Error(`PSUBSCRIBE-UNSUPPORTED for namespace ${namespace}: Data=${JSON.stringify(data)}`));
|
|
765
712
|
}
|
|
766
713
|
});
|
|
767
|
-
|
|
768
714
|
// Handle Redis "UNSUBSCRIBE" request for state, log and session namespace
|
|
769
715
|
handler.on('punsubscribe', (data, responseId) => {
|
|
770
|
-
const { id, namespace } = this._normalizeId(data[0]);
|
|
771
|
-
|
|
716
|
+
const { id, namespace, name } = this._normalizeId(data[0]);
|
|
772
717
|
if (namespace === this.namespaceObj) {
|
|
773
718
|
this._unsubscribeConfigForClient(handler, id);
|
|
774
719
|
handler.sendArray(responseId, ['punsubscribe', data[0], 1]);
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
720
|
+
}
|
|
721
|
+
else if (namespace === this.namespaceFile) {
|
|
722
|
+
this._unsubscribeFileForClient(handler, id, name);
|
|
723
|
+
handler.sendArray(responseId, ['punsubscribe', data[0], 1]);
|
|
724
|
+
}
|
|
725
|
+
else {
|
|
726
|
+
handler.sendError(responseId, new Error(`PUNSUBSCRIBE-UNSUPPORTED for namespace ${namespace}: Data=${JSON.stringify(data)}`));
|
|
780
727
|
}
|
|
781
728
|
});
|
|
782
|
-
|
|
783
729
|
// Handle Redis "SUBSCRIBE" ... currently mainly ignored
|
|
784
730
|
handler.on('subscribe', (data, responseId) => {
|
|
785
731
|
if (data[0].startsWith('__keyevent@')) {
|
|
786
732
|
// we ignore these type of events because we publish expires anyway directly
|
|
787
733
|
handler.sendArray(responseId, ['subscribe', data[0], 1]);
|
|
788
|
-
}
|
|
734
|
+
}
|
|
735
|
+
else {
|
|
789
736
|
handler.sendError(responseId, new Error(`SUBSCRIBE-UNSUPPORTED for ${data[0]}`));
|
|
790
737
|
}
|
|
791
738
|
});
|
|
792
|
-
|
|
793
739
|
// Handle Redis "CONFIG" ... currently mainly ignored
|
|
794
740
|
handler.on('config', (data, responseId) => {
|
|
795
|
-
|
|
741
|
+
const command = typeof data[0] === 'string' ? data[0].toLowerCase() : data[0].toString().toLowerCase();
|
|
742
|
+
if (command === 'set' && data[1] === 'notify-keyspace-events') {
|
|
796
743
|
// we ignore these type of commands for now, should only be to subscribe to keyspace events
|
|
797
744
|
handler.sendString(responseId, 'OK');
|
|
798
|
-
}
|
|
745
|
+
}
|
|
746
|
+
else if (command === 'set' && data[1] === 'lua-time-limit') {
|
|
799
747
|
// we ignore these type of commands for now, irrelevant
|
|
800
748
|
handler.sendString(responseId, 'OK');
|
|
801
|
-
}
|
|
802
|
-
|
|
749
|
+
}
|
|
750
|
+
else {
|
|
751
|
+
handler.sendError(responseId, new Error(`CONFIG-UNSUPPORTED for ${JSON.stringify(data)}`));
|
|
803
752
|
}
|
|
804
753
|
});
|
|
805
|
-
|
|
806
754
|
// handle client SETNAME/GETNAME
|
|
807
755
|
handler.on('client', (data, responseId) => {
|
|
808
756
|
if (data[0] === 'setname' && typeof data[1] === 'string') {
|
|
809
757
|
if (data[1] === '') {
|
|
810
758
|
// on empty string redis sets null again and sends 'OK'
|
|
811
759
|
connectionName = null;
|
|
812
|
-
}
|
|
760
|
+
}
|
|
761
|
+
else {
|
|
813
762
|
connectionName = data[1];
|
|
814
763
|
namespaceLog = connectionName;
|
|
815
764
|
}
|
|
816
765
|
handler.sendString(responseId, 'OK');
|
|
817
|
-
}
|
|
766
|
+
}
|
|
767
|
+
else if (data[0] === 'getname') {
|
|
818
768
|
if (typeof connectionName === 'string' && connectionName !== '') {
|
|
819
769
|
handler.sendString(responseId, connectionName);
|
|
820
|
-
}
|
|
770
|
+
}
|
|
771
|
+
else {
|
|
821
772
|
// redis sends null if no name defined
|
|
822
773
|
handler.sendNull(responseId);
|
|
823
774
|
}
|
|
824
|
-
}
|
|
775
|
+
}
|
|
776
|
+
else {
|
|
825
777
|
handler.sendError(responseId, new Error(`CLIENT-UNSUPPORTED for ${JSON.stringify(data)}`));
|
|
826
778
|
}
|
|
827
779
|
});
|
|
828
|
-
|
|
829
|
-
handler.on('error', err => this.log.warn(`${namespaceLog} Redis states: ${err}`));
|
|
780
|
+
handler.on('error', err => this.log.warn(`${namespaceLog} Redis objects: ${err}`));
|
|
830
781
|
}
|
|
831
|
-
|
|
832
782
|
/**
|
|
833
783
|
* Return connected RedisHandlers/Connections
|
|
834
784
|
* @returns {{}|*}
|
|
@@ -836,7 +786,6 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
836
786
|
getClients() {
|
|
837
787
|
return this.serverConnections;
|
|
838
788
|
}
|
|
839
|
-
|
|
840
789
|
/**
|
|
841
790
|
* Destructor of the class. Called by shutting down.
|
|
842
791
|
*/
|
|
@@ -846,14 +795,14 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
846
795
|
this.serverConnections[s].close();
|
|
847
796
|
delete this.serverConnections[s];
|
|
848
797
|
});
|
|
849
|
-
|
|
850
798
|
await new Promise(resolve => {
|
|
851
799
|
if (!this.server) {
|
|
852
800
|
return void resolve();
|
|
853
801
|
}
|
|
854
802
|
try {
|
|
855
803
|
this.server.close(() => resolve());
|
|
856
|
-
}
|
|
804
|
+
}
|
|
805
|
+
catch (e) {
|
|
857
806
|
console.log(e.message);
|
|
858
807
|
resolve();
|
|
859
808
|
}
|
|
@@ -861,7 +810,6 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
861
810
|
}
|
|
862
811
|
await super.destroy();
|
|
863
812
|
}
|
|
864
|
-
|
|
865
813
|
/**
|
|
866
814
|
* Get keys matching pattern and send it to given responseId, for "SCAN" and "KEYS" - Objects and files supported
|
|
867
815
|
*
|
|
@@ -873,7 +821,6 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
873
821
|
*/
|
|
874
822
|
_handleScanOrKeys(handler, pattern, responseId, isScan = false) {
|
|
875
823
|
const { id, namespace, name, isMeta } = this._normalizeId(pattern);
|
|
876
|
-
|
|
877
824
|
let response = [];
|
|
878
825
|
if (namespace === this.namespaceObj || namespace === this.namespaceObjects) {
|
|
879
826
|
response = this._getKeys(id).map(val => this.namespaceObj + val);
|
|
@@ -900,7 +847,8 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
900
847
|
}
|
|
901
848
|
];
|
|
902
849
|
}
|
|
903
|
-
}
|
|
850
|
+
}
|
|
851
|
+
catch (err) {
|
|
904
852
|
if (!err.message.endsWith(utils.ERRORS.ERROR_NOT_FOUND)) {
|
|
905
853
|
return void handler.sendError(responseId, new Error(`ERROR readDir id=${id}: ${err.message}`));
|
|
906
854
|
}
|
|
@@ -916,7 +864,8 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
916
864
|
if (entryId === '' || entryId === '*') {
|
|
917
865
|
entryId = arr.file;
|
|
918
866
|
arr.file = '_data.json'; // We return a "virtual file" to mark the directory as existing
|
|
919
|
-
}
|
|
867
|
+
}
|
|
868
|
+
else {
|
|
920
869
|
arr.file += '/_data.json'; // We return a "virtual file" to mark the directory as existing
|
|
921
870
|
}
|
|
922
871
|
}
|
|
@@ -925,20 +874,19 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
925
874
|
response.push(this.getFileId(entryId, baseName + arr.file, false));
|
|
926
875
|
});
|
|
927
876
|
handler.sendArray(responseId, isScan ? ['0', response] : response); // send out file or full db response
|
|
928
|
-
}
|
|
877
|
+
}
|
|
878
|
+
else {
|
|
929
879
|
// such a request should never happen
|
|
930
880
|
handler.sendArray(responseId, isScan ? ['0', []] : []); // send out file or full db response
|
|
931
881
|
}
|
|
932
|
-
}
|
|
882
|
+
}
|
|
883
|
+
else if (namespace === this.namespaceSet) {
|
|
933
884
|
handler.sendArray(responseId, isScan ? ['0', []] : []); // send out empty array, we have no sets
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
new Error(`${isScan ? 'SCAN' : 'KEYS'}-UNSUPPORTED for namespace ${namespace}: Pattern=${pattern}`)
|
|
938
|
-
);
|
|
885
|
+
}
|
|
886
|
+
else {
|
|
887
|
+
handler.sendError(responseId, new Error(`${isScan ? 'SCAN' : 'KEYS'}-UNSUPPORTED for namespace ${namespace}: Pattern=${pattern}`));
|
|
939
888
|
}
|
|
940
889
|
}
|
|
941
|
-
|
|
942
890
|
/**
|
|
943
891
|
* Initialize RedisHandler for a new network connection
|
|
944
892
|
* @param socket Network socket
|
|
@@ -950,13 +898,12 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
950
898
|
}
|
|
951
899
|
const options = {
|
|
952
900
|
log: this.log,
|
|
953
|
-
logScope:
|
|
901
|
+
logScope: `${this.settings.namespace || ''} Objects`,
|
|
954
902
|
handleAsBuffers: true,
|
|
955
903
|
enhancedLogging: this.settings.connection.enhancedLogging
|
|
956
904
|
};
|
|
957
905
|
const handler = new RedisHandler(socket, options);
|
|
958
906
|
this._socketEvents(handler);
|
|
959
|
-
|
|
960
907
|
this.serverConnections[socket.remoteAddress + ':' + socket.remotePort] = handler;
|
|
961
908
|
socket.on('close', () => {
|
|
962
909
|
if (this.serverConnections[socket.remoteAddress + ':' + socket.remotePort]) {
|
|
@@ -964,7 +911,6 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
964
911
|
}
|
|
965
912
|
});
|
|
966
913
|
}
|
|
967
|
-
|
|
968
914
|
/**
|
|
969
915
|
* Initialize Redis Server
|
|
970
916
|
* @param settings Settings object
|
|
@@ -978,25 +924,15 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
978
924
|
}
|
|
979
925
|
try {
|
|
980
926
|
this.server = net.createServer();
|
|
981
|
-
this.server.on('error', err =>
|
|
982
|
-
this.log.info(
|
|
983
|
-
`${this.namespace} ${settings.secure ? 'Secure ' : ''} Error inMem-objects listening on port ${
|
|
984
|
-
settings.port || 9001
|
|
985
|
-
}: ${err}`
|
|
986
|
-
)
|
|
987
|
-
);
|
|
927
|
+
this.server.on('error', err => this.log.info(`${this.namespace} ${settings.secure ? 'Secure ' : ''} Error inMem-objects listening on port ${settings.port || 9001}: ${err}`));
|
|
988
928
|
this.server.on('connection', socket => this._initSocket(socket));
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
settings.host === 'localhost' ? '127.0.0.1' : settings.host ? settings.host : undefined,
|
|
993
|
-
() => resolve()
|
|
994
|
-
);
|
|
995
|
-
} catch (err) {
|
|
929
|
+
this.server.listen(settings.port || 9001, settings.host === 'localhost' ? '127.0.0.1' : settings.host ? settings.host : undefined, () => resolve());
|
|
930
|
+
}
|
|
931
|
+
catch (err) {
|
|
996
932
|
reject(err);
|
|
997
933
|
}
|
|
998
934
|
});
|
|
999
935
|
}
|
|
1000
936
|
}
|
|
1001
|
-
|
|
1002
937
|
module.exports = ObjectsInMemoryServer;
|
|
938
|
+
//# sourceMappingURL=objectsInMemServerRedis.js.map
|