83 lines
2.0 KiB
JavaScript
83 lines
2.0 KiB
JavaScript
|
|
|
||
|
|
/**
|
||
|
|
* Module dependencies.
|
||
|
|
*/
|
||
|
|
|
||
|
|
var assert = require('assert');
|
||
|
|
var debug = require('debug')('icecast:preprocessor');
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Module exports.
|
||
|
|
*/
|
||
|
|
|
||
|
|
module.exports = preprocessor;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* The fake HTTP version to write when an "ICY" version is encountered.
|
||
|
|
*/
|
||
|
|
|
||
|
|
var HTTP10 = new Buffer('HTTP/1.0');
|
||
|
|
|
||
|
|
/**
|
||
|
|
* This all really... really.. sucks...
|
||
|
|
*/
|
||
|
|
|
||
|
|
function preprocessor (socket) {
|
||
|
|
debug('setting up "data" preprocessor');
|
||
|
|
|
||
|
|
function ondata (chunk) {
|
||
|
|
// TODO: don't be lazy, buffer if needed...
|
||
|
|
assert(chunk.length >= 3, 'buffer too small! ' + chunk.length);
|
||
|
|
if (/icy/i.test(chunk.slice(0, 3))) {
|
||
|
|
debug('got ICY response!');
|
||
|
|
var b = new Buffer(chunk.length + HTTP10.length - 'icy'.length);
|
||
|
|
var i = 0;
|
||
|
|
i += HTTP10.copy(b);
|
||
|
|
i += chunk.copy(b, i, 3);
|
||
|
|
assert.equal(i, b.length);
|
||
|
|
chunk = b;
|
||
|
|
socket._wasIcy = true;
|
||
|
|
} else {
|
||
|
|
socket._wasIcy = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return chunk;
|
||
|
|
}
|
||
|
|
|
||
|
|
var listeners;
|
||
|
|
function icecastOnData (buf) {
|
||
|
|
var chunk = ondata(buf);
|
||
|
|
|
||
|
|
// clean up, and re-emit "data" event
|
||
|
|
socket.removeListener('data', icecastOnData);
|
||
|
|
listeners.forEach(function (listener) {
|
||
|
|
socket.on('data', listener);
|
||
|
|
});
|
||
|
|
listeners = null;
|
||
|
|
socket.emit('data', chunk);
|
||
|
|
}
|
||
|
|
|
||
|
|
if ('function' == typeof socket.ondata) {
|
||
|
|
// node < v0.11.3, the `ondata` function is set on the socket
|
||
|
|
var origOnData = socket.ondata;
|
||
|
|
socket.ondata = function (buf, start, length) {
|
||
|
|
var chunk = ondata(buf.slice(start, length));
|
||
|
|
|
||
|
|
// now clean up and inject the modified `chunk`
|
||
|
|
socket.ondata = origOnData;
|
||
|
|
origOnData = null;
|
||
|
|
socket.ondata(chunk, 0, chunk.length);
|
||
|
|
};
|
||
|
|
} else if (socket.listeners('data').length > 0) {
|
||
|
|
// node >= v0.11.3, the "data" event is listened for directly
|
||
|
|
|
||
|
|
// add our own "data" listener, and remove all the old ones
|
||
|
|
listeners = socket.listeners('data');
|
||
|
|
socket.removeAllListeners('data');
|
||
|
|
socket.on('data', icecastOnData);
|
||
|
|
} else {
|
||
|
|
// never?
|
||
|
|
throw new Error('should not happen...');
|
||
|
|
}
|
||
|
|
}
|