hyperlog-index
Version:
forking indexes for hyperlog
110 lines (98 loc) • 2.95 kB
JavaScript
var through = require('through2')
var inherits = require('inherits')
var EventEmitter = require('events').EventEmitter
module.exports = Ix
inherits(Ix, EventEmitter)
var SEQ = 'seq'
function Ix (opts) {
if (!(this instanceof Ix)) return new Ix(opts)
var self = this
EventEmitter.call(self)
self.setMaxListeners(Infinity)
self._change = -1
self._latest = 0
self._live = false
self._pending = 0
self._paused = false
self.map = opts.map
self.log = opts.log
self.db = opts.db
self.log.on('preadd', function (node) {
self._pending++
})
self.log.on('add', function (node) {
self._latest = Math.max(node.change, self._latest)
if (--self._pending === 0) self.emit('_ready')
})
self.log.on('reject', function (node) {
if (--self._pending === 0) self.emit('_ready')
})
self.db.get(SEQ, function (err, value) {
self.log.ready(function f () {
if (self._paused) {
return self.once('resume', function () { self.log.ready(f) })
}
self._change = Number(value || 0)
var r = self.log.createReadStream({ since: value })
r.on('error', function (err) { self.emit('error', err) })
var t = through.obj(write, end)
t.on('error', function (err) { self.emit('error', err) })
r.pipe(t)
})
})
function write (row, enc, next) {
if (self._paused) {
return self.once('resume', function () { write(row, enc, next) })
}
self._latest = Math.max(row.change, self._latest)
self.emit('row', row)
self.map(row, function (err) {
if (err) return next(err)
self.db.put(SEQ, String(row.change), function (err) {
if (err) return next(err)
self._change = row.change
self.emit('change', self._change)
next()
})
})
}
function end () {
if (self._paused) return self.once('resume', end)
self._live = true
self._latest = self._change
self.emit('live')
self.log.ready(function f () {
if (self._paused) {
return self.once('resume', function () { self.log.ready(f) })
}
var r = self.log.createReadStream({
live: true,
since: self._change
})
r.pipe(through.obj(write))
r.on('error', function (err) { self.emit('error', err) })
})
}
}
Ix.prototype.ready = function (fn) {
var self = this
if (self._paused) {
self.once('resume', function () { self.ready(fn) })
} else if (!self._live) {
self.once('live', function () { self.ready(fn) })
} else if (self._pending > 0) {
self.once('_ready', function () { self.ready(fn) })
} else if (self._latest !== self._change) {
self.once('change', function () { self.ready(fn) })
} else process.nextTick(fn)
}
Ix.prototype.pause = function () {
var p = this._paused
this._paused = true
if (!p) this.emit('pause')
}
Ix.prototype.resume = function () {
var p = this._paused
this._paused = false
if (p) this.emit('resume')
}