hyperdeck-js-lib
Advanced tools
Comparing version 1.2.0 to 1.3.0
@@ -6,3 +6,3 @@ var jshint = require('gulp-jshint'); | ||
gulp.task('lint', function() { | ||
return gulp.src(['src/*.js', 'src/**/*.js']) | ||
return gulp.src(['src/*.js', 'src/**/*.js', 'test/*.js', 'test/**/*.js']) | ||
.pipe(jshint()) | ||
@@ -9,0 +9,0 @@ .pipe(jshint.reporter('jshint-stylish')) |
{ | ||
"name": "hyperdeck-js-lib", | ||
"version": "1.2.0", | ||
"version": "1.3.0", | ||
"description": "A javascript library for communication with the Blackmagic Hyperdeck.", | ||
@@ -5,0 +5,0 @@ "main": "src/index.js", |
@@ -6,5 +6,5 @@ /*jshint latedef: false */ | ||
var events = require('events'); | ||
var Logger = require("../logger"); | ||
var Logger = require('../logger'); | ||
var logger = Logger.get("hyperdeck.HyperdeckCore"); | ||
var logger = Logger.get('hyperdeck.HyperdeckCore'); | ||
@@ -23,3 +23,3 @@ /** | ||
if (!state.connected) { | ||
publicNotifier.emit("connectionLost"); | ||
publicNotifier.emit('connectionLost'); | ||
} | ||
@@ -30,8 +30,8 @@ } | ||
function removeListeners() { | ||
responseHandler.getNotifier().removeListener("asynchronousResponse", handler); | ||
responseHandler.getNotifier().removeListener("connectionStateChange", handleConnectionLoss); | ||
responseHandler.getNotifier().removeListener('asynchronousResponse', handler); | ||
responseHandler.getNotifier().removeListener('connectionStateChange', handleConnectionLoss); | ||
} | ||
function handler(response) { | ||
if (response.code === 500 && response.text === "connection info") { | ||
if (response.code === 500 && response.text === 'connection info') { | ||
removeListeners(); | ||
@@ -41,3 +41,3 @@ connected = true; | ||
registerAsyncResponseListener(); | ||
notifier.emit("connectionStateChange", {connected: true}); | ||
notifier.emit('connectionStateChange', {connected: true}); | ||
pingTimerId = setInterval(ping, 10000); | ||
@@ -48,3 +48,3 @@ // a request might have been queued whilst the connection | ||
} | ||
else if (response.code === 120 && response.text === "connection rejected") { | ||
else if (response.code === 120 && response.text === 'connection rejected') { | ||
removeListeners(); | ||
@@ -55,3 +55,3 @@ // close the socket, which should then result in onConnectionLost() being called | ||
else { | ||
throw new Error("Was expecting an async response stating whether the connection was succesful."); | ||
throw new Error('Was expecting an async response stating whether the connection was succesful.'); | ||
} | ||
@@ -62,15 +62,15 @@ } | ||
if (state.connected) { | ||
throw new Error("Invalid connection state."); | ||
throw new Error('Invalid connection state.'); | ||
} | ||
removeListeners(); | ||
} | ||
responseHandler.getNotifier().on("asynchronousResponse", handler); | ||
responseHandler.getNotifier().on("connectionStateChange", handleConnectionLoss); | ||
responseHandler.getNotifier().on('asynchronousResponse', handler); | ||
responseHandler.getNotifier().on('connectionStateChange', handleConnectionLoss); | ||
} | ||
function registerAsyncResponseListener() { | ||
responseHandler.getNotifier().on("asynchronousResponse", function(data) { | ||
responseHandler.getNotifier().on('asynchronousResponse', function(data) { | ||
// the developer will listen on the notifier for asynchronous events | ||
// fired from the hyperdeck | ||
publicNotifier.emit("asynchronousEvent", data); | ||
publicNotifier.emit('asynchronousEvent', data); | ||
}); | ||
@@ -82,3 +82,3 @@ } | ||
if (!socketConnected && !connecting) { | ||
throw "Must be connected (or connecting) in order to loose the connection!"; | ||
throw 'Must be connected (or connecting) in order to loose the connection!'; | ||
} | ||
@@ -92,3 +92,3 @@ connecting = false; | ||
} | ||
notifier.emit("connectionStateChange", {connected: false}); | ||
notifier.emit('connectionStateChange', {connected: false}); | ||
performNextRequest(); | ||
@@ -99,3 +99,3 @@ } | ||
// requests must not contain new lines | ||
return request.indexOf("\r") === -1 && request.indexOf("\n") === -1; | ||
return request.indexOf('\r') === -1 && request.indexOf('\n') === -1; | ||
} | ||
@@ -105,3 +105,3 @@ | ||
function write(data) { | ||
logger.debug("Writing to socket.", data); | ||
logger.debug('Writing to socket.', data); | ||
client.write(data); | ||
@@ -111,3 +111,3 @@ } | ||
function ping() { | ||
self.makeRequest("ping"); | ||
self.makeRequest('ping'); | ||
} | ||
@@ -140,4 +140,4 @@ | ||
listenersRegistered = true; | ||
responseHandler.getNotifier().on("synchronousResponse", handleResponse); | ||
notifier.on("connectionStateChange", handleConnectionLoss); | ||
responseHandler.getNotifier().on('synchronousResponse', handleResponse); | ||
notifier.on('connectionStateChange', handleConnectionLoss); | ||
} | ||
@@ -147,4 +147,4 @@ | ||
if (listenersRegistered) { | ||
responseHandler.getNotifier().removeListener("synchronousResponse", handleResponse); | ||
notifier.removeListener("connectionStateChange", handleConnectionLoss); | ||
responseHandler.getNotifier().removeListener('synchronousResponse', handleResponse); | ||
notifier.removeListener('connectionStateChange', handleConnectionLoss); | ||
} | ||
@@ -154,3 +154,3 @@ } | ||
function handleResponse(response) { | ||
logger.debug("Got response. Resolving provided promise with response."); | ||
logger.debug('Got response. Resolving provided promise with response.'); | ||
removeListeners(); | ||
@@ -170,3 +170,3 @@ if (response.success) { | ||
if (state.connected) { | ||
throw new Error("Invalid connection state."); | ||
throw new Error('Invalid connection state.'); | ||
} | ||
@@ -177,3 +177,3 @@ onConnectionLost(); | ||
function onConnectionLost() { | ||
logger.debug("Connection lost. Rejecting provided promise to signify failure."); | ||
logger.debug('Connection lost. Rejecting provided promise to signify failure.'); | ||
removeListeners(); | ||
@@ -188,3 +188,3 @@ // null to signify connection loss | ||
// don't even attempt the request | ||
logger.debug("Not attempting request because connection lost."); | ||
logger.debug('Not attempting request because connection lost.'); | ||
onConnectionLost(); | ||
@@ -195,6 +195,6 @@ } | ||
// make the request | ||
// either the "synchronousResponse" or "connectionLost" event should be | ||
// either the 'synchronousResponse' or 'connectionLost' event should be | ||
// fired at some point in the future. | ||
logger.info("Making request.", request); | ||
write(request+"\n"); | ||
logger.info('Making request.', request); | ||
write(request+'\n'); | ||
} | ||
@@ -216,3 +216,3 @@ } | ||
var pingTimerId = null; | ||
notifier.on("connectionStateChange", onConnectionStateChange); | ||
notifier.on('connectionStateChange', onConnectionStateChange); | ||
@@ -228,9 +228,9 @@ var client = net.connect({ | ||
}); | ||
client.setEncoding("utf8"); | ||
client.on("error", function(e) { | ||
logger.warn("Socket error.", e); | ||
client.setEncoding('utf8'); | ||
client.on('error', function(e) { | ||
logger.warn('Socket error.', e); | ||
}); | ||
// when the connection closes handle this | ||
// this should also happen if the connection fails at some point | ||
client.on("close", onConnectionLost); | ||
client.on('close', onConnectionLost); | ||
var responseHandler = new ResponseHandler(client); | ||
@@ -251,3 +251,3 @@ | ||
if (!isValidRequest(requestToProcess)) { | ||
throw new Error("Invalid request."); | ||
throw new Error('Invalid request.'); | ||
} | ||
@@ -263,3 +263,3 @@ | ||
pendingRequests.push(requestToProcess); | ||
logger.info("Queueing request.", requestToProcess); | ||
logger.info('Queueing request.', requestToProcess); | ||
performNextRequest(); | ||
@@ -282,3 +282,3 @@ return completionPromise; | ||
else { | ||
notifier.once("connectionStateChange", function(state) { | ||
notifier.once('connectionStateChange', function(state) { | ||
if (state.connected) { | ||
@@ -305,5 +305,5 @@ resolve(); | ||
* Get the notifier. | ||
* Events with id "asynchronousEvent" will be emitted from this for asynchronous events | ||
* Events with id 'asynchronousEvent' will be emitted from this for asynchronous events | ||
* from the hyperdeck. | ||
* "connectionLost" is emitted if the hyperdeck connection is lost (or fails to connect) | ||
* 'connectionLost' is emitted if the hyperdeck connection is lost (or fails to connect) | ||
*/ | ||
@@ -310,0 +310,0 @@ this.getNotifier = function() { |
var util = require('util'); | ||
var HyperdeckCore = require("./hyperdeck-core.js"); | ||
var HyperdeckCore = require('./hyperdeck-core.js'); | ||
@@ -9,6 +9,6 @@ var Hyperdeck = function(ip) { | ||
this.makeRequest("notify: remote: true"); | ||
this.makeRequest("notify: transport: true"); | ||
this.makeRequest("notify: slot: true"); | ||
this.makeRequest("notify: configuration: true"); | ||
this.makeRequest('notify: remote: true'); | ||
this.makeRequest('notify: transport: true'); | ||
this.makeRequest('notify: slot: true'); | ||
this.makeRequest('notify: configuration: true'); | ||
@@ -19,8 +19,8 @@ // add Easy Access commands | ||
if (Math.abs(speed) <= 1600) { | ||
commandString = "play: speed: " + speed; | ||
commandString = 'play: speed: ' + speed; | ||
} else { | ||
if (speed) { | ||
throw new Error("Speed value invalid or out of range"); | ||
throw new Error('Speed value invalid or out of range'); | ||
} else { | ||
commandString = "play"; | ||
commandString = 'play'; | ||
} | ||
@@ -32,11 +32,11 @@ } | ||
this.stop = function() { | ||
return this.makeRequest("stop"); | ||
return this.makeRequest('stop'); | ||
}; | ||
this.record = function() { | ||
return this.makeRequest("record"); | ||
return this.makeRequest('record'); | ||
}; | ||
this.goTo = function(timecode) { | ||
return this.makeRequest("goto: timecode: " + timecode); | ||
return this.makeRequest('goto: timecode: ' + timecode); | ||
}; | ||
@@ -46,8 +46,8 @@ | ||
if (id === 0 || id === 1 || id === 2){ //TO DO find if it's 0-1 or 1-2 | ||
return this.makeRequest("slot info: slot id: " + id); | ||
return this.makeRequest('slot info: slot id: ' + id); | ||
} else{ | ||
if (!id){ | ||
return this.makeRequest("slot info"); | ||
return this.makeRequest('slot info'); | ||
} | ||
throw new Error("Slot ID Value out of range"); | ||
throw new Error('Slot ID Value out of range'); | ||
} | ||
@@ -57,20 +57,20 @@ }; | ||
this.transportInfo = function(){ | ||
return this.makeRequest("transport info"); | ||
return this.makeRequest('transport info'); | ||
}; | ||
this.clipsGet = function(){ | ||
return this.makeRequest("clips get"); | ||
return this.makeRequest('clips get'); | ||
}; | ||
this.slotSelect = function(id){ | ||
return this.makeRequest("slot select: slot id: " + id); | ||
return this.makeRequest('slot select: slot id: ' + id); | ||
}; | ||
this.format = function(format){ | ||
return this.makeRequest("format: prepare: " + format).then(function(response){ | ||
if (response.code !== 216 || response.text !== "format ready" || !response.rawData) { | ||
throw new Error("Unexpected response."); | ||
return this.makeRequest('format: prepare: ' + format).then(function(response){ | ||
if (response.code !== 216 || response.text !== 'format ready' || !response.rawData) { | ||
throw new Error('Unexpected response.'); | ||
} | ||
var token = response.rawData; | ||
return this.makeRequest("format: confirm: " + token); | ||
return this.makeRequest('format: confirm: ' + token); | ||
}); | ||
@@ -77,0 +77,0 @@ }; |
@@ -0,8 +1,11 @@ | ||
var FIRST_LINE_REGEX = /^([0-9]+) (.+?)(\:?)$/; | ||
var PARAMS_REGEX = /^(.*)\: (.*)$/; | ||
/** | ||
* Converts the data to a Object. | ||
* So the hyperdeck class can do things nicely with it. | ||
* @return dataObject, The data in a nice object. This will contain "code", "text" and "params" keys, | ||
* @return dataObject, The data in a nice object. This will contain 'code', 'text' and 'params' keys, | ||
* (if there are parameters) where params is an object. | ||
**/ | ||
function convertDataToObject(data) { | ||
function convertDataToObject(lines) { | ||
var dataObject = { | ||
@@ -13,5 +16,4 @@ code: null, | ||
var lines = data.split("\r\n"); //Splits the data on a new line. | ||
var firstLine = lines.shift(); // should contain {Response code} {Response text} | ||
var firstLineMatches = /^([0-9]+) (.+?)(\:?)$/.exec(firstLine); | ||
var firstLineMatches = FIRST_LINE_REGEX.exec(firstLine); | ||
var code = parseInt(firstLineMatches[1]); | ||
@@ -24,6 +26,6 @@ var text = firstLineMatches[2]; | ||
// provide the raw data in addition to attempting to parse the response into params | ||
dataObject.rawData = lines.slice(0, lines.length-2).join("\r\n"); | ||
dataObject.rawData = lines.join('\r\n'); | ||
} | ||
if (firstLineMatches[3] === ":") { | ||
if (firstLineMatches[3] === ':') { | ||
// the response should have params on the next lines | ||
@@ -35,3 +37,3 @@ // (although sometimes it doesn't because of the responses (e.g 'commands'), do not return | ||
lines.forEach(function(line) { | ||
var lineData = /^(.*)\: (.*)$/.exec(line); | ||
var lineData = PARAMS_REGEX.exec(line); | ||
//First element in array is the whole string. | ||
@@ -50,20 +52,20 @@ if(lineData) { | ||
*/ | ||
function failureResponseCode(data) { | ||
function failureResponseCode(lines) { | ||
return { | ||
type: "synchronousFailure", | ||
data: convertDataToObject(data) | ||
type: 'synchronousFailure', | ||
data: convertDataToObject(lines) | ||
}; | ||
} | ||
function successResponseCode(data) { | ||
function successResponseCode(lines) { | ||
return { | ||
type: "synchronousSuccess", | ||
data: convertDataToObject(data) | ||
type: 'synchronousSuccess', | ||
data: convertDataToObject(lines) | ||
}; | ||
} | ||
function asynchornousResponseCode(data) { | ||
function asynchornousResponseCode(lines) { | ||
return { | ||
type: "asynchronous", | ||
data: convertDataToObject(data) | ||
type: 'asynchronous', | ||
data: convertDataToObject(lines) | ||
}; | ||
@@ -74,13 +76,13 @@ } | ||
parse: function(data) { | ||
parse: function(lines) { | ||
// pass into the switch/case to decide which function to use. | ||
switch (data.charAt(0)){ | ||
case "1": | ||
return failureResponseCode(data); | ||
case "2": | ||
return successResponseCode(data); | ||
case "5": | ||
return asynchornousResponseCode(data); | ||
switch (lines[0].charAt(0)){ | ||
case '1': | ||
return failureResponseCode(lines); | ||
case '2': | ||
return successResponseCode(lines); | ||
case '5': | ||
return asynchornousResponseCode(lines); | ||
default: | ||
throw new Error("Invalid payload. Unknown response code."); | ||
throw new Error('Invalid payload. Unknown response code.'); | ||
} | ||
@@ -90,2 +92,2 @@ } | ||
module.exports = Parser; | ||
module.exports = Parser; |
var events = require('events'); | ||
var Parser = require('./parser'); | ||
var Logger = require("../logger"); | ||
var Logger = require('../logger'); | ||
var logger = Logger.get("hyperdeck.ResponseHandler"); | ||
var logger = Logger.get('hyperdeck.ResponseHandler'); | ||
var SINGLE_LINE_REGEX = /^(?:1\d{2}|200) /; | ||
/** | ||
@@ -13,43 +15,63 @@ * Handles responses from they hyperdeck. | ||
var notifier = new events.EventEmitter(); | ||
var buffer = ""; | ||
function isBufferComplete() { | ||
var lines = buffer.split("\r\n"); | ||
// there will always be an empty element at the end as every line will always end in "\r\n" | ||
// so remove it. | ||
// i.e. "1\r\n2\r\n" => ["1", "2", ""] | ||
lines.pop(); | ||
if (lines.length === 1) { | ||
// is it a single line response? | ||
return lines[0].indexOf(":") !== lines[0].length-1; | ||
} | ||
// multi line response so waiting for a blank line to signify end | ||
return lines[lines.length-1] === ""; | ||
var buffer = []; | ||
var incompleteLastLine = ''; | ||
function isRespComplete() { | ||
var complete = false; | ||
if (buffer.length === 1) { | ||
// a single line response | ||
// 1XX and 200 is always single line response | ||
complete = SINGLE_LINE_REGEX.test(buffer[0]); | ||
} else { | ||
// multi line response, so waiting for a blank line to signify end | ||
complete = buffer[buffer.length - 1] === ''; | ||
} | ||
return complete; | ||
} | ||
function onData(rawData) { | ||
buffer += rawData; | ||
if (!isBufferComplete()) { | ||
return; | ||
} | ||
logger.debug('Got data on socket.', rawData); | ||
var data = Parser.parse(buffer); | ||
// reset buffer | ||
buffer = ""; | ||
switch (data.type) { | ||
case "synchronousFailure": | ||
case "synchronousSuccess": | ||
var response = { | ||
success: data.type === "synchronousSuccess", | ||
data: data.data | ||
}; | ||
notifier.emit("synchronousResponse", response); | ||
break; | ||
case "asynchronous": | ||
notifier.emit("asynchronousResponse", data.data); | ||
break; | ||
default: | ||
throw "Unknown response type."; | ||
} | ||
logger.debug('Got data on socket.\n', rawData); | ||
var resArray = (incompleteLastLine + rawData).split('\r\n'); | ||
incompleteLastLine = resArray.pop(); | ||
resArray.forEach(function (line) { | ||
// push to buffer till response is read completly | ||
// handle empty lines before the data | ||
// see https://github.com/LA1TV/Hyperdeck-JS-Lib/issues/44 | ||
if (buffer.length > 0 || (buffer.length === 0 && line.trim() !== '')) { | ||
buffer.push(line); | ||
if (isRespComplete()) { | ||
if (buffer.length > 1) { | ||
// multiline response, remove empty line | ||
buffer.pop(); | ||
} | ||
logger.debug('Got complete data.\n', buffer); | ||
// reset buffer here and use clone (in case exception happens below) | ||
var bufferClone = buffer.splice(0); | ||
try { | ||
var data = Parser.parse(bufferClone); | ||
switch (data.type) { | ||
case 'synchronousFailure': | ||
case 'synchronousSuccess': | ||
var response = { | ||
success: data.type === 'synchronousSuccess', | ||
data: data.data | ||
}; | ||
notifier.emit('synchronousResponse', response); | ||
break; | ||
case 'asynchronous': | ||
notifier.emit('asynchronousResponse', data.data); | ||
break; | ||
default: | ||
throw new Error('Unknown response type.'); | ||
} | ||
} catch(e) { | ||
// defer exception so that we don't stop processing response | ||
setTimeout(function() { | ||
throw e; | ||
}, 0); | ||
} | ||
} | ||
} | ||
}); | ||
} | ||
@@ -59,7 +81,7 @@ | ||
this.getNotifier = function() { | ||
this.getNotifier = function () { | ||
return notifier; | ||
}; | ||
this.destroy = function() { | ||
this.destroy = function () { | ||
if (destroyed) { | ||
@@ -74,2 +96,2 @@ return; | ||
module.exports = ResponseHandler; | ||
module.exports = ResponseHandler; |
// Here we export what we want to be accessible from the library to the developer | ||
module.exports = { | ||
Hyperdeck: require("./hyperdeck/hyperdeck"), | ||
HyperdeckCore: require("./hyperdeck/hyperdeck-core"), | ||
Logger: require("./logger") | ||
Hyperdeck: require('./hyperdeck/hyperdeck'), | ||
HyperdeckCore: require('./hyperdeck/hyperdeck-core'), | ||
Logger: require('./logger') | ||
}; |
@@ -1,2 +0,2 @@ | ||
var JsLogger = require("js-logger"); | ||
var JsLogger = require('js-logger'); | ||
@@ -3,0 +3,0 @@ JsLogger.useDefaults({ |
@@ -9,15 +9,15 @@ var proxyquire = require('proxyquire'); | ||
code: 512, | ||
text: "Async event", | ||
text: 'Async event', | ||
params: { | ||
"protocol version": "9.5", | ||
model: "xyz", | ||
time: "12:40:12" | ||
'protocol version': '9.5', | ||
model: 'xyz', | ||
time: '12:40:12' | ||
} | ||
}; | ||
var SUCCESS_DATA = { | ||
code: 200, | ||
text: "Success with data", | ||
code: 201, | ||
text: 'Success with data', | ||
params: { | ||
something: "123", | ||
"something else": "test" | ||
something: '123', | ||
'something else': 'test' | ||
} | ||
@@ -27,10 +27,10 @@ }; | ||
code: 102, | ||
text: "Failure", | ||
text: 'Failure', | ||
params: { | ||
something: "123", | ||
"something else": "test" | ||
something: '123', | ||
'something else': 'test' | ||
} | ||
}; | ||
// require Hyperdeck but overriding the require("net") and require("ResponseHandler") to use our stubs | ||
// require Hyperdeck but overriding the require('net') and require('ResponseHandler') to use our stubs | ||
var Hyperdeck = proxyquire('../../src/hyperdeck/hyperdeck-core', { | ||
@@ -48,3 +48,3 @@ 'net': getNetStub(), | ||
beforeEach(function() { | ||
hyperdeck = new Hyperdeck("127.0.0.1"); | ||
hyperdeck = new Hyperdeck('127.0.0.1'); | ||
}); | ||
@@ -60,3 +60,3 @@ | ||
it('can be constructed', function() { | ||
hyperdeck.should.be.ok; | ||
hyperdeck.should.be.ok(); | ||
}); | ||
@@ -66,9 +66,9 @@ | ||
(function() { | ||
hyperdeck.makeRequest("something\r"); | ||
hyperdeck.makeRequest('something\r'); | ||
}).should.throw(); | ||
(function() { | ||
hyperdeck.makeRequest("something\r"); | ||
hyperdeck.makeRequest('something\r'); | ||
}).should.throw(); | ||
(function() { | ||
hyperdeck.makeRequest("something\r\n"); | ||
hyperdeck.makeRequest('something\r\n'); | ||
}).should.throw(); | ||
@@ -78,3 +78,3 @@ }); | ||
it('triggers asynchronousEvent when the responseHandler gets an async response message.', function(done) { | ||
hyperdeck.getNotifier().once("asynchronousEvent", function(data) { | ||
hyperdeck.getNotifier().once('asynchronousEvent', function(data) { | ||
data.should.eql(ASYNCHRONOUS_EVENT_DATA); | ||
@@ -92,3 +92,3 @@ done(); | ||
hyperdeck.makeRequest("a valid hyperdeck request").then(function(data) { | ||
hyperdeck.makeRequest('a valid hyperdeck request').then(function(data) { | ||
data.should.eql(SUCCESS_DATA); | ||
@@ -103,3 +103,3 @@ done(); | ||
hyperdeck.makeRequest("a valid hyperdeck request").catch(function(data) { | ||
hyperdeck.makeRequest('a valid hyperdeck request').catch(function(data) { | ||
data.should.eql(FAILURE_DATA); | ||
@@ -115,3 +115,3 @@ done(); | ||
hyperdeck.makeRequest("a valid hyperdeck request").then(function(data) { | ||
hyperdeck.makeRequest('a valid hyperdeck request').then(function(data) { | ||
data.should.eql(SUCCESS_DATA); | ||
@@ -135,13 +135,17 @@ done(); | ||
setTimeout(function() { | ||
if (destroyed) return; | ||
if (destroyed) { | ||
return; | ||
} | ||
onSuccess(); | ||
setTimeout(function() { | ||
if (destroyed) return; | ||
if (destroyed) { | ||
return; | ||
} | ||
// fake hyperdeck connection response | ||
responseHandlerNotifier.emit("asynchronousResponse", { | ||
responseHandlerNotifier.emit('asynchronousResponse', { | ||
code: 500, | ||
text: "connection info", | ||
text: 'connection info', | ||
params: { | ||
"protocol version": "some protocol version", | ||
model: "some model" | ||
'protocol version': 'some protocol version', | ||
model: 'some model' | ||
} | ||
@@ -162,18 +166,15 @@ }); | ||
on: function(evt, listener) { | ||
if (evt === "close") { | ||
if (evt === 'close') { | ||
onCloseListeners.push(listener); | ||
} | ||
else if (evt === "error") { | ||
else if (evt !== 'error') { | ||
throw new Error('Not supported in mock net.'); | ||
} | ||
else { | ||
throw new Error("Not supported in mock net."); | ||
} | ||
}, | ||
setEncoding: function() { | ||
// | ||
}, | ||
destroy: function() { | ||
if (destroyed) { | ||
throw new Error("Already destroyed."); | ||
throw new Error('Already destroyed.'); | ||
} | ||
@@ -185,3 +186,3 @@ destroyed = true; | ||
} | ||
} | ||
}; | ||
} | ||
@@ -196,3 +197,3 @@ }; | ||
if (responseHandlerNotifier) { | ||
throw new Error("responseHandlerNotifier should have been destroyed after each test."); | ||
throw new Error('responseHandlerNotifier should have been destroyed after each test.'); | ||
} | ||
@@ -217,6 +218,6 @@ var notifier = new events.EventEmitter(); | ||
if (onSocketWrite) { | ||
throw new Error("onSocketWrite already set. Should be cleared after use."); | ||
throw new Error('onSocketWrite already set. Should be cleared after use.'); | ||
} | ||
// will be called when the Hyperdeck writes to the socket. | ||
onSocketWrite = function(data) { | ||
onSocketWrite = function(/* data */) { | ||
onSocketWrite = null; | ||
@@ -228,6 +229,6 @@ | ||
// fake an async response first | ||
responseHandlerNotifier.emit("asynchronousResponse", ASYNCHRONOUS_EVENT_DATA); | ||
responseHandlerNotifier.emit('asynchronousResponse', ASYNCHRONOUS_EVENT_DATA); | ||
} | ||
setTimeout(function() { | ||
responseHandlerNotifier.emit("synchronousResponse", { | ||
responseHandlerNotifier.emit('synchronousResponse', { | ||
success: true, | ||
@@ -245,6 +246,6 @@ data: SUCCESS_DATA | ||
if (onSocketWrite) { | ||
throw new Error("onSocketWrite already set. Should be cleared after use."); | ||
throw new Error('onSocketWrite already set. Should be cleared after use.'); | ||
} | ||
// will be called when the Hyperdeck writes to the socket. | ||
onSocketWrite = function(data) { | ||
onSocketWrite = function(/* data */) { | ||
onSocketWrite = null; | ||
@@ -254,3 +255,3 @@ | ||
setTimeout(function() { | ||
responseHandlerNotifier.emit("synchronousResponse", { | ||
responseHandlerNotifier.emit('synchronousResponse', { | ||
success: false, | ||
@@ -265,8 +266,8 @@ data: FAILURE_DATA | ||
if (onConnectionCompleted) { | ||
throw new Error("onConnectionCompleted already set. Should be cleared after use."); | ||
throw new Error('onConnectionCompleted already set. Should be cleared after use.'); | ||
} | ||
onConnectionCompleted = function() { | ||
onConnectionCompleted = null; | ||
responseHandlerNotifier.emit("asynchronousResponse", ASYNCHRONOUS_EVENT_DATA); | ||
responseHandlerNotifier.emit('asynchronousResponse', ASYNCHRONOUS_EVENT_DATA); | ||
}; | ||
} |
var Parser = require('../../src/hyperdeck/parser'); | ||
var SUCCESS_RESPONSE = "200 Success"; | ||
var SUCCESS_RESPONSE_WITH_PARAMS = "200 Success with data:\r\nsomething: 123\r\nsomething else: test\r\n\r\n"; | ||
var SUCCESS_RESPONSE_WITH_UNPARSEABLE_PARAMS = "200 Success with data:\r\n<something-unexpected />\r\n\r\n"; | ||
var FAILURE_RESPONSE = "102 Failure"; | ||
var FAILURE_RESPONSE_WITH_PARAMS = "102 Failure:\r\nsomething: 123\r\nsomething else: test\r\n\r\n"; | ||
var ASYNC_RESPONSE = "512 Async event:\r\nprotocol version: 9.5\r\nmodel: xyz\r\ntime: 12:40:12\r\n\r\n"; | ||
var INVALID_RESPONSE = "something invalid"; | ||
var SUCCESS_RESPONSE = [ '200 ok' ]; | ||
var SUCCESS_RESPONSE_WITH_PARAMS = [ | ||
'201 Success with data:', | ||
'something: 123', | ||
'something else: test' | ||
]; | ||
var SUCCESS_RESPONSE_WITH_UNPARSEABLE_PARAMS = [ | ||
'201 Success with data:', | ||
'<something-unexpected />' | ||
]; | ||
var FAILURE_RESPONSE = [ '102 Failure' ]; | ||
var ASYNC_RESPONSE = [ | ||
'512 Async event:', | ||
'protocol version: 9.5', | ||
'model: xyz', | ||
'time: 12:40:12' | ||
]; | ||
var INVALID_RESPONSE = [ 'something invalid' ]; | ||
var SUCCESS_RESPONSE_DATA = { | ||
type: "synchronousSuccess", | ||
type: 'synchronousSuccess', | ||
data: { | ||
code: 200, | ||
text: "Success" | ||
text: 'ok' | ||
} | ||
@@ -20,10 +31,10 @@ }; | ||
var SUCCESS_PARAMS_RESPONSE_DATA = { | ||
type: "synchronousSuccess", | ||
type: 'synchronousSuccess', | ||
data: { | ||
code: 200, | ||
text: "Success with data", | ||
code: 201, | ||
text: 'Success with data', | ||
rawData: 'something: 123\r\nsomething else: test', | ||
params: { | ||
something: "123", | ||
"something else": "test" | ||
something: '123', | ||
'something else': 'test' | ||
} | ||
@@ -34,6 +45,6 @@ } | ||
var SUCCESS_UNPARSEABLE_PARAMS_RESPONSE_DATA = { | ||
type: "synchronousSuccess", | ||
type: 'synchronousSuccess', | ||
data: { | ||
code: 200, | ||
text: "Success with data", | ||
code: 201, | ||
text: 'Success with data', | ||
rawData: '<something-unexpected />', | ||
@@ -45,32 +56,19 @@ params: {} | ||
var FAILURE_RESPONSE_DATA = { | ||
type: "synchronousFailure", | ||
type: 'synchronousFailure', | ||
data: { | ||
code: 102, | ||
text: "Failure" | ||
text: 'Failure' | ||
} | ||
}; | ||
var FAILURE_PARAMS_RESPONSE_DATA = { | ||
type: "synchronousFailure", | ||
data: { | ||
code: 102, | ||
text: "Failure", | ||
rawData: "something: 123\r\nsomething else: test", | ||
params: { | ||
something: "123", | ||
"something else": "test" | ||
} | ||
} | ||
}; | ||
var ASYNC_RESPONSE_DATA = { | ||
type: "asynchronous", | ||
type: 'asynchronous', | ||
data: { | ||
code: 512, | ||
text: "Async event", | ||
rawData: "protocol version: 9.5\r\nmodel: xyz\r\ntime: 12:40:12", | ||
text: 'Async event', | ||
rawData: 'protocol version: 9.5\r\nmodel: xyz\r\ntime: 12:40:12', | ||
params: { | ||
"protocol version": "9.5", | ||
model: "xyz", | ||
time: "12:40:12" | ||
'protocol version': '9.5', | ||
model: 'xyz', | ||
time: '12:40:12' | ||
} | ||
@@ -94,6 +92,2 @@ } | ||
it('should handle a response string with a failure status code and params', function() { | ||
Parser.parse(FAILURE_RESPONSE_WITH_PARAMS).should.eql(FAILURE_PARAMS_RESPONSE_DATA); | ||
}); | ||
it('should handle a response string with an async status code', function() { | ||
@@ -100,0 +94,0 @@ Parser.parse(ASYNC_RESPONSE).should.eql(ASYNC_RESPONSE_DATA); |
var ResponseHandler = require('../../src/hyperdeck/response-handler'); | ||
var SUCCESS_RESPONSE = "200 Success with data:\r\nsomething: 123\r\nsomething else: test\r\n\r\n"; | ||
var SUCCESS_RESPONSE = '201 Success with data:\r\nsomething: 123\r\nsomething else: test\r\n\r\n'; | ||
var SUCCESS_RESPONSE_EVENT_PAYLOAD = { | ||
success: true, | ||
data: { | ||
code: 200, | ||
text: "Success with data", | ||
rawData: "something: 123\r\nsomething else: test", | ||
code: 201, | ||
text: 'Success with data', | ||
rawData: 'something: 123\r\nsomething else: test', | ||
params: { | ||
something: "123", | ||
"something else": "test" | ||
something: '123', | ||
'something else': 'test' | ||
} | ||
@@ -17,28 +17,37 @@ } | ||
var FAILURE_RESPONSE = "102 Failure:\r\nsomething: 123\r\nsomething else: test\r\n\r\n"; | ||
var FAILURE_RESPONSE_EVENT_PAYLOAD = { | ||
success: false, | ||
// See format response | ||
var SUCCESS_RESPONSE_WITH_DATA_NO_BUT_NOT_PARAMS = '201 Success with data but not params and no colon\r\nabc\r\n\r\n'; | ||
var SUCCESS_RESPONSE_WITH_DATA_NO_BUT_NOT_PARAMS_EVENT_PAYLOAD = { | ||
success: true, | ||
data: { | ||
code: 102, | ||
text: "Failure", | ||
rawData: "something: 123\r\nsomething else: test", | ||
params: { | ||
something: "123", | ||
"something else": "test" | ||
} | ||
code: 201, | ||
text: 'Success with data but not params and no colon', | ||
rawData: 'abc' | ||
} | ||
}; | ||
var ASYNC_RESPONSE = "512 Async event:\r\nprotocol version: 9.5\r\nmodel: xyz\r\ntime: 12:40:12\r\n\r\n"; | ||
var SINGLE_LINE_SUCCESS_RESPONSE = '200 ok\r\n'; | ||
var SINGLE_LINE_SUCCESS_RESPONSE_DATA = { | ||
success: true, | ||
data: { | ||
code: 200, | ||
text: 'ok' | ||
} | ||
}; | ||
var ASYNC_RESPONSE = '512 Async event:\r\nprotocol version: 9.5\r\nmodel: xyz\r\ntime: 12:40:12\r\n\r\n'; | ||
var ASYNC_RESPONSE_EVENT_PAYLOAD = { | ||
code: 512, | ||
text: "Async event", | ||
rawData: "protocol version: 9.5\r\nmodel: xyz\r\ntime: 12:40:12", | ||
text: 'Async event', | ||
rawData: 'protocol version: 9.5\r\nmodel: xyz\r\ntime: 12:40:12', | ||
params: { | ||
"protocol version": "9.5", | ||
model: "xyz", | ||
time: "12:40:12" | ||
'protocol version': '9.5', | ||
model: 'xyz', | ||
time: '12:40:12' | ||
} | ||
}; | ||
var COMBINED_RESPONSE = SUCCESS_RESPONSE + SINGLE_LINE_SUCCESS_RESPONSE + ASYNC_RESPONSE; | ||
var COMBINED_RESPONSE_EXTRA_LINES = ASYNC_RESPONSE + '\r\n' + SUCCESS_RESPONSE; | ||
describe('ResponseHandler', function() { | ||
@@ -60,7 +69,7 @@ | ||
it('can be built', function() { | ||
responseHandler.should.be.ok; | ||
responseHandler.should.be.ok(); | ||
}); | ||
it('emits a valid synchronous response event when receives a success response', function(done) { | ||
responseHandler.getNotifier().once("synchronousResponse", function(response) { | ||
responseHandler.getNotifier().once('synchronousResponse', function(response) { | ||
response.should.eql(SUCCESS_RESPONSE_EVENT_PAYLOAD); | ||
@@ -72,12 +81,23 @@ done(); | ||
it('emits a valid synchronous response event when receives a failure response', function(done) { | ||
responseHandler.getNotifier().once("synchronousResponse", function(response) { | ||
response.should.eql(FAILURE_RESPONSE_EVENT_PAYLOAD); | ||
it('emits a valid synchronous response event when receives a success response with data which is not params', function(done) { | ||
responseHandler.getNotifier().once('synchronousResponse', function(response) { | ||
response.should.eql(SUCCESS_RESPONSE_WITH_DATA_NO_BUT_NOT_PARAMS_EVENT_PAYLOAD); | ||
done(); | ||
}); | ||
socket.write(FAILURE_RESPONSE); | ||
socket.write(SUCCESS_RESPONSE_WITH_DATA_NO_BUT_NOT_PARAMS); | ||
}); | ||
it('emits a valid synchronous response event when receives a success response with data which is not params, after receiving an asynchronous response', function(done) { | ||
responseHandler.getNotifier().once('asynchronousResponse', function(response) { | ||
response.should.eql(ASYNC_RESPONSE_EVENT_PAYLOAD); | ||
responseHandler.getNotifier().once('synchronousResponse', function(response) { | ||
response.should.eql(SUCCESS_RESPONSE_WITH_DATA_NO_BUT_NOT_PARAMS_EVENT_PAYLOAD); | ||
done(); | ||
}); | ||
}); | ||
socket.write(ASYNC_RESPONSE + SUCCESS_RESPONSE_WITH_DATA_NO_BUT_NOT_PARAMS); | ||
}); | ||
it('emits a valid asynchronous response event when receives an aync response', function(done) { | ||
responseHandler.getNotifier().once("asynchronousResponse", function(response) { | ||
responseHandler.getNotifier().once('asynchronousResponse', function(response) { | ||
response.should.eql(ASYNC_RESPONSE_EVENT_PAYLOAD); | ||
@@ -88,2 +108,44 @@ done(); | ||
}); | ||
it('handles multiple responses arriving at the same time', function(done) { | ||
responseHandler.getNotifier().once('synchronousResponse', function(response) { | ||
response.should.eql(SUCCESS_RESPONSE_EVENT_PAYLOAD); | ||
responseHandler.getNotifier().once('synchronousResponse', function(response) { | ||
response.should.eql(SINGLE_LINE_SUCCESS_RESPONSE_DATA); | ||
responseHandler.getNotifier().once('asynchronousResponse', function(response) { | ||
response.should.eql(ASYNC_RESPONSE_EVENT_PAYLOAD); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
socket.write(COMBINED_RESPONSE); | ||
}); | ||
// see https://github.com/LA1TV/Hyperdeck-JS-Lib/issues/44 | ||
it('handles multiple responses arriving at the same time with extra lines inbetween', function(done) { | ||
responseHandler.getNotifier().once('asynchronousResponse', function(response) { | ||
response.should.eql(ASYNC_RESPONSE_EVENT_PAYLOAD); | ||
responseHandler.getNotifier().once('synchronousResponse', function(response) { | ||
response.should.eql(SUCCESS_RESPONSE_EVENT_PAYLOAD); | ||
done(); | ||
}); | ||
}); | ||
socket.write(COMBINED_RESPONSE_EXTRA_LINES); | ||
}); | ||
it('handles multiple responses arriving character by character', function(done) { | ||
responseHandler.getNotifier().once('synchronousResponse', function(response) { | ||
response.should.eql(SUCCESS_RESPONSE_EVENT_PAYLOAD); | ||
responseHandler.getNotifier().once('synchronousResponse', function(response) { | ||
response.should.eql(SINGLE_LINE_SUCCESS_RESPONSE_DATA); | ||
responseHandler.getNotifier().once('asynchronousResponse', function(response) { | ||
response.should.eql(ASYNC_RESPONSE_EVENT_PAYLOAD); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
COMBINED_RESPONSE.split('').forEach(function(char) { | ||
socket.write(char); | ||
}); | ||
}); | ||
}); | ||
@@ -108,8 +170,8 @@ | ||
MockSocket.prototype.on = function(evt, listener) { | ||
if (evt === "data") { | ||
if (evt === 'data') { | ||
this._dataListeners.push(listener); | ||
} | ||
else { | ||
throw new Error("MockSocket doesn't support this!"); | ||
throw new Error('MockSocket doesn\'t support this!'); | ||
} | ||
}; |
@@ -5,12 +5,12 @@ var index = require('../src/index'); | ||
it('should provide the Hyperdeck class', function() { | ||
index.Hyperdeck.should.be.ok; | ||
index.Hyperdeck.should.be.ok(); | ||
}); | ||
it('should provide the HyperdeckCore class', function() { | ||
index.HyperdeckCore.should.be.ok; | ||
index.HyperdeckCore.should.be.ok(); | ||
}); | ||
it('should provide the Logger class', function() { | ||
index.Logger.should.be.ok; | ||
index.Logger.should.be.ok(); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
46531
1004
16