@screeps/storage 5.1.0 → 5.1.2

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/lib/db.js CHANGED
@@ -1,776 +1,776 @@
1
- var loki = require('lokijs'),
2
- q = require('q'),
3
- fs = require('fs'),
4
- _ = require('lodash'),
5
- common = require('@screeps/common'),
6
- C = require('@screeps/common/lib/constants'),
7
- config = common.configManager.config;
8
-
9
- /**
10
- * @type Loki
11
- */
12
- var db;
13
-
14
- Object.assign(config.storage, {
15
- dbOptions: {autosave: true, autosaveInterval: 10000},
16
- getDb() {
17
- try {
18
- fs.statSync(process.env.DB_PATH);
19
- }
20
- catch (e) {
21
- fs.writeFileSync(process.env.DB_PATH, '');
22
- }
23
- return new loki(process.env.DB_PATH, config.storage.dbOptions);
24
- },
25
- loadDb() {
26
- db = config.storage.getDb();
27
- return q.ninvoke(db, 'loadDatabase', {})
28
- .then(upgradeDb);
29
- }
30
- });
31
-
32
- function upgradeDb() {
33
-
34
- let upgradeInterval;
35
- if(process.send) {
36
- upgradeInterval = setInterval(function () {
37
- process.send('storageUpgrading');
38
- }, 1000);
39
- }
40
-
41
- let env = db.getCollection('env');
42
- let envData = env.get(1);
43
- if(!envData) {
44
- return;
45
- }
46
- if(!envData.databaseVersion || envData.databaseVersion < 4) {
47
- console.log("Upgrading database to version 4");
48
-
49
- const innerRooms = db.getCollection('rooms').find({_id: {$regex: '^[WE][1-9][NS][1-9]$'}});
50
- innerRooms.forEach(room => {
51
- room.bus = false;
52
- return db.getCollection('rooms').update(room);
53
- });
54
-
55
- const depositTypes = [C.RESOURCE_SILICON, C.RESOURCE_METAL, C.RESOURCE_BIOMASS, C.RESOURCE_MIST];
56
- const busRooms = db.getCollection('rooms').find({$or: [{_id: {$regex: '^[WE]\\d*0'}},{_id: {$regex: '0$'}}]});
57
- busRooms.forEach(room => {
58
- const [match, longitude, latitude] = /^[WE](\d+)[NS](\d+)$/.exec(room._id);
59
- if(match) {
60
- room.depositType = depositTypes[(longitude+latitude)%4];
61
- return db.getCollection('rooms').update(room);
62
- }
63
- });
64
- envData.databaseVersion = 4;
65
- env.update(envData);
66
- }
67
-
68
- if(envData.databaseVersion < 5) {
69
- console.log("Upgrading database to version 5");
70
-
71
- const energyOnly = function energyOnly(structure) {
72
- structure.store = { energy: structure.energy };
73
- structure.storeCapacityResource = {energy: structure.energyCapacity};
74
- delete structure.energy;
75
- delete structure.energyCapacity;
76
- };
77
-
78
- const storeOnly = function storeOnly(structure) {
79
- if(!_.isUndefined(structure.energyCapacity)) {
80
- structure.storeCapacity = structure.energyCapacity;
81
- delete structure.energyCapacity;
82
- }
83
-
84
- structure.store = {};
85
- C.RESOURCES_ALL.forEach(r => {
86
- if(!_.isUndefined(structure[r])) {
87
- structure.store[r] = structure[r];
88
- delete structure[r];
89
- }
90
- });
91
- };
92
-
93
- const converters = {
94
- spawn: energyOnly,
95
- extension: energyOnly,
96
- tower: energyOnly,
97
- link: energyOnly,
98
- storage: storeOnly,
99
- terminal: storeOnly,
100
- container: storeOnly,
101
- factory: storeOnly,
102
- creep: storeOnly,
103
- powerCreep: storeOnly,
104
- tombstone: storeOnly,
105
- nuker: function nuker(structure) {
106
- structure.store = { energy: structure.energy, G: structure.G };
107
- structure.storeCapacityResource = { energy: structure.energyCapacity, G: structure.GCapacity };
108
-
109
- delete structure.energy;
110
- delete structure.energyCapacity;
111
- delete structure.G;
112
- delete structure.GCapacity;
113
- },
114
- powerSpawn: function powerSpawn(structure) {
115
- structure.store = { energy: structure.energy, power: structure.power };
116
- structure.storeCapacityResource = { energy: structure.energyCapacity, power: structure.powerCapacity };
117
-
118
- delete structure.energy;
119
- delete structure.energyCapacity;
120
- delete structure.power;
121
- delete structure.powerCapacity;
122
- },
123
- lab: function lab(structure) {
124
- structure.store = { energy: structure.energy };
125
- structure.storeCapacityResource = { energy: structure.energyCapacity };
126
- if(structure.mineralType && structure.mineralAmount) {
127
- structure.store[structure.mineralType] = structure.mineralAmount;
128
- structure.storeCapacityResource[structure.mineralType] = structure.mineralCapacity;
129
- } else {
130
- structure.storeCapacity = structure.energyCapacity + structure.mineralCapacity;
131
- }
132
-
133
- delete structure.energy;
134
- delete structure.energyCapacity;
135
- delete structure.mineralType;
136
- delete structure.mineralAmount;
137
- delete structure.mineralCapacity;
138
- }
139
- };
140
-
141
- const powerCreepsCollection = db.getCollection("users.power_creeps");
142
- if(powerCreepsCollection) {
143
- const powerCreeps = powerCreepsCollection.find({});
144
- powerCreeps.forEach(powerCreep => {
145
- console.log(`powerCreep${powerCreep._id}`);
146
- converters.powerCreep(powerCreep);
147
- return powerCreepsCollection.update(powerCreep);
148
- });
149
- }
150
-
151
- const roomObjects = db.getCollection("rooms.objects").find({type: {$in: _.keys(converters)}});
152
- roomObjects.forEach(object => {
153
- console.log(`${object.type}#${object._id}`);
154
- converters[object.type](object);
155
- return db.getCollection("rooms.objects").update(object);
156
- });
157
-
158
- const nowTimestamp = new Date().getTime();
159
- const orders = db.getCollection("market.orders").find({});
160
- orders.forEach(order => {
161
- if(!order.createdTimestamp) {
162
- console.log(`order#${order._id}`);
163
- order.createdTimestamp = nowTimestamp;
164
- return db.getCollection("market.orders").update(order);
165
- }
166
- });
167
- envData.databaseVersion = 5;
168
- env.update(envData);
169
- }
170
-
171
- if(envData.databaseVersion < 6) {
172
- console.log("Upgrading database to version 6");
173
-
174
- const roomObjects = db.getCollection("rooms.objects").find({type: 'powerBank'});
175
- roomObjects.forEach(object => {
176
- console.log(`${object.type}#${object._id}`);
177
- object.store = { power: object.power };
178
- delete object.power;
179
- return db.getCollection("rooms.objects").update(object);
180
- });
181
-
182
- envData.databaseVersion = 6;
183
- env.update(envData);
184
- }
185
-
186
- if(envData.databaseVersion < 7) {
187
- console.log("Upgrading database to version 7");
188
-
189
- const user = db.getCollection("users").findOne({_id: "2"});
190
- user.badge = {
191
- "type" : {
192
- "path1" : "m 60.493413,13.745781 -1.122536,7.527255 -23.302365,-6.118884 -24.097204,26.333431 6.412507,0.949878 -5.161481,19.706217 26.301441,24.114728 1.116562,-7.546193 23.350173,6.122868 24.097202,-26.318478 -6.462307,-0.95785 5.16845,-19.699243 z m -1.58271,10.611118 -0.270923,1.821013 C 57.330986,25.69819 55.969864,25.331543 54.570958,25.072546 Z m -8.952409,4.554029 c 11.653612,0 21.055294,9.408134 21.055294,21.069735 0,11.661603 -9.401682,21.068738 -21.055294,21.068738 -11.65361,0 -21.055297,-9.407135 -21.055297,-21.068738 0,-11.661601 9.401687,-21.069735 21.055297,-21.069735 z M 26.634018,40.123069 c -0.262324,0.618965 -0.494865,1.252967 -0.708185,1.895768 l -0.0508,-0.104656 -0.194228,-0.417627 c 0.261245,-0.385697 0.631962,-0.909531 0.953211,-1.373485 z m 47.391601,17.714764 0.115539,0.237219 0.214148,0.462479 c -0.380159,0.55986 -0.886342,1.281124 -1.3835,1.988466 0.400298,-0.870957 0.752837,-1.767746 1.053813,-2.688164 z M 41.364458,73.812322 c 0.694434,0.251619 1.40261,0.471895 2.123558,0.662817 l -2.303841,0.558165 z",
193
- "path2" : "m 60.857962,24.035953 -6.397566,1.055531 c 6.084137,1.084905 11.78633,4.394548 15.786244,9.746957 5.741405,7.682749 6.465607,17.544704 2.736121,25.67958 1.511089,-2.147013 2.622575,-3.851337 2.622575,-3.851337 l 1.628526,0.241209 c 0.726895,-2.869027 1.004942,-5.843252 0.811775,-8.806053 l 1.185288,-8.634615 -3.768025,-3.072898 -2.908435,-3.21842 c -0.0103,-0.01383 -0.01958,-0.02805 -0.02988,-0.04186 -3.118009,-4.172293 -7.17889,-7.228662 -11.666624,-9.098091 z M 50.001124,37.965163 A 12.020784,12.029027 0 0 0 37.979913,49.994617 12.020784,12.029027 0 0 0 50.001124,62.024074 12.020784,12.029027 0 0 0 62.022337,49.994617 12.020784,12.029027 0 0 0 50.001124,37.965163 Z M 27.019485,39.55693 c -1.481686,2.114179 -2.5658,3.779575 -2.5658,3.779575 l -1.647451,-0.244197 c -0.69707,2.775045 -0.977606,5.64628 -0.81476,8.511019 l -1.22015,8.890775 3.768021,3.072896 3.422394,3.786551 c 2.921501,3.715734 6.608397,6.499915 10.668588,8.29872 l 5.050921,-1.223973 C 38.324728,73.038607 33.383805,69.887984 29.806406,65.100956 28.655972,63.561522 27.71377,61.932905 26.961715,60.249903 L 24.8272,48.359991 c 0.194234,-3.030146 0.935183,-6.015406 2.192285,-8.803061 z"
194
- },
195
- "color1" : "#735252",
196
- "color2" : "#390305",
197
- "color3" : "#ff0d39",
198
- "flip" : false
199
- };
200
- db.getCollection("users").update(user);
201
-
202
- envData.databaseVersion = 7;
203
- env.update(envData);
204
- }
205
-
206
- if(envData.databaseVersion < 8) {
207
- console.log("Upgrading database to version 8");
208
- const gameTime = parseInt(envData.data[common.storage.env.keys.GAMETIME]);
209
- const roomObjects = db.getCollection("rooms.objects").find({
210
- 'type': {$in: ['spawn', 'invaderCore']},
211
- 'spawning': {$ne: null},
212
- 'spawning.remainingTime': {$exists: true}});
213
-
214
- roomObjects.forEach(object => {
215
- console.log(`${object.type}#${object._id}: ${JSON.stringify(object.spawning, 0, 2)}`);
216
- object.spawning.spawnTime = gameTime + object.spawning.remainingTime;
217
- delete object.spawning.remainingTime;
218
- return db.getCollection("rooms.objects").update(object);
219
- });
220
-
221
- envData.databaseVersion = 8;
222
- env.update(envData);
223
- }
224
-
225
- if(envData.databaseVersion < 9) {
226
- console.log("Upgrading database to version 9");
227
-
228
- const rooms = db.getCollection("rooms").find({});
229
-
230
- const activeRoomsNames = [];
231
- rooms.forEach(room => {
232
- if(room.active) {
233
- activeRoomsNames.push(room._id);
234
- }
235
- delete room.active;
236
- return db.getCollection("rooms").update(room);
237
- });
238
-
239
- const env = db.getCollection('env');
240
- let values = env.get(1) || {};
241
- if (values) {
242
- values.data[common.storage.env.keys.ACTIVE_ROOMS] = activeRoomsNames;
243
- env.update(values);
244
- } else {
245
- values = {data: {[common.storage.env.keys.ACTIVE_ROOMS]: activeRoomsNames}};
246
- env.insert(values);
247
- }
248
-
249
- envData.databaseVersion = 9;
250
- env.update(envData);
251
- }
252
-
253
- clearInterval(upgradeInterval);
254
- }
255
-
256
-
257
- function updateDocument(doc, update) {
258
- if (update.$set) {
259
- _.extend(doc, update.$set);
260
- }
261
- if (update.$merge) {
262
- _.merge(doc, update.$merge);
263
- }
264
- if (update.$inc) {
265
- _.forEach(update.$inc, (val, key) => doc[key] = (doc[key] || 0) + val);
266
- }
267
- if (update.$unset) {
268
- for (var j in update.$unset) {
269
- delete doc[j];
270
- }
271
- }
272
- if(update.$addToSet) {
273
- for(let i in update.$addToSet) {
274
- if(!doc[i]) {
275
- doc[i] = [];
276
- }
277
- if(doc[i].indexOf(update.$addToSet[i]) == -1) {
278
- doc[i].push(update.$addToSet[i]);
279
- }
280
- }
281
- }
282
- if(update.$pull) {
283
- for(let i in update.$pull) {
284
- if(!doc[i]) {
285
- continue;
286
- }
287
- var idx = doc[i].indexOf(update.$pull[i]);
288
- if(idx != -1) {
289
- doc[i].splice(idx, 1);
290
- }
291
- }
292
- }
293
- }
294
-
295
- setInterval(function envCleanExpired() {
296
- var env = db.getCollection('env');
297
- var values = env.get(1);
298
- var expiration = env.get(2);
299
- var dirty = false;
300
- if (expiration) {
301
- for (var name in expiration.data) {
302
- if (Date.now() > expiration.data[name]) {
303
- dirty = true;
304
- if (values.data[name]) {
305
- delete values.data[name];
306
- }
307
- delete expiration.data[name];
308
- }
309
- }
310
- }
311
- if (dirty) {
312
- env.update(values);
313
- env.update(expiration);
314
- }
315
- }, 10000);
316
-
317
- function getRandomString() {
318
- for (var val = Math.floor(Math.random() * 0x10000).toString(16); val.length < 4; val = '0' + val);
319
- return val;
320
- }
321
-
322
- function genId(obj) {
323
- var id = getRandomString() + Date.now().toString(16).slice(4) + getRandomString();
324
- if (obj && !obj._id) {
325
- obj._id = id;
326
- }
327
- return id;
328
- }
329
-
330
- function getOrAddCollection(collectionName) {
331
- var collection = db.getCollection(collectionName);
332
- if (!collection) {
333
- collection = db.addCollection(collectionName);
334
- }
335
- collection.ensureUniqueIndex('_id');
336
- switch(collectionName) {
337
- case 'rooms.objects': {
338
- collection.ensureIndex('room');
339
- collection.ensureIndex('user');
340
- break;
341
- }
342
- case 'rooms.intents': {
343
- collection.ensureIndex('room');
344
- break;
345
- }
346
- case 'users': {
347
- collection.ensureIndex('username');
348
- break;
349
- }
350
- case 'rooms.flags': {
351
- collection.ensureIndex('room');
352
- collection.ensureIndex('user');
353
- break;
354
- }
355
- case 'rooms.terrain': {
356
- collection.ensureIndex('room');
357
- break;
358
- }
359
- case 'transactions': {
360
- collection.ensureIndex('user');
361
- break;
362
- }
363
- case 'users.code': {
364
- collection.ensureIndex('user');
365
- break;
366
- }
367
- case 'users.console': {
368
- collection.ensureIndex('user');
369
- break;
370
- }
371
- case 'users.money': {
372
- collection.ensureIndex('user');
373
- break;
374
- }
375
- case 'users.notifications': {
376
- collection.ensureIndex('user');
377
- break;
378
- }
379
- case 'users.resources': {
380
- collection.ensureIndex('user');
381
- break;
382
- }
383
- case 'users.power_creeps': {
384
- collection.ensureIndex('user');
385
- break;
386
- }
387
- }
388
- return collection;
389
- }
390
-
391
- function recursReplaceNeNull(val) {
392
- if(!_.isObject(val)) {
393
- return;
394
- }
395
-
396
- for(var i in val) {
397
- if (_.isEqual(val[i], {$ne: null}) && !val.$and) {
398
- val.$and = [{[i]: {$ne: null}}, {[i]: {$ne: undefined}}];
399
- delete val[i];
400
- }
401
- if (_.isEqual(val[i], {$eq: null}) && !val.$or) {
402
- val.$or = [{[i]: {$eq: null}}, {[i]: {$eq: undefined}}];
403
- delete val[i];
404
- }
405
- recursReplaceNeNull(val[i]);
406
- }
407
- }
408
-
409
- module.exports = {
410
-
411
- dbRequest(collectionName, method, argsArray, cb) {
412
- try {
413
- var collection = getOrAddCollection(collectionName);
414
- if (method == 'insert') {
415
- if (_.isArray(argsArray[0])) {
416
- argsArray[0].forEach(genId);
417
- }
418
- else {
419
- genId(argsArray[0]);
420
- }
421
- }
422
-
423
- if(method == 'find' || method == 'findOne' || method == 'count' || method == 'removeWhere') {
424
- recursReplaceNeNull(argsArray[0]);
425
- }
426
-
427
- var result = collection[method].apply(collection, argsArray);
428
- cb(null, result);
429
- }
430
- catch (e) {
431
- cb(e.message);
432
- console.error(e);
433
- }
434
- },
435
-
436
- dbUpdate(collectionName, query, update, params, cb) {
437
- try {
438
- recursReplaceNeNull(query);
439
- var collection = getOrAddCollection(collectionName);
440
- var result = [];
441
- if (Object.keys(query).length == 1 && query._id && _.isString(query._id)) {
442
- var found = collection.by('_id', query._id);
443
- if(found) {
444
- result = [found];
445
- }
446
- }
447
- else {
448
- result = collection.find(query);
449
- }
450
- if (result.length) {
451
- result.forEach(doc => {
452
- updateDocument(doc, update);
453
- collection.update(doc);
454
- });
455
- cb(null, {modified: result.length});
456
- }
457
- else if (params && params.upsert) {
458
- var item = {};
459
- if (query.$and) {
460
- query.$and.forEach(i => _.extend(item, i));
461
- }
462
- else {
463
- _.extend(item, query);
464
- }
465
- updateDocument(item, update);
466
- genId(item);
467
- collection.insert(item);
468
- cb(null, {inserted: 1});
469
- }
470
- else {
471
- cb(null, {});
472
- }
473
- }
474
- catch (e) {
475
- cb(e.message);
476
- console.error(e);
477
- }
478
- },
479
-
480
- dbBulk(collectionName, bulk, cb) {
481
- try {
482
- var collection = getOrAddCollection(collectionName), result;
483
- bulk.forEach(i => {
484
- switch (i.op) {
485
- case 'update': {
486
- result = collection.by('_id', i.id);
487
- if (result) {
488
- updateDocument(result, i.update);
489
- collection.update(result);
490
- }
491
- break;
492
- }
493
- case 'insert': {
494
- genId(i.data);
495
- collection.insert(i.data);
496
- break;
497
- }
498
- case 'remove': {
499
- result = collection.by('_id', i.id);
500
- if (result) {
501
- collection.remove(result);
502
- }
503
- break;
504
- }
505
- }
506
- });
507
- cb(null);
508
- }
509
- catch (e) {
510
- cb(e.message);
511
- console.error(e);
512
- }
513
- },
514
-
515
- dbFindEx(collectionName, query, opts, cb) {
516
- try {
517
- recursReplaceNeNull(query);
518
- var collection = getOrAddCollection(collectionName);
519
- var chain = collection.chain().find(query);
520
- if (opts.sort) {
521
- for (var field in opts.sort) {
522
- chain = chain.simplesort(field, opts.sort[field] == -1);
523
- }
524
- }
525
- if (opts.offset) {
526
- chain = chain.offset(opts.offset);
527
- }
528
- if (opts.limit) {
529
- chain = chain.limit(opts.limit);
530
- }
531
- cb(null, chain.data());
532
- }
533
- catch (e) {
534
- cb(e.message);
535
- console.error(e);
536
- }
537
- },
538
-
539
- dbEnvGet(name, cb) {
540
- try {
541
- var item = db.getCollection('env').get(1) || {data: {}};
542
- cb(null, item.data[name]);
543
- }
544
- catch (e) {
545
- cb(e.message);
546
- console.error(e);
547
- }
548
- },
549
-
550
- dbEnvMget(names, cb) {
551
- try {
552
- var item = db.getCollection('env').get(1) || {data: {}};
553
- var result = names.map(name => item.data[name]);
554
- cb(null, result);
555
- }
556
- catch (e) {
557
- cb(e.message);
558
- console.error(e);
559
- }
560
- },
561
-
562
- dbEnvSet(name, value, cb) {
563
- try {
564
- var env = db.getCollection('env');
565
- var values = env.get(1);
566
- if (values) {
567
- values.data[name] = value;
568
- env.update(values);
569
- }
570
- else {
571
- values = {data: {[name]: value}};
572
- env.insert(values);
573
- }
574
- cb && cb(null, value);
575
- }
576
- catch (e) {
577
- cb(e.message);
578
- console.error(e);
579
- }
580
- },
581
-
582
- dbEnvExpire(name, seconds, cb) {
583
- try {
584
- var env = db.getCollection('env');
585
- var expiration = env.get(2);
586
- if (expiration) {
587
- expiration.data[name] = Date.now() + seconds * 1000;
588
- env.update(expiration);
589
- }
590
- else {
591
- expiration = {data: {[name]: Date.now() + seconds * 1000}};
592
- env.insert(expiration);
593
- }
594
- cb && cb(null);
595
- }
596
- catch (e) {
597
- cb(e.message);
598
- console.error(e);
599
- }
600
- },
601
-
602
- dbEnvSetex(name, seconds, value, cb) {
603
- try {
604
- module.exports.dbEnvSet(name, value);
605
- module.exports.dbEnvExpire(name, seconds);
606
- cb(null);
607
- }
608
- catch (e) {
609
- cb(e.message);
610
- console.error(e);
611
- }
612
- },
613
-
614
- dbEnvTtl(name, cb) {
615
- try {
616
- var env = db.getCollection('env');
617
- var expiration = env.get(2);
618
- if (!expiration || !expiration.data[name] || expiration.data[name] < Date.now()) {
619
- cb(null, -1);
620
- return;
621
- }
622
- cb(null, (expiration.data[name] - Date.now()) / 1000);
623
- }
624
- catch (e) {
625
- cb(e.message);
626
- console.error(e);
627
- }
628
- },
629
-
630
- dbEnvDel(name, cb) {
631
- try {
632
- var env = db.getCollection('env');
633
- var values = env.get(1);
634
- if (values && values.data[name]) {
635
- delete values.data[name];
636
- cb(null, 1);
637
- }
638
- else {
639
- cb(null, 0);
640
- }
641
- }
642
- catch (e) {
643
- cb(e.message);
644
- console.error(e);
645
- }
646
- },
647
-
648
- dbEnvHget(name, field, cb) {
649
- try {
650
- var env = db.getCollection('env');
651
- var values = env.get(1);
652
- if (values && values.data && values.data[name]) {
653
- cb(null, values.data[name][field]);
654
- }
655
- else {
656
- cb(null);
657
- }
658
- }
659
- catch (e) {
660
- cb(e.message);
661
- console.error(e);
662
- }
663
- },
664
-
665
- dbEnvHset(name, field, value, cb) {
666
- try {
667
- var env = db.getCollection('env');
668
- var values = env.get(1);
669
- if (values) {
670
- values.data[name] = values.data[name] || {};
671
- values.data[name][field] = value;
672
- env.update(values);
673
- }
674
- else {
675
- values = {data: {[name]: {[field]: value}}};
676
- env.insert(values);
677
- }
678
- cb(null, values.data[name][field]);
679
- }
680
- catch (e) {
681
- cb(e.message);
682
- console.error(e);
683
- }
684
- },
685
-
686
- dbEnvHmget(name, fields, cb) {
687
- try {
688
- var env = db.getCollection('env');
689
- var values = env.get(1) || {data: {}};
690
- values.data[name] = values.data[name] || {};
691
- var result = fields.map(i => values.data[name][i]);
692
- cb(null, result);
693
- }
694
- catch (e) {
695
- cb(e.message);
696
- console.error(e);
697
- }
698
- },
699
-
700
- dbEnvHmset(name, data, cb) {
701
- try {
702
- var env = db.getCollection('env');
703
- var values = env.get(1);
704
- if (values) {
705
- values.data[name] = values.data[name] || {};
706
- _.extend(values.data[name], data);
707
- env.update(values);
708
- }
709
- else {
710
- values = {data: {[name]: data}};
711
- env.insert(values);
712
- }
713
- cb(null, values.data[name]);
714
- }
715
- catch (e) {
716
- cb(e.message);
717
- console.error(e);
718
- }
719
- },
720
-
721
- dbEnvSadd(name, data, cb) {
722
- try {
723
- if(!_.isArray(data)) {
724
- data = [data];
725
- }
726
-
727
- const env = db.getCollection('env');
728
- let values = env.get(1);
729
- if (values) {
730
- values.data[name] = values.data[name] || [];
731
- _.forEach(data, i => {
732
- if(!_.includes(values.data[name], i)) {
733
- values.data[name].push(i);
734
- }
735
- });
736
-
737
- env.update(values);
738
- } else {
739
- values = {data: {[name]: data}};
740
- env.insert(values);
741
- }
742
- cb(null, values.data[name]);
743
- }
744
- catch (e) {
745
- cb(e.message);
746
- console.error(e);
747
- }
748
- },
749
-
750
- dbEnvSmembers(name, cb) {
751
- try {
752
- const env = db.getCollection('env');
753
- const values = env.get(1) || {data: {}};
754
- if(values && values.data && values.data[name]) {
755
- cb(null, values.data[name]);
756
- } else {
757
- cb(null);
758
- }
759
- }
760
- catch (e) {
761
- cb(e.message);
762
- console.error(e);
763
- }
764
- },
765
-
766
- dbResetAllData(cb) {
767
- try {
768
- db.loadJSON(JSON.stringify(require('../db.original')));
769
- cb(null);
770
- }
771
- catch (e) {
772
- cb(e.message);
773
- console.error(e);
774
- }
775
- }
776
- };
1
+ var loki = require('lokijs'),
2
+ q = require('q'),
3
+ fs = require('fs'),
4
+ _ = require('lodash'),
5
+ common = require('@screeps/common'),
6
+ C = require('@screeps/common/lib/constants'),
7
+ config = common.configManager.config;
8
+
9
+ /**
10
+ * @type Loki
11
+ */
12
+ var db;
13
+
14
+ Object.assign(config.storage, {
15
+ dbOptions: {autosave: true, autosaveInterval: 10000},
16
+ getDb() {
17
+ try {
18
+ fs.statSync(process.env.DB_PATH);
19
+ }
20
+ catch (e) {
21
+ fs.writeFileSync(process.env.DB_PATH, '');
22
+ }
23
+ return new loki(process.env.DB_PATH, config.storage.dbOptions);
24
+ },
25
+ loadDb() {
26
+ db = config.storage.getDb();
27
+ return q.ninvoke(db, 'loadDatabase', {})
28
+ .then(upgradeDb);
29
+ }
30
+ });
31
+
32
+ function upgradeDb() {
33
+
34
+ let upgradeInterval;
35
+ if(process.send) {
36
+ upgradeInterval = setInterval(function () {
37
+ process.send('storageUpgrading');
38
+ }, 1000);
39
+ }
40
+
41
+ let env = db.getCollection('env');
42
+ let envData = env.get(1);
43
+ if(!envData) {
44
+ return;
45
+ }
46
+ if(!envData.databaseVersion || envData.databaseVersion < 4) {
47
+ console.log("Upgrading database to version 4");
48
+
49
+ const innerRooms = db.getCollection('rooms').find({_id: {$regex: '^[WE][1-9][NS][1-9]$'}});
50
+ innerRooms.forEach(room => {
51
+ room.bus = false;
52
+ return db.getCollection('rooms').update(room);
53
+ });
54
+
55
+ const depositTypes = [C.RESOURCE_SILICON, C.RESOURCE_METAL, C.RESOURCE_BIOMASS, C.RESOURCE_MIST];
56
+ const busRooms = db.getCollection('rooms').find({$or: [{_id: {$regex: '^[WE]\\d*0'}},{_id: {$regex: '0$'}}]});
57
+ busRooms.forEach(room => {
58
+ const [match, longitude, latitude] = /^[WE](\d+)[NS](\d+)$/.exec(room._id);
59
+ if(match) {
60
+ room.depositType = depositTypes[(longitude+latitude)%4];
61
+ return db.getCollection('rooms').update(room);
62
+ }
63
+ });
64
+ envData.databaseVersion = 4;
65
+ env.update(envData);
66
+ }
67
+
68
+ if(envData.databaseVersion < 5) {
69
+ console.log("Upgrading database to version 5");
70
+
71
+ const energyOnly = function energyOnly(structure) {
72
+ structure.store = { energy: structure.energy };
73
+ structure.storeCapacityResource = {energy: structure.energyCapacity};
74
+ delete structure.energy;
75
+ delete structure.energyCapacity;
76
+ };
77
+
78
+ const storeOnly = function storeOnly(structure) {
79
+ if(!_.isUndefined(structure.energyCapacity)) {
80
+ structure.storeCapacity = structure.energyCapacity;
81
+ delete structure.energyCapacity;
82
+ }
83
+
84
+ structure.store = {};
85
+ C.RESOURCES_ALL.forEach(r => {
86
+ if(!_.isUndefined(structure[r])) {
87
+ structure.store[r] = structure[r];
88
+ delete structure[r];
89
+ }
90
+ });
91
+ };
92
+
93
+ const converters = {
94
+ spawn: energyOnly,
95
+ extension: energyOnly,
96
+ tower: energyOnly,
97
+ link: energyOnly,
98
+ storage: storeOnly,
99
+ terminal: storeOnly,
100
+ container: storeOnly,
101
+ factory: storeOnly,
102
+ creep: storeOnly,
103
+ powerCreep: storeOnly,
104
+ tombstone: storeOnly,
105
+ nuker: function nuker(structure) {
106
+ structure.store = { energy: structure.energy, G: structure.G };
107
+ structure.storeCapacityResource = { energy: structure.energyCapacity, G: structure.GCapacity };
108
+
109
+ delete structure.energy;
110
+ delete structure.energyCapacity;
111
+ delete structure.G;
112
+ delete structure.GCapacity;
113
+ },
114
+ powerSpawn: function powerSpawn(structure) {
115
+ structure.store = { energy: structure.energy, power: structure.power };
116
+ structure.storeCapacityResource = { energy: structure.energyCapacity, power: structure.powerCapacity };
117
+
118
+ delete structure.energy;
119
+ delete structure.energyCapacity;
120
+ delete structure.power;
121
+ delete structure.powerCapacity;
122
+ },
123
+ lab: function lab(structure) {
124
+ structure.store = { energy: structure.energy };
125
+ structure.storeCapacityResource = { energy: structure.energyCapacity };
126
+ if(structure.mineralType && structure.mineralAmount) {
127
+ structure.store[structure.mineralType] = structure.mineralAmount;
128
+ structure.storeCapacityResource[structure.mineralType] = structure.mineralCapacity;
129
+ } else {
130
+ structure.storeCapacity = structure.energyCapacity + structure.mineralCapacity;
131
+ }
132
+
133
+ delete structure.energy;
134
+ delete structure.energyCapacity;
135
+ delete structure.mineralType;
136
+ delete structure.mineralAmount;
137
+ delete structure.mineralCapacity;
138
+ }
139
+ };
140
+
141
+ const powerCreepsCollection = db.getCollection("users.power_creeps");
142
+ if(powerCreepsCollection) {
143
+ const powerCreeps = powerCreepsCollection.find({});
144
+ powerCreeps.forEach(powerCreep => {
145
+ console.log(`powerCreep${powerCreep._id}`);
146
+ converters.powerCreep(powerCreep);
147
+ return powerCreepsCollection.update(powerCreep);
148
+ });
149
+ }
150
+
151
+ const roomObjects = db.getCollection("rooms.objects").find({type: {$in: _.keys(converters)}});
152
+ roomObjects.forEach(object => {
153
+ console.log(`${object.type}#${object._id}`);
154
+ converters[object.type](object);
155
+ return db.getCollection("rooms.objects").update(object);
156
+ });
157
+
158
+ const nowTimestamp = new Date().getTime();
159
+ const orders = db.getCollection("market.orders").find({});
160
+ orders.forEach(order => {
161
+ if(!order.createdTimestamp) {
162
+ console.log(`order#${order._id}`);
163
+ order.createdTimestamp = nowTimestamp;
164
+ return db.getCollection("market.orders").update(order);
165
+ }
166
+ });
167
+ envData.databaseVersion = 5;
168
+ env.update(envData);
169
+ }
170
+
171
+ if(envData.databaseVersion < 6) {
172
+ console.log("Upgrading database to version 6");
173
+
174
+ const roomObjects = db.getCollection("rooms.objects").find({type: 'powerBank'});
175
+ roomObjects.forEach(object => {
176
+ console.log(`${object.type}#${object._id}`);
177
+ object.store = { power: object.power };
178
+ delete object.power;
179
+ return db.getCollection("rooms.objects").update(object);
180
+ });
181
+
182
+ envData.databaseVersion = 6;
183
+ env.update(envData);
184
+ }
185
+
186
+ if(envData.databaseVersion < 7) {
187
+ console.log("Upgrading database to version 7");
188
+
189
+ const user = db.getCollection("users").findOne({_id: "2"});
190
+ user.badge = {
191
+ "type" : {
192
+ "path1" : "m 60.493413,13.745781 -1.122536,7.527255 -23.302365,-6.118884 -24.097204,26.333431 6.412507,0.949878 -5.161481,19.706217 26.301441,24.114728 1.116562,-7.546193 23.350173,6.122868 24.097202,-26.318478 -6.462307,-0.95785 5.16845,-19.699243 z m -1.58271,10.611118 -0.270923,1.821013 C 57.330986,25.69819 55.969864,25.331543 54.570958,25.072546 Z m -8.952409,4.554029 c 11.653612,0 21.055294,9.408134 21.055294,21.069735 0,11.661603 -9.401682,21.068738 -21.055294,21.068738 -11.65361,0 -21.055297,-9.407135 -21.055297,-21.068738 0,-11.661601 9.401687,-21.069735 21.055297,-21.069735 z M 26.634018,40.123069 c -0.262324,0.618965 -0.494865,1.252967 -0.708185,1.895768 l -0.0508,-0.104656 -0.194228,-0.417627 c 0.261245,-0.385697 0.631962,-0.909531 0.953211,-1.373485 z m 47.391601,17.714764 0.115539,0.237219 0.214148,0.462479 c -0.380159,0.55986 -0.886342,1.281124 -1.3835,1.988466 0.400298,-0.870957 0.752837,-1.767746 1.053813,-2.688164 z M 41.364458,73.812322 c 0.694434,0.251619 1.40261,0.471895 2.123558,0.662817 l -2.303841,0.558165 z",
193
+ "path2" : "m 60.857962,24.035953 -6.397566,1.055531 c 6.084137,1.084905 11.78633,4.394548 15.786244,9.746957 5.741405,7.682749 6.465607,17.544704 2.736121,25.67958 1.511089,-2.147013 2.622575,-3.851337 2.622575,-3.851337 l 1.628526,0.241209 c 0.726895,-2.869027 1.004942,-5.843252 0.811775,-8.806053 l 1.185288,-8.634615 -3.768025,-3.072898 -2.908435,-3.21842 c -0.0103,-0.01383 -0.01958,-0.02805 -0.02988,-0.04186 -3.118009,-4.172293 -7.17889,-7.228662 -11.666624,-9.098091 z M 50.001124,37.965163 A 12.020784,12.029027 0 0 0 37.979913,49.994617 12.020784,12.029027 0 0 0 50.001124,62.024074 12.020784,12.029027 0 0 0 62.022337,49.994617 12.020784,12.029027 0 0 0 50.001124,37.965163 Z M 27.019485,39.55693 c -1.481686,2.114179 -2.5658,3.779575 -2.5658,3.779575 l -1.647451,-0.244197 c -0.69707,2.775045 -0.977606,5.64628 -0.81476,8.511019 l -1.22015,8.890775 3.768021,3.072896 3.422394,3.786551 c 2.921501,3.715734 6.608397,6.499915 10.668588,8.29872 l 5.050921,-1.223973 C 38.324728,73.038607 33.383805,69.887984 29.806406,65.100956 28.655972,63.561522 27.71377,61.932905 26.961715,60.249903 L 24.8272,48.359991 c 0.194234,-3.030146 0.935183,-6.015406 2.192285,-8.803061 z"
194
+ },
195
+ "color1" : "#735252",
196
+ "color2" : "#390305",
197
+ "color3" : "#ff0d39",
198
+ "flip" : false
199
+ };
200
+ db.getCollection("users").update(user);
201
+
202
+ envData.databaseVersion = 7;
203
+ env.update(envData);
204
+ }
205
+
206
+ if(envData.databaseVersion < 8) {
207
+ console.log("Upgrading database to version 8");
208
+ const gameTime = parseInt(envData.data[common.storage.env.keys.GAMETIME]);
209
+ const roomObjects = db.getCollection("rooms.objects").find({
210
+ 'type': {$in: ['spawn', 'invaderCore']},
211
+ 'spawning': {$ne: null},
212
+ 'spawning.remainingTime': {$exists: true}});
213
+
214
+ roomObjects.forEach(object => {
215
+ console.log(`${object.type}#${object._id}: ${JSON.stringify(object.spawning, 0, 2)}`);
216
+ object.spawning.spawnTime = gameTime + object.spawning.remainingTime;
217
+ delete object.spawning.remainingTime;
218
+ return db.getCollection("rooms.objects").update(object);
219
+ });
220
+
221
+ envData.databaseVersion = 8;
222
+ env.update(envData);
223
+ }
224
+
225
+ if(envData.databaseVersion < 9) {
226
+ console.log("Upgrading database to version 9");
227
+
228
+ const rooms = db.getCollection("rooms").find({});
229
+
230
+ const activeRoomsNames = [];
231
+ rooms.forEach(room => {
232
+ if(room.active) {
233
+ activeRoomsNames.push(room._id);
234
+ }
235
+ delete room.active;
236
+ return db.getCollection("rooms").update(room);
237
+ });
238
+
239
+ const env = db.getCollection('env');
240
+ let values = env.get(1) || {};
241
+ if (values) {
242
+ values.data[common.storage.env.keys.ACTIVE_ROOMS] = activeRoomsNames;
243
+ env.update(values);
244
+ } else {
245
+ values = {data: {[common.storage.env.keys.ACTIVE_ROOMS]: activeRoomsNames}};
246
+ env.insert(values);
247
+ }
248
+
249
+ envData.databaseVersion = 9;
250
+ env.update(envData);
251
+ }
252
+
253
+ clearInterval(upgradeInterval);
254
+ }
255
+
256
+
257
+ function updateDocument(doc, update) {
258
+ if (update.$set) {
259
+ _.extend(doc, update.$set);
260
+ }
261
+ if (update.$merge) {
262
+ _.merge(doc, update.$merge);
263
+ }
264
+ if (update.$inc) {
265
+ _.forEach(update.$inc, (val, key) => doc[key] = (doc[key] || 0) + val);
266
+ }
267
+ if (update.$unset) {
268
+ for (var j in update.$unset) {
269
+ delete doc[j];
270
+ }
271
+ }
272
+ if(update.$addToSet) {
273
+ for(let i in update.$addToSet) {
274
+ if(!doc[i]) {
275
+ doc[i] = [];
276
+ }
277
+ if(doc[i].indexOf(update.$addToSet[i]) == -1) {
278
+ doc[i].push(update.$addToSet[i]);
279
+ }
280
+ }
281
+ }
282
+ if(update.$pull) {
283
+ for(let i in update.$pull) {
284
+ if(!doc[i]) {
285
+ continue;
286
+ }
287
+ var idx = doc[i].indexOf(update.$pull[i]);
288
+ if(idx != -1) {
289
+ doc[i].splice(idx, 1);
290
+ }
291
+ }
292
+ }
293
+ }
294
+
295
+ setInterval(function envCleanExpired() {
296
+ var env = db.getCollection('env');
297
+ var values = env.get(1);
298
+ var expiration = env.get(2);
299
+ var dirty = false;
300
+ if (expiration) {
301
+ for (var name in expiration.data) {
302
+ if (Date.now() > expiration.data[name]) {
303
+ dirty = true;
304
+ if (values.data[name]) {
305
+ delete values.data[name];
306
+ }
307
+ delete expiration.data[name];
308
+ }
309
+ }
310
+ }
311
+ if (dirty) {
312
+ env.update(values);
313
+ env.update(expiration);
314
+ }
315
+ }, 10000);
316
+
317
+ function getRandomString() {
318
+ for (var val = Math.floor(Math.random() * 0x10000).toString(16); val.length < 4; val = '0' + val);
319
+ return val;
320
+ }
321
+
322
+ function genId(obj) {
323
+ var id = getRandomString() + Date.now().toString(16).slice(4) + getRandomString();
324
+ if (obj && !obj._id) {
325
+ obj._id = id;
326
+ }
327
+ return id;
328
+ }
329
+
330
+ function getOrAddCollection(collectionName) {
331
+ var collection = db.getCollection(collectionName);
332
+ if (!collection) {
333
+ collection = db.addCollection(collectionName);
334
+ }
335
+ collection.ensureUniqueIndex('_id');
336
+ switch(collectionName) {
337
+ case 'rooms.objects': {
338
+ collection.ensureIndex('room');
339
+ collection.ensureIndex('user');
340
+ break;
341
+ }
342
+ case 'rooms.intents': {
343
+ collection.ensureIndex('room');
344
+ break;
345
+ }
346
+ case 'users': {
347
+ collection.ensureIndex('username');
348
+ break;
349
+ }
350
+ case 'rooms.flags': {
351
+ collection.ensureIndex('room');
352
+ collection.ensureIndex('user');
353
+ break;
354
+ }
355
+ case 'rooms.terrain': {
356
+ collection.ensureIndex('room');
357
+ break;
358
+ }
359
+ case 'transactions': {
360
+ collection.ensureIndex('user');
361
+ break;
362
+ }
363
+ case 'users.code': {
364
+ collection.ensureIndex('user');
365
+ break;
366
+ }
367
+ case 'users.console': {
368
+ collection.ensureIndex('user');
369
+ break;
370
+ }
371
+ case 'users.money': {
372
+ collection.ensureIndex('user');
373
+ break;
374
+ }
375
+ case 'users.notifications': {
376
+ collection.ensureIndex('user');
377
+ break;
378
+ }
379
+ case 'users.resources': {
380
+ collection.ensureIndex('user');
381
+ break;
382
+ }
383
+ case 'users.power_creeps': {
384
+ collection.ensureIndex('user');
385
+ break;
386
+ }
387
+ }
388
+ return collection;
389
+ }
390
+
391
+ function recursReplaceNeNull(val) {
392
+ if(!_.isObject(val)) {
393
+ return;
394
+ }
395
+
396
+ for(var i in val) {
397
+ if (_.isEqual(val[i], {$ne: null}) && !val.$and) {
398
+ val.$and = [{[i]: {$ne: null}}, {[i]: {$ne: undefined}}];
399
+ delete val[i];
400
+ }
401
+ if (_.isEqual(val[i], {$eq: null}) && !val.$or) {
402
+ val.$or = [{[i]: {$eq: null}}, {[i]: {$eq: undefined}}];
403
+ delete val[i];
404
+ }
405
+ recursReplaceNeNull(val[i]);
406
+ }
407
+ }
408
+
409
+ module.exports = {
410
+
411
+ dbRequest(collectionName, method, argsArray, cb) {
412
+ try {
413
+ var collection = getOrAddCollection(collectionName);
414
+ if (method == 'insert') {
415
+ if (_.isArray(argsArray[0])) {
416
+ argsArray[0].forEach(genId);
417
+ }
418
+ else {
419
+ genId(argsArray[0]);
420
+ }
421
+ }
422
+
423
+ if(method == 'find' || method == 'findOne' || method == 'count' || method == 'removeWhere') {
424
+ recursReplaceNeNull(argsArray[0]);
425
+ }
426
+
427
+ var result = collection[method].apply(collection, argsArray);
428
+ cb(null, result);
429
+ }
430
+ catch (e) {
431
+ cb(e.message);
432
+ console.error(e);
433
+ }
434
+ },
435
+
436
+ dbUpdate(collectionName, query, update, params, cb) {
437
+ try {
438
+ recursReplaceNeNull(query);
439
+ var collection = getOrAddCollection(collectionName);
440
+ var result = [];
441
+ if (Object.keys(query).length == 1 && query._id && _.isString(query._id)) {
442
+ var found = collection.by('_id', query._id);
443
+ if(found) {
444
+ result = [found];
445
+ }
446
+ }
447
+ else {
448
+ result = collection.find(query);
449
+ }
450
+ if (result.length) {
451
+ result.forEach(doc => {
452
+ updateDocument(doc, update);
453
+ collection.update(doc);
454
+ });
455
+ cb(null, {modified: result.length});
456
+ }
457
+ else if (params && params.upsert) {
458
+ var item = {};
459
+ if (query.$and) {
460
+ query.$and.forEach(i => _.extend(item, i));
461
+ }
462
+ else {
463
+ _.extend(item, query);
464
+ }
465
+ updateDocument(item, update);
466
+ genId(item);
467
+ collection.insert(item);
468
+ cb(null, {inserted: 1});
469
+ }
470
+ else {
471
+ cb(null, {});
472
+ }
473
+ }
474
+ catch (e) {
475
+ cb(e.message);
476
+ console.error(e);
477
+ }
478
+ },
479
+
480
+ dbBulk(collectionName, bulk, cb) {
481
+ try {
482
+ var collection = getOrAddCollection(collectionName), result;
483
+ bulk.forEach(i => {
484
+ switch (i.op) {
485
+ case 'update': {
486
+ result = collection.by('_id', i.id);
487
+ if (result) {
488
+ updateDocument(result, i.update);
489
+ collection.update(result);
490
+ }
491
+ break;
492
+ }
493
+ case 'insert': {
494
+ genId(i.data);
495
+ collection.insert(i.data);
496
+ break;
497
+ }
498
+ case 'remove': {
499
+ result = collection.by('_id', i.id);
500
+ if (result) {
501
+ collection.remove(result);
502
+ }
503
+ break;
504
+ }
505
+ }
506
+ });
507
+ cb(null);
508
+ }
509
+ catch (e) {
510
+ cb(e.message);
511
+ console.error(e);
512
+ }
513
+ },
514
+
515
+ dbFindEx(collectionName, query, opts, cb) {
516
+ try {
517
+ recursReplaceNeNull(query);
518
+ var collection = getOrAddCollection(collectionName);
519
+ var chain = collection.chain().find(query);
520
+ if (opts.sort) {
521
+ for (var field in opts.sort) {
522
+ chain = chain.simplesort(field, opts.sort[field] == -1);
523
+ }
524
+ }
525
+ if (opts.offset) {
526
+ chain = chain.offset(opts.offset);
527
+ }
528
+ if (opts.limit) {
529
+ chain = chain.limit(opts.limit);
530
+ }
531
+ cb(null, chain.data());
532
+ }
533
+ catch (e) {
534
+ cb(e.message);
535
+ console.error(e);
536
+ }
537
+ },
538
+
539
+ dbEnvGet(name, cb) {
540
+ try {
541
+ var item = db.getCollection('env').get(1) || {data: {}};
542
+ cb(null, item.data[name]);
543
+ }
544
+ catch (e) {
545
+ cb(e.message);
546
+ console.error(e);
547
+ }
548
+ },
549
+
550
+ dbEnvMget(names, cb) {
551
+ try {
552
+ var item = db.getCollection('env').get(1) || {data: {}};
553
+ var result = names.map(name => item.data[name]);
554
+ cb(null, result);
555
+ }
556
+ catch (e) {
557
+ cb(e.message);
558
+ console.error(e);
559
+ }
560
+ },
561
+
562
+ dbEnvSet(name, value, cb) {
563
+ try {
564
+ var env = db.getCollection('env');
565
+ var values = env.get(1);
566
+ if (values) {
567
+ values.data[name] = value;
568
+ env.update(values);
569
+ }
570
+ else {
571
+ values = {data: {[name]: value}};
572
+ env.insert(values);
573
+ }
574
+ cb && cb(null, value);
575
+ }
576
+ catch (e) {
577
+ cb(e.message);
578
+ console.error(e);
579
+ }
580
+ },
581
+
582
+ dbEnvExpire(name, seconds, cb) {
583
+ try {
584
+ var env = db.getCollection('env');
585
+ var expiration = env.get(2);
586
+ if (expiration) {
587
+ expiration.data[name] = Date.now() + seconds * 1000;
588
+ env.update(expiration);
589
+ }
590
+ else {
591
+ expiration = {data: {[name]: Date.now() + seconds * 1000}};
592
+ env.insert(expiration);
593
+ }
594
+ cb && cb(null);
595
+ }
596
+ catch (e) {
597
+ cb(e.message);
598
+ console.error(e);
599
+ }
600
+ },
601
+
602
+ dbEnvSetex(name, seconds, value, cb) {
603
+ try {
604
+ module.exports.dbEnvSet(name, value);
605
+ module.exports.dbEnvExpire(name, seconds);
606
+ cb(null);
607
+ }
608
+ catch (e) {
609
+ cb(e.message);
610
+ console.error(e);
611
+ }
612
+ },
613
+
614
+ dbEnvTtl(name, cb) {
615
+ try {
616
+ var env = db.getCollection('env');
617
+ var expiration = env.get(2);
618
+ if (!expiration || !expiration.data[name] || expiration.data[name] < Date.now()) {
619
+ cb(null, -1);
620
+ return;
621
+ }
622
+ cb(null, (expiration.data[name] - Date.now()) / 1000);
623
+ }
624
+ catch (e) {
625
+ cb(e.message);
626
+ console.error(e);
627
+ }
628
+ },
629
+
630
+ dbEnvDel(name, cb) {
631
+ try {
632
+ var env = db.getCollection('env');
633
+ var values = env.get(1);
634
+ if (values && values.data[name]) {
635
+ delete values.data[name];
636
+ cb(null, 1);
637
+ }
638
+ else {
639
+ cb(null, 0);
640
+ }
641
+ }
642
+ catch (e) {
643
+ cb(e.message);
644
+ console.error(e);
645
+ }
646
+ },
647
+
648
+ dbEnvHget(name, field, cb) {
649
+ try {
650
+ var env = db.getCollection('env');
651
+ var values = env.get(1);
652
+ if (values && values.data && values.data[name]) {
653
+ cb(null, values.data[name][field]);
654
+ }
655
+ else {
656
+ cb(null);
657
+ }
658
+ }
659
+ catch (e) {
660
+ cb(e.message);
661
+ console.error(e);
662
+ }
663
+ },
664
+
665
+ dbEnvHset(name, field, value, cb) {
666
+ try {
667
+ var env = db.getCollection('env');
668
+ var values = env.get(1);
669
+ if (values) {
670
+ values.data[name] = values.data[name] || {};
671
+ values.data[name][field] = value;
672
+ env.update(values);
673
+ }
674
+ else {
675
+ values = {data: {[name]: {[field]: value}}};
676
+ env.insert(values);
677
+ }
678
+ cb(null, values.data[name][field]);
679
+ }
680
+ catch (e) {
681
+ cb(e.message);
682
+ console.error(e);
683
+ }
684
+ },
685
+
686
+ dbEnvHmget(name, fields, cb) {
687
+ try {
688
+ var env = db.getCollection('env');
689
+ var values = env.get(1) || {data: {}};
690
+ values.data[name] = values.data[name] || {};
691
+ var result = fields.map(i => values.data[name][i]);
692
+ cb(null, result);
693
+ }
694
+ catch (e) {
695
+ cb(e.message);
696
+ console.error(e);
697
+ }
698
+ },
699
+
700
+ dbEnvHmset(name, data, cb) {
701
+ try {
702
+ var env = db.getCollection('env');
703
+ var values = env.get(1);
704
+ if (values) {
705
+ values.data[name] = values.data[name] || {};
706
+ _.extend(values.data[name], data);
707
+ env.update(values);
708
+ }
709
+ else {
710
+ values = {data: {[name]: data}};
711
+ env.insert(values);
712
+ }
713
+ cb(null, values.data[name]);
714
+ }
715
+ catch (e) {
716
+ cb(e.message);
717
+ console.error(e);
718
+ }
719
+ },
720
+
721
+ dbEnvSadd(name, data, cb) {
722
+ try {
723
+ if(!_.isArray(data)) {
724
+ data = [data];
725
+ }
726
+
727
+ const env = db.getCollection('env');
728
+ let values = env.get(1);
729
+ if (values) {
730
+ values.data[name] = values.data[name] || [];
731
+ _.forEach(data, i => {
732
+ if(!_.includes(values.data[name], i)) {
733
+ values.data[name].push(i);
734
+ }
735
+ });
736
+
737
+ env.update(values);
738
+ } else {
739
+ values = {data: {[name]: data}};
740
+ env.insert(values);
741
+ }
742
+ cb(null, values.data[name]);
743
+ }
744
+ catch (e) {
745
+ cb(e.message);
746
+ console.error(e);
747
+ }
748
+ },
749
+
750
+ dbEnvSmembers(name, cb) {
751
+ try {
752
+ const env = db.getCollection('env');
753
+ const values = env.get(1) || {data: {}};
754
+ if(values && values.data && values.data[name]) {
755
+ cb(null, values.data[name]);
756
+ } else {
757
+ cb(null);
758
+ }
759
+ }
760
+ catch (e) {
761
+ cb(e.message);
762
+ console.error(e);
763
+ }
764
+ },
765
+
766
+ dbResetAllData(cb) {
767
+ try {
768
+ db.loadJSON(JSON.stringify(require('../db.original')));
769
+ cb(null);
770
+ }
771
+ catch (e) {
772
+ cb(e.message);
773
+ console.error(e);
774
+ }
775
+ }
776
+ };