180 lines
5.0 KiB
JavaScript
180 lines
5.0 KiB
JavaScript
let tls = require('tls');
|
|
var inject = require('reconnect-core');
|
|
var slice = [].slice;
|
|
var MumbleClient = require('mumble-client');
|
|
var NodeCodecs = require('mumble-client-codecs-node');
|
|
var fs = require('fs');
|
|
var execSync = require('child_process').execSync;
|
|
var currentPath = require('path').dirname(require.main.filename);
|
|
const utils = require('./utils');
|
|
const OpusEncoder = require('node-opus').OpusEncoder;
|
|
|
|
class Mumble {
|
|
|
|
constructor(id, configs, connectedCallback) {
|
|
|
|
this.id = id;
|
|
this.configs = configs;
|
|
let mumble = configs.mumble;
|
|
this._createCertificatesForUser(id, () => {
|
|
|
|
this._makeMumbleConnection(id, mumble.port, mumble.host, id, id, connectedCallback);
|
|
})
|
|
}
|
|
|
|
// Create cerificates by running createCerts.sh script.
|
|
_createCertificatesForUser(id, callback) {
|
|
|
|
var code;
|
|
var path = currentPath + '/certs/' + id + '-cert.pem';
|
|
|
|
if (!fs.existsSync(path)) {
|
|
utils.writeLog(`Creating certificates for asset ${id}`)
|
|
try {
|
|
var code = execSync(currentPath + '/createCerts.sh ' + id);
|
|
} catch (e) {
|
|
return callback(false);
|
|
}
|
|
return callback(true);
|
|
} else {
|
|
utils.writeLog(`Certificates for asset ${id} already created`);
|
|
return callback(true);
|
|
}
|
|
}
|
|
|
|
_makeMumbleConnection(id, port, host, username, password, connectedCallback) {
|
|
|
|
// If ca does not exist create them.
|
|
var rootPath = currentPath + '/certs/root-cert.pem';
|
|
if (!fs.existsSync(rootPath)) {
|
|
utils.writeLog(`Creating certificates for Mumble`);
|
|
try { execSync('./createCA.sh'); }
|
|
catch(e) {
|
|
utils.writeErrorLog(`Could not crete Mumble certificates. Error:${e}`);
|
|
throw 'Could not crete CA certificates. ' + e;
|
|
}
|
|
} else {
|
|
utils.writeLog(`Certificates for Mumble already created`);
|
|
}
|
|
|
|
var reconnect = inject(function(){
|
|
var args = slice.call(arguments);
|
|
var cleartextStream = tls.connect.apply(tls, args);
|
|
cleartextStream.on('secureConnect', function(){
|
|
// if(cleartextStream.authorized){
|
|
// cleartextStream.emit('connect');
|
|
// }else{
|
|
// cleartextStream.emit('error', cleartextStream.authorizationError);
|
|
// }
|
|
});
|
|
return cleartextStream;
|
|
});
|
|
|
|
var secureContext = tls.createSecureContext({
|
|
ca: [
|
|
fs.readFileSync(currentPath + '/certs/root-cert.pem'),
|
|
fs.readFileSync(currentPath + '/certs/ca1-cert.pem'),
|
|
],
|
|
key: fs.readFileSync(currentPath + '/certs/' + this.id + '-key.pem'),
|
|
cert: fs.readFileSync(currentPath + '/certs/' + this.id + '-cert.pem'),
|
|
});
|
|
|
|
// Create connection socket with Murmur server.
|
|
reconnect((socket) => {
|
|
|
|
this.socket = socket;
|
|
|
|
// Connect to mumble server.
|
|
this.client = new MumbleClient({
|
|
username: '' + username,
|
|
password: '' + password,
|
|
codecs: NodeCodecs
|
|
});
|
|
this.client.connectDataStream(this.socket);
|
|
|
|
this._prepareClient()
|
|
})
|
|
.once('connect', function (con) {
|
|
// con = underlying connection
|
|
connectedCallback();
|
|
})
|
|
.on('connect', function (con) {
|
|
// con = underlying connection
|
|
})
|
|
.on('reconnect', function (n, delay) {
|
|
// n = current number of reconnect
|
|
// delay = delay used before reconnect
|
|
console.log('------ Server reconnect...');
|
|
})
|
|
.on('disconnect', function (err) {
|
|
// err = possible error
|
|
})
|
|
.on('error', function (err) {
|
|
// never forget
|
|
// console.log(err)
|
|
// connectedCallback(err);
|
|
console.log('Mumble _makeMumbleConnection ERROR')
|
|
utils.writeErrorLog('Mumble _makeMumbleConnection ERROR', err);
|
|
})
|
|
.connect({ port: port, host: host, rejectUnauthorized: false, secureContext: secureContext });
|
|
}
|
|
|
|
_prepareClient() {
|
|
|
|
// Register all users
|
|
this.client.users.forEach(user => this._newUser(user));
|
|
|
|
// Register future users
|
|
this.client.on('newUser', user => this._newUser(user))
|
|
|
|
this.client.on('newChannel', channel => this._newChannel(channel))
|
|
}
|
|
|
|
_newUser(user) {
|
|
|
|
// @TODO: Ugly hack for the voice to work with mp3. It is the _transform function from DecoderStream class (mumble-client-codecs-node project).
|
|
user.on('voice', voice => {
|
|
voice._transform = function (chunk, encoding, callback) {
|
|
if (chunk.codec === 'Opus' && chunk.frame) {
|
|
if (!this._opus) {
|
|
this._opus = new OpusEncoder(48000, 1);
|
|
}
|
|
callback(null, {
|
|
target: chunk.target,
|
|
pcm: chunk.frame ? this._opus.decode(chunk.frame) : {buffer: Buffer.alloc(3840)},
|
|
numberOfChannels: 1,
|
|
position: chunk.position
|
|
});
|
|
} else {
|
|
callback();
|
|
}
|
|
}
|
|
});
|
|
|
|
user.on('update', (actor, properties) => {
|
|
|
|
}).on('remove', () => {
|
|
|
|
}).on('voice', stream => {
|
|
|
|
// Leave all commented and empty. We currently dont need to receive voice.
|
|
|
|
// console.log(`User ${user.username} started takling`);
|
|
|
|
// Leave it empty. Its used for 'end' event to be trigered.
|
|
stream.on('data', (data) => {
|
|
|
|
});
|
|
stream.on('end', () => {
|
|
// console.log(`User ${user.username} stopped takling`)
|
|
});
|
|
});
|
|
}
|
|
|
|
_newChannel(channel) {
|
|
}
|
|
|
|
|
|
}
|
|
|
|
module.exports = Mumble |