Files
Zos/Skills/@be/node_modules/icecast/lib/client.js

129 lines
2.8 KiB
JavaScript

/**
* Module dependencies.
*/
var net = require('net');
var url = require('url');
var http = require('http');
var Reader = require('./reader');
var preprocess = require('./preprocessor');
var debug = require('debug')('icecast:client');
/**
* Module exports.
*/
exports = module.exports = Client;
/**
* The `Client` class is a subclass of the `http.ClientRequest` object.
*
* It adds a stream preprocessor to make "ICY" responses work. This is only needed
* because of the strictness of node's HTTP parser. I'll volley for ICY to be
* supported (or at least configurable) in the http header for the JavaScript
* HTTP rewrite (v0.12 of node?).
*
* The other big difference is that it passes an `icecast.Reader` instance
* instead of a `http.ClientResponse` instance to the "response" event callback,
* so that the "metadata" events are automatically parsed and the raw audio stream
* it output without the Icecast bytes.
*
* Also see the [`request()`](#request) and [`get()`](#get) convenience functions.
*
* @param {Object} options connection info and options object
* @param {Function} cb optional callback function for the "response" event
* @api public
*/
function Client (options, cb) {
if ('string' == typeof options) {
options = url.parse(options);
}
var req = http.request(options);
// add the "Icy-MetaData" header
req.setHeader('Icy-MetaData', '1');
if ('function' == typeof cb) {
req.once('icecastResponse', cb);
}
req.once('response', icecastOnResponse);
req.once('socket', icecastOnSocket);
return req;
};
/**
* "response" event listener.
*
* @api private
*/
function icecastOnResponse (res) {
debug('request "response" event');
var s = res;
var metaint = res.headers['icy-metaint'];
if (metaint) {
debug('got metaint: %d', metaint);
s = new Reader(metaint);
res.pipe(s);
s.res = res;
Object.keys(res).forEach(function (k) {
if ('_' === k[0]) return;
debug('proxying %j', k);
proxy(s, k);
});
}
if (res.connection._wasIcy) {
s.httpVersion = 'ICY';
}
this.emit('icecastResponse', s);
}
/**
* "socket" event listener.
*
* @api private
*/
function icecastOnSocket (socket) {
debug('request "socket" event');
// we have to preprocess the stream (that is, intercept "data" events and
// emit our own) to make the invalid "ICY" HTTP version get translated into
// "HTTP/1.0"
preprocess(socket);
}
/**
* Proxies "key" from `stream` to `stream.res`.
*
* @api private
*/
function proxy (stream, key) {
if (key in stream) {
debug('not proxying prop "%s" because it already exists on target stream', key);
return;
}
function get () {
return stream.res[key];
}
function set (v) {
return stream.res[key] = v;
}
Object.defineProperty(stream, key, {
configurable: true,
enumerable: true,
get: get,
set: set
});
}