vchat
Version:
An experimental video chat server/client hybrid
164 lines (156 loc) • 5.62 kB
JavaScript
import Ember from 'ember';
const { Evented, RSVP, Service, inject } = Ember;
//Emitted events:
//error, msg (something went wrong!)
//open (server is up!)
//close (server is closed!)
export default Service.extend(Evented, {
debug: inject.service(),
nodeModules: inject.service(),
settings: inject.service(),
httpsServer: null,
socketServer: null,
rootSpace: {},
listening: false,
serverEstablished: false,
tryPort: '0',
setup: function(){
let nodeModules = this.get('nodeModules');
let https = nodeModules.get('https');
let Io = nodeModules.get('socketIo');
let pem = nodeModules.get('pem');
let openSSLPath = this.get('settings').getOpenSSLPath();
pem.config({
pathOpenSSL: openSSLPath ? openSSLPath : (process.env.OPENSSL_BIN || 'openssl')
});
return new RSVP.Promise((res, rej) => {
//we can't do anything until we have ssl keys to host a call
pem.createCertificate({days:999, selfSigned: true}, (err, keys) => {
if(err)
{
rej('OpenSSL is not available on this machine or is misconfigured, but it is required to host a call. Please install OpenSSL and modify your OpenSSL path in settings.<br><br>' + err);
}
else
{
let httpsServer = https.createServer({key: keys.serviceKey, cert: keys.certificate});
let socketServer = new Io(httpsServer, { 'transports': ['polling', 'websocket'], allowUpgrades: true, log: false });
let rootSpace = socketServer.of('/');
this.setProperties({
httpsServer,
socketServer,
rootSpace,
serverEstablished: true
});
this.routeServer();
httpsServer.on('error', () => {
this.set('listening', false);
this.trigger('error', 'Unable to listen on port: ' + this.get('tryPort'));
this.trigger('close');
});
res();
}
});
});
},
listen: function(port){
let established = this.get('serverEstablished');
let listening = this.get('listening');
port = (isNaN(port) || port < 1) ? 9090 : port;
if(!listening)
{
this.set('tryPort', port);
if(established)
{
this.bindServer();
}
else
{
this.setup().then(() => {
this.bindServer();
}).catch((err) => {
this.trigger('error', err);
this.trigger('close');
});
}
}
},
bindServer: function(){
this.get('httpsServer').listen(this.get('tryPort'), () => {
this.set('listening', true);
this.trigger('open');
});
},
stopListening: function(){
let listening = this.get('listening');
let sockets = this.findSockets();
if(listening)
{
this.get('httpsServer').close(() => {
this.set('listening', false);
this.trigger('close');
});
}
sockets.forEach((socket) => {
socket.disconnect();
});
},
disconnectSocket: function(el){
let sockets = this.findSockets();
sockets.forEach((socket) => {
if(el === socket.id)
{
sockets.disconnect();
}
});
},
findSockets: function(roomId, namespace){ //find all sockets in a place
let res = [];
let ns = this.get('socketServer').of(namespace || "/"); // the default namespace is "/"
if(ns)
{
Object.keys(ns.connected).forEach((id) => {
if(roomId)
{
if(ns.connected[id].rooms.indexOf(roomId) !== -1)
{
res.push(ns.connected[id]);
}
}
else
{
res.push(ns.connected[id]);
}
});
}
return res;
},
routeServer: function(){
let socketio = this.get('socketServer');
let debug = this.get('debug');
socketio.on('connection', (socket) => {
socket.broadcast.emit('peerConnected', { id: socket.id });
debug.debug('Alerting peers of new client: ' + socket.id);
socket.on('webrtc', (data) => {
let tgt = this.get('rootSpace').connected[data.to];
if(tgt)
{
data.by = socket.id;
debug.debug('Redirecting message to: ' + data.to + ' from: ' + data.by);
debug.debug('Message data: ' + JSON.stringify(data));
tgt.emit('webrtc', data);
}
else
{
debug.warn('Invalid user');
}
});
socket.on('disconnect', () => {
if(socket)
{
socket.broadcast.emit('peerDisconnected', { id: socket.id });
}
});
debug.debug('Socket link established: ' + socket.id);
});
}
});