mediaproxy
Version:
Node.js Media Proxy with REST API
281 lines (258 loc) • 8.86 kB
JavaScript
// Generated by CoffeeScript 1.6.3
(function() {
var EventEmitter, MediaProxy, SingleMediaProxy, assert, dgram, log,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
dgram = require('dgram');
assert = require('assert');
EventEmitter = require('events').EventEmitter;
log = require('util').log;
SingleMediaProxy = (function(_super) {
__extends(SingleMediaProxy, _super);
function SingleMediaProxy(local, remote) {
var _ref,
_this = this;
this.local = local;
this.remote = remote;
assert(this.local != null, 'local is required');
assert(((_ref = this.local) != null ? _ref.port : void 0) != null, 'local.port is required');
this.sent = 0;
this.received = 0;
this.errors = 0;
this.local.socket = dgram.createSocket('udp4');
this.local.socket.on('error', function(err) {
log("Received error " + err + " on port " + _this.local.port);
return _this.emit('error', err);
});
this.local.socket.on('message', function(msg, rinfo) {
_this.received += 1;
if (_this.remote == null) {
_this.remote = rinfo;
}
_this.emit('message', msg, rinfo);
return _this.renew_timeout();
});
if ((this.local.address != null) && this.local.address !== '0.0.0.0' && this.local.address !== '::') {
this.local.socket.bind(this.local.port, this.local.address);
} else {
this.local.socket.bind(this.local.port, function() {
return _this.local.address = _this.local.socket.address();
});
}
this.renew_timeout();
log("SingleMediaProxy ready on port " + this.local.port);
return;
}
SingleMediaProxy.prototype.close = function() {
this.local.socket.close();
delete this.local.socket;
if (this.local.timeout != null) {
clearTimeout(this.local.timeout);
delete this.local.timeout;
}
log("SingleMediaProxy closed on port " + this.local.port);
};
SingleMediaProxy.prototype.send = function(buf) {
var _this = this;
if (this.local.socket == null) {
log('Not ready to send, no local socket.');
return;
}
if ((this.local.socket != null) && (this.remote != null) && (this.remote.address != null) && (this.remote.port != null)) {
this.local.socket.send(buf, 0, buf.length, this.remote.port, this.remote.address, function(err, bytes) {
if (err != null) {
_this.errors += 1;
return log("Send failed with " + err);
} else {
return _this.sent += 1;
}
});
} else {
log('Not ready to send, still missing remote address or port');
}
this.renew_timeout();
};
SingleMediaProxy.prototype.renew_timeout = function() {
var _this = this;
if (this.local.timeout != null) {
clearTimeout(this.local.timeout);
}
this.local.timeout = setTimeout((function() {
return _this.emit('timeout');
}), 30000);
};
return SingleMediaProxy;
})(EventEmitter);
module.exports = MediaProxy = (function() {
function MediaProxy(config) {
var _base, _base1, _base2;
this.config = config;
if (this.config == null) {
this.config = {};
}
if ((_base = this.config).ports == null) {
_base.ports = {};
}
if ((_base1 = this.config.ports).min == null) {
_base1.min = 49152;
}
if ((_base2 = this.config.ports).max == null) {
_base2.max = 65535;
}
this.config.ports.span = Math.floor((this.config.ports.max - this.config.ports.min) / 2);
this.by_uuid = {};
this.by_port = {};
}
MediaProxy.prototype.allocate_port = function() {
var port;
port = this.config.ports.min + 2 * Math.floor(this.config.ports.span * Math.random());
while (this.by_port[port] != null) {
port += 2;
if (port >= this.config.ports.max) {
return false;
}
}
return port;
};
MediaProxy.prototype.allocate_proxy = function(leg, linfo) {
var _ref;
if (leg.local == null) {
leg.local = {
address: (_ref = linfo.address) != null ? _ref : this.config.address,
port: linfo.port || this.allocate_port()
};
}
if (!leg.local.port) {
log('Could not allocate a local port.');
leg.error = 'Could not allocate a local port.';
return;
}
delete leg.error;
leg.proxy = new SingleMediaProxy(leg.local, leg.remote);
this.by_port[leg.local.port] = leg;
log('Allocate proxy successful');
};
MediaProxy.prototype.remove_leg = function(port) {
var leg, name, uuid, _ref;
leg = this.by_port[port];
if (leg == null) {
log("Did not find a leg for port " + port);
return false;
}
name = leg.name;
uuid = leg.uuid;
if ((_ref = leg.proxy) != null) {
_ref.close();
}
delete leg.proxy;
delete this.by_port[port];
log("Removed leg " + name + " uuid " + uuid);
return true;
};
MediaProxy.prototype.add = function(uuid, new_legs) {
var legs, name, new_leg, _base, _fn,
_this = this;
if ((_base = this.by_uuid)[uuid] == null) {
_base[uuid] = {};
}
legs = this.by_uuid[uuid];
_fn = function(name, new_leg) {
var leg, _ref, _ref1, _ref2;
log("Updating leg " + name + " in uuid " + uuid);
leg = (_ref = legs[name]) != null ? _ref : {};
leg.name = name;
leg.uuid = uuid;
if (leg.remote == null) {
leg.remote = new_leg.remote;
}
if (leg.local == null) {
if (new_leg.local != null) {
_this.allocate_proxy(leg, new_leg.local);
}
if ((_ref1 = leg.proxy) != null) {
_ref1.on('message', function(msg) {
var l, n, _results;
_results = [];
for (n in legs) {
l = legs[n];
if (n !== name) {
_results.push((function(l) {
var _ref2;
return (_ref2 = l.proxy) != null ? _ref2.send(msg) : void 0;
})(l));
}
}
return _results;
});
}
if ((_ref2 = leg.proxy) != null) {
_ref2.on('timeout', function() {
log("Received timeout on uuid " + uuid + " leg " + name + ".");
return _this.remove(uuid);
});
}
}
return legs[name] = leg;
};
for (name in new_legs) {
new_leg = new_legs[name];
_fn(name, new_leg);
}
return log("Add successful for uuid " + uuid);
};
MediaProxy.prototype.get = function(uuid) {
var legs, name, response, _, _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7;
response = {};
legs = (_ref = this.by_uuid[uuid]) != null ? _ref : {};
for (name in legs) {
_ = legs[name];
response[name] = {
error: _.error,
remote: {
address: (_ref1 = _.remote) != null ? _ref1.address : void 0,
port: (_ref2 = _.remote) != null ? _ref2.port : void 0
},
local: {
address: (_ref3 = _.local) != null ? _ref3.address : void 0,
port: (_ref4 = _.local) != null ? _ref4.port : void 0
},
sent: (_ref5 = _.proxy) != null ? _ref5.sent : void 0,
received: (_ref6 = _.proxy) != null ? _ref6.received : void 0,
errors: (_ref7 = _.proxy) != null ? _ref7.errors : void 0
};
}
return response;
};
MediaProxy.prototype.remove = function(uuid) {
var leg, legs, name;
legs = this.by_uuid[uuid];
if (legs == null) {
log("Could not find legs for uuid " + uuid);
return {
error: "Could not find legs for uuid " + uuid
};
}
for (name in legs) {
leg = legs[name];
if (leg.local != null) {
this.remove_leg(leg.local.port);
}
}
delete this.by_uuid[uuid];
log("Removed uuid " + uuid);
return {
ok: true
};
};
MediaProxy.prototype.close = function() {
var uuid;
for (uuid in this.by_uuid) {
this.remove(uuid);
}
delete this.by_uuid;
delete this.by_port;
log("Closed");
};
return MediaProxy;
})();
}).call(this);