-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcounter.js
98 lines (88 loc) · 2.94 KB
/
counter.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
var mongodb = require('mongodb');
module.exports = counter;
module.exports.createCounters = createCounters;
function createCounters(options) {
var counters = counter(options);
return function (name) {
var uniqueIdPool = [], callbacks = [];
return {
increment: counters.increment.bind(null, name),
decrement: counters.decrement.bind(null, name),
set: counters.set.bind(null, name),
get: counters.get.bind(null, name),
getNextUniqueId: counters.getNextUniqueId.bind(null, name, uniqueIdPool, callbacks)
};
}
}
function counter(options) {
var collection;
return {
increment: increment,
decrement: decrement,
get: get,
getNextUniqueId: getNextUniqueId,
set: set
};
function getNextUniqueId(counterName, uniqueIdPool, callbacks, done) {
if (uniqueIdPool.length) return done(null, uniqueIdPool.pop());
callbacks.push(done);
if (callbacks.length == 1) {
increment(counterName, 100, function (err, last) {
var notifies = callbacks.slice();
callbacks.length = 0;
if (!err) for(var jj = 0; jj < 100; jj ++) uniqueIdPool.push(last - jj)
for (var kk = 0; kk < notifies.length; kk ++) {
if (err) notifies[kk](err);
else getNextUniqueId(counterName, uniqueIdPool, callbacks, notifies[kk]);
}
});
}
}
function increment(counterName, by, done) {
if (typeof(by) == 'function' || typeof(by) == 'undefined') { done = by; by = 1; }
getCollection(function (err, collection) {
if (err) return done(err);
collection.findAndModify(
{_id: counterName},
{_id: 1},
{$inc: {seq: by}},
{upsert: true, new: true},
function (err, doc) { return done && done(err, doc && doc.seq); }
);
});
}
function decrement(counterName, by, done) {
if (typeof(by) == 'function' || typeof(by) == 'undefined') { done = by; by = 1; }
return increment(counterName, -by, done);
}
function get(counterName, done) {
getCollection(function (err, collection) {
if (err) return done(err);
collection.findOne({_id: counterName}, function (err, val) { return done(err, val && val.seq); });
});
}
function set(counterName, seq, done) {
getCollection(function (err, collection) {
if (err) return done(err);
collection.findAndModify(
{_id: counterName},
{_id: 1},
{$set: {seq: seq}},
{new: true, upsert: true},
function (err, doc) { return done && done(err, doc && doc.seq); }
);
});
}
function getCollection(done) {
if (collection) return done(null, collection);
if (options.collection) {
collection = options.collection;
return done(null, collection);
}
mongodb.MongoClient.connect(options.mongoUrl, function (err, _db) {
if (err) return done(err);
collection = _db.collection(options.collectionName || 'counters');
return done(null, collection);
});
}
}