Integrate new minicap along with a moderate rewrite. What's currently missing is recovering from socket death.

This commit is contained in:
Simo Kinnunen
2015-04-15 18:55:46 +09:00
parent 6fe4f8ae1b
commit 95e9dd0b82
43 changed files with 1138 additions and 438 deletions

View File

@@ -0,0 +1,108 @@
var Promise = require('bluebird')
module.exports.read = function parseBanner(out) {
var tryRead
return new Promise(function(resolve, reject) {
var readBannerBytes = 0
var needBannerBytes = 2
var banner = out.banner = {
version: 0
, length: 0
, pid: 0
, realWidth: 0
, realHeight: 0
, virtualWidth: 0
, virtualHeight: 0
, orientation: 0
, quirks: 0
}
tryRead = function() {
for (var chunk; (chunk = out.read(needBannerBytes - readBannerBytes));) {
for (var cursor = 0, len = chunk.length; cursor < len;) {
if (readBannerBytes < needBannerBytes) {
switch (readBannerBytes) {
case 0:
// version
banner.version = chunk[cursor]
break
case 1:
// length
banner.length = needBannerBytes = chunk[cursor]
break
case 2:
case 3:
case 4:
case 5:
// pid
banner.pid +=
(chunk[cursor] << ((readBannerBytes - 2) * 8)) >>> 0
break
case 6:
case 7:
case 8:
case 9:
// real width
banner.realWidth +=
(chunk[cursor] << ((readBannerBytes - 6) * 8)) >>> 0
break
case 10:
case 11:
case 12:
case 13:
// real height
banner.realHeight +=
(chunk[cursor] << ((readBannerBytes - 10) * 8)) >>> 0
break
case 14:
case 15:
case 16:
case 17:
// virtual width
banner.virtualWidth +=
(chunk[cursor] << ((readBannerBytes - 14) * 8)) >>> 0
break
case 18:
case 19:
case 20:
case 21:
// virtual height
banner.virtualHeight +=
(chunk[cursor] << ((readBannerBytes - 18) * 8)) >>> 0
break
case 22:
// orientation
banner.orientation += chunk[cursor] * 90
break
case 23:
// quirks
banner.quirks = chunk[cursor]
break
}
cursor += 1
readBannerBytes += 1
if (readBannerBytes === needBannerBytes) {
return resolve(banner)
}
}
else {
reject(new Error(
'Supposedly impossible error parsing banner'
))
}
}
}
}
tryRead()
out.on('readable', tryRead)
})
.finally(function() {
out.removeListener('readable', tryRead)
})
}

View File

@@ -0,0 +1,40 @@
var util = require('util')
var EventEmitter = require('eventemitter3').EventEmitter
function BroadcastSet() {
this.set = Object.create(null)
this.count = 0
}
util.inherits(BroadcastSet, EventEmitter)
BroadcastSet.prototype.insert = function(id, ws) {
if (!(id in this.set)) {
this.set[id] = ws
this.count += 1
this.emit('insert', id)
if (this.count === 1) {
this.emit('nonempty')
}
}
}
BroadcastSet.prototype.remove = function(id) {
if (id in this.set) {
delete this.set[id]
this.count -= 1
this.emit('remove', id)
if (this.count === 0) {
this.emit('empty')
}
}
}
BroadcastSet.prototype.each = function(fn) {
return Object.keys(this.set).forEach(function(id) {
return fn(this.set[id])
}, this)
}
module.exports = BroadcastSet

View File

@@ -0,0 +1,22 @@
var util = require('util')
function FrameConfig(real, virtual) {
this.realWidth = real.width
this.realHeight = real.height
this.virtualWidth = virtual.width
this.virtualHeight = virtual.height
this.rotation = virtual.rotation
}
FrameConfig.prototype.toString = function() {
return util.format(
'%dx%d@%dx%d/%d'
, this.realWidth
, this.realHeight
, this.virtualWidth
, this.virtualHeight
, this.rotation
)
}
module.exports = FrameConfig

View File

@@ -0,0 +1,56 @@
var stream = require('stream')
var util = require('util')
function FrameParser() {
this.readFrameBytes = 0
this.frameBodyLength = 0
this.frameBody = new Buffer(0)
stream.Transform.call(this)
}
util.inherits(FrameParser, stream.Transform)
FrameParser.prototype._transform = function(chunk, encoding, done) {
var cursor, len, bytesLeft
for (cursor = 0, len = chunk.length; cursor < len;) {
if (this.readFrameBytes < 4) {
this.frameBodyLength +=
(chunk[cursor] << (this.readFrameBytes * 8)) >>> 0
cursor += 1
this.readFrameBytes += 1
}
else {
bytesLeft = len - cursor
if (bytesLeft >= this.frameBodyLength) {
this.frameBody = Buffer.concat([
this.frameBody
, chunk.slice(cursor, cursor + this.frameBodyLength)
])
this.push(this.frameBody)
cursor += this.frameBodyLength
this.frameBodyLength = this.readFrameBytes = 0
this.frameBody = new Buffer(0)
}
else {
// @todo Consider/benchmark continuation frames to prevent
// potential Buffer thrashing.
this.frameBody = Buffer.concat([
this.frameBody
, chunk.slice(cursor, len)
])
this.frameBodyLength -= bytesLeft
this.readFrameBytes += bytesLeft
cursor = len
}
}
}
return done()
}
module.exports = FrameParser

View File

@@ -0,0 +1,26 @@
function StateQueue() {
this.queue = []
}
StateQueue.prototype.next = function() {
return this.queue.shift()
}
StateQueue.prototype.push = function(state) {
var found = false
// Not super efficient, but this shouldn't be running all the time anyway.
for (var i = 0, l = this.queue.length; i < l; ++i) {
if (this.queue[i] === state) {
this.queue.splice(i + 1)
found = true
break
}
}
if (!found) {
this.queue.push(state)
}
}
module.exports = StateQueue