UNPKG

dns-discovery

Version:

Discovery peers in a distributed system using regular dns and multicast dns.

145 lines (116 loc) 3.29 kB
var set = require('unordered-set') var lru = require('lru') module.exports = Store function Store (opts) { if (!(this instanceof Store)) return new Store(opts) if (!opts) opts = {} this.maxValues = opts.values || Infinity this.maxEntries = opts.records || Infinity this.entries = lru(this.maxEntries) this.limit = opts.limit || 10000 this.ttl = (opts.ttl || 0) * 1000 this.used = 0 } Store.prototype.get = function (name, max) { var entry = this.entries.get(name) var result = [] if (!entry) return result if (!max) max = entry.values.length while (result.length < max) { var i = result.length if (i >= entry.values.length) return result var missing = entry.values.length - i var next = i + (Math.random() * missing) | 0 var val = entry.values[next] if (this.ttl && (Date.now() - val._modified) > this.ttl) { set.remove(entry.values, val) this.used-- if (!entry.values.length) { this.entries.remove(name) return result } } else { set.swap(entry.values, entry.values[i], val) result.push(val) } } return result } Store.prototype.remove = function (name, port, host) { var address = host + ':' + port var entry = this.entries.peek(name) if (!entry) return var peer = entry.byAddr.remove(address) if (!peer) return set.remove(entry.values, peer) this.used-- if (!entry.values.length) this.entries.remove(name) } Store.prototype.add = function (name, port, host) { var peer = new Peer(port, host) if (this.used >= this.limit) this.evict() var entry = this.entries.get(name) if (!entry) { entry = this.entries.set(name, new Record(name, this.maxValues)) } var prev = entry.byAddr.get(peer.address) var old = !!prev if (!old) { prev = peer set.add(entry.values, peer) entry.byAddr.set(peer.address, peer) this.used++ } if (this.ttl) prev._modified = Date.now() return !old } Store.prototype.evict = function () { var oldest = this.entries.tail && this.entries.peek(this.entries.tail) if (!oldest) return var oldestPeer = oldest.byAddr.tail && oldest.byAddr.remove(oldest.byAddr.tail) if (!oldestPeer) return set.remove(oldest.values, oldestPeer) this.used-- if (!oldest.values.length) { this.entries.remove(this.entries.tail) } } Store.prototype.toJSON = function () { var entries = [] var keys = Object.keys(this.entries.cache) for (var i = 0; i < keys.length; i++) { entries.push({ name: keys[i], records: this.entries.peek(keys[i]).values }) } return entries } Store.prototype.getTopKeyStats = function (n) { n = n || 10 var entries = [] var keys = Object.keys(this.entries.cache) for (var i = 0; i < keys.length; i++) { entries.push({ name: keys[i], numRecords: this.entries.peek(keys[i]).values.length }) } entries.sort(function (a, b) { return b.numRecords - a.numRecords }) return entries.slice(0, n) } function Peer (port, host) { this.host = host || '127.0.0.1' this.port = port this.address = this.host + ':' + this.port this.buffer = null this._modified = 0 this._index = 0 } function Record (name, limit) { this.name = name this.values = [] this.byAddr = lru(limit || Infinity) }