From 6c78bf44e424a2a0941f5dcbc0eb317301d1e7f5 Mon Sep 17 00:00:00 2001 From: Jianlin Qiu Date: Wed, 10 Mar 2021 02:24:59 +0800 Subject: [PATCH 1/6] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c579e8926..cee36f04f 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ The ${webrtc-javascript-sdk-sample-conference-dist} is built from owt-javascript If "--archive ${name}" option is appended to the pack command, a "Release-${name}.tgz" file will be generated in root folder. For other options, run the scripts with "--help" option. ## Quick Start -In the repository root, run the following commands to start the media server on a single machine: +In dist folder, run the following commands to start the media server on a single machine: 1. `./bin/init-all.sh --deps` 2. `./bin/start-all.sh` 3. Open https://localhost:3004 to visit the web sample page. Due to the test certificate, you may need confirm this unsafe access. From c8f4f6a9f5095021655f00cb8cee98f4ddec5880 Mon Sep 17 00:00:00 2001 From: DWJ01 <1521974869@qq.com> Date: Wed, 17 Mar 2021 06:27:34 +0800 Subject: [PATCH 2/6] Add eslint in packing process --- scripts/pack.js | 42 ++++++++++++++++++++++++++++++++++++++++++ source/.eslintrc.json | 13 +++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 source/.eslintrc.json diff --git a/scripts/pack.js b/scripts/pack.js index 8b0361a03..6dd5d072f 100755 --- a/scripts/pack.js +++ b/scripts/pack.js @@ -28,6 +28,7 @@ optParser.addOption('b', 'binary', 'boolean', 'Pack binary'); optParser.addOption('np', 'no-pseudo', 'boolean', 'Whether use pseudo library'); optParser.addOption('wf', 'with-ffmpeg', 'boolean', 'Whether pack ffmpeg library'); optParser.addOption('h', 'help', 'boolean', 'Show help'); +optParser.addOption('li', 'lint', 'boolean', 'Whether lint code with eslint'); const options = optParser.parseArgs(process.argv); @@ -58,6 +59,26 @@ if (options.help || Object.keys(options).length === 0) { process.exit(0); } +if (options.lint) { + // Check lint deps + const lintDeps = ['eslint']; + console.log('Checking lint dependencies...'); + const npmRoot = execSync(`npm root -g`).toString().trim(); + const missingLintDeps = lintDeps.filter((dep) => { + return !fs.existsSync(path.join(npmRoot, dep)); + }); + + if (missingLintDeps.length === 0) { + console.log('Lint dependencies OK.'); + } else { + for (const dep of missingLintDeps) { + console.log('Installing eslint'); + execSync(`npm install eslint --global --save-dev`); + execSync('npm init --yes'); + } + } +} + var npmInstallOption = ''; if (process.getuid && process.getuid() === 0) { // Running as root @@ -237,9 +258,30 @@ function packCommon(target) { } } if (common.files) { + let eslint; + if (options.lint) { + const { ESLint } = require('eslint'); + eslint = new ESLint({ overrideConfigFile: `${rootDir}/source/.eslintrc.json` }); + } // Copy common files for (const file of common.files) { const filePath = path.join(packSrc, file); + const extname = path.extname(filePath); + if (options.lint && extname === '.js') { + eslint.lintFiles(filePath) + .then((results) => { + eslint.loadFormatter('stylish') + .then((formatter) => { + console.log(formatter.format(results)); + }) + .catch((err) => { + console.log(err); + }) + }) + .catch((err) => { + console.log(err); + }) + } execSync(`cp -a ${filePath} ${packDist}`); } } diff --git a/source/.eslintrc.json b/source/.eslintrc.json new file mode 100644 index 000000000..cfe1e0b3a --- /dev/null +++ b/source/.eslintrc.json @@ -0,0 +1,13 @@ +{ + "env": { + "browser": true, + "es2021": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "ecmaVersion": 12, + "sourceType": "module" + }, + "rules": { + } +} From 41d1a47aef53aa1f7605cdbfbd14066cade9d743 Mon Sep 17 00:00:00 2001 From: DWJ01 <1521974869@qq.com> Date: Wed, 17 Mar 2021 08:04:54 +0800 Subject: [PATCH 3/6] Add eslint in packing process --- scripts/pack.js | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/scripts/pack.js b/scripts/pack.js index 6dd5d072f..a5acdb09a 100755 --- a/scripts/pack.js +++ b/scripts/pack.js @@ -258,29 +258,16 @@ function packCommon(target) { } } if (common.files) { - let eslint; - if (options.lint) { - const { ESLint } = require('eslint'); - eslint = new ESLint({ overrideConfigFile: `${rootDir}/source/.eslintrc.json` }); - } // Copy common files for (const file of common.files) { const filePath = path.join(packSrc, file); const extname = path.extname(filePath); if (options.lint && extname === '.js') { - eslint.lintFiles(filePath) - .then((results) => { - eslint.loadFormatter('stylish') - .then((formatter) => { - console.log(formatter.format(results)); - }) - .catch((err) => { - console.log(err); - }) - }) - .catch((err) => { - console.log(err); - }) + try { + execSync(`eslint -c ${rootDir}/source/.eslintrc.json ${filePath}`); + } catch(error) { + console.error(error.stdout.toString()); + } } execSync(`cp -a ${filePath} ${packDist}`); } From d838f10100174b287abd61d8ce3888fce6cdd06f Mon Sep 17 00:00:00 2001 From: DWJ01 <1521974869@qq.com> Date: Wed, 17 Mar 2021 08:35:47 +0800 Subject: [PATCH 4/6] Add eslint in packing process --- scripts/pack.js | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/pack.js b/scripts/pack.js index a5acdb09a..f1160dd2a 100755 --- a/scripts/pack.js +++ b/scripts/pack.js @@ -74,7 +74,6 @@ if (options.lint) { for (const dep of missingLintDeps) { console.log('Installing eslint'); execSync(`npm install eslint --global --save-dev`); - execSync('npm init --yes'); } } } From 0379a2e2bedf9425cbdbf907c301d755002b7be9 Mon Sep 17 00:00:00 2001 From: DWJ01 <1521974869@qq.com> Date: Tue, 23 Mar 2021 05:46:00 +0800 Subject: [PATCH 5/6] Fix linting problems in portal code --- scripts/release/initauth.js | 134 ++--- scripts/release/initcert.js | 17 +- source/common/amqpClient.js | 156 +++--- source/common/cipher.js | 62 ++- source/common/clusterWorker.js | 447 +++++++-------- source/common/loadCollector.js | 379 +++++++------ source/common/logger.js | 4 +- source/common/makeRPC.js | 31 +- source/common/rpcChannel.js | 29 +- source/portal/client.js | 212 ++++---- source/portal/index.js | 340 ++++++------ source/portal/legacyClient.js | 931 ++++++++++++++++++-------------- source/portal/portal.js | 324 ++++++----- source/portal/rpcRequest.js | 85 ++- source/portal/socketIOServer.js | 281 +++++----- 15 files changed, 1877 insertions(+), 1555 deletions(-) diff --git a/scripts/release/initauth.js b/scripts/release/initauth.js index 0dda31e2d..1d84fa34c 100755 --- a/scripts/release/initauth.js +++ b/scripts/release/initauth.js @@ -9,7 +9,7 @@ const fs = require('fs'); const cipher = require('./cipher'); const authStore = path.resolve(__dirname, cipher.astore); const authBase = path.basename(path.dirname(authStore)); -const { Writable } = require('stream'); +const {Writable} = require('stream'); const mutableStdout = new Writable({ write(chunk, encoding, callback) { @@ -61,65 +61,65 @@ const saveAuth = (obj, filename) => new Promise((resolve, reject) => { const updateRabbit = () => new Promise((resolve, reject) => { question('Update RabbitMQ account?[yes/no]') - .then((answer) => { - answer = answer.toLowerCase(); - if (answer !== 'y' && answer !== 'yes') { - resolve(); - return; - } - question(`(${authBase}) Enter username of rabbitmq: `) - .then((username) => { - question(`(${authBase}) Enter password of rabbitmq: `) - .then((password) => { - mutableStdout.muted = false; - saveAuth({ rabbit: { username, password } }, authStore) - .then(resolve) - .catch(reject); + .then((answer) => { + answer = answer.toLowerCase(); + if (answer !== 'y' && answer !== 'yes') { + resolve(); + return; + } + question(`(${authBase}) Enter username of rabbitmq: `) + .then((username) => { + question(`(${authBase}) Enter password of rabbitmq: `) + .then((password) => { + mutableStdout.muted = false; + saveAuth({rabbit: {username, password}}, authStore) + .then(resolve) + .catch(reject); + }); + mutableStdout.muted = true; }); - mutableStdout.muted = true; - }); - }); + }); }); const updateMongo = () => new Promise((resolve, reject) => { question('Update MongoDB account?[yes/no]') - .then((answer) => { - answer = answer.toLowerCase(); - if (answer !== 'y' && answer !== 'yes') { - resolve(); - return; - } - question(`(${authBase}) Enter username of mongodb: `) - .then((username) => { - question(`(${authBase}) Enter password of mongodb: `) - .then((password) => { - mutableStdout.muted = false; - saveAuth({ mongo: { username, password } }, authStore) - .then(resolve) - .catch(reject); + .then((answer) => { + answer = answer.toLowerCase(); + if (answer !== 'y' && answer !== 'yes') { + resolve(); + return; + } + question(`(${authBase}) Enter username of mongodb: `) + .then((username) => { + question(`(${authBase}) Enter password of mongodb: `) + .then((password) => { + mutableStdout.muted = false; + saveAuth({mongo: {username, password}}, authStore) + .then(resolve) + .catch(reject); + }); + mutableStdout.muted = true; }); - mutableStdout.muted = true; - }); - }); + }); }); const updateInternal = () => new Promise((resolve, reject) => { question('Update internal passphrase?[yes/no]') - .then((answer) => { - answer = answer.toLowerCase(); - if (answer !== 'y' && answer !== 'yes') { - resolve(); - return; - } - question(`(${authBase}) Enter internal passphrase: `) - .then((passphrase) => { - mutableStdout.muted = false; - saveAuth({ internalPass: passphrase }, authStore) - .then(resolve) - .catch(reject); - }); - mutableStdout.muted = true; - }); + .then((answer) => { + answer = answer.toLowerCase(); + if (answer !== 'y' && answer !== 'yes') { + resolve(); + return; + } + question(`(${authBase}) Enter internal passphrase: `) + .then((passphrase) => { + mutableStdout.muted = false; + saveAuth({internalPass: passphrase}, authStore) + .then(resolve) + .catch(reject); + }); + mutableStdout.muted = true; + }); }); const options = {}; @@ -138,22 +138,22 @@ const parseArgs = () => { options.mongo = true; } return Promise.resolve(); -} +}; parseArgs() - .then(() => { - if (options.rabbit) { - return updateRabbit(); - } - }) - .then(() => { - if (options.mongo) { - return updateMongo(); - } - }) - .then(() => { - if (options.internal) { - return updateInternal(); - } - }) - .finally(() => readline.close()); + .then(() => { + if (options.rabbit) { + return updateRabbit(); + } + }) + .then(() => { + if (options.mongo) { + return updateMongo(); + } + }) + .then(() => { + if (options.internal) { + return updateInternal(); + } + }) + .finally(() => readline.close()); diff --git a/scripts/release/initcert.js b/scripts/release/initcert.js index 9dd43457a..eb570137e 100755 --- a/scripts/release/initcert.js +++ b/scripts/release/initcert.js @@ -4,17 +4,18 @@ // SPDX-License-Identifier: Apache-2.0 'use strict'; -(function () { - var readline = require('readline').createInterface({ +(function() { + const readline = require('readline').createInterface({ input: process.stdin, - output: process.stdout + output: process.stdout, }); - var cipher = require('./cipher'); - var dirName = !process.pkg ? __dirname : require('path').dirname(process.execPath); - var keystore = require('path').resolve(dirName, 'cert/' + cipher.kstore); - readline.question('Enter passphrase of certificate: ', function (res) { + const cipher = require('./cipher'); + const dirName = + !process.pkg ? __dirname : require('path').dirname(process.execPath); + const keystore = require('path').resolve(dirName, 'cert/' + cipher.kstore); + readline.question('Enter passphrase of certificate: ', function(res) { readline.close(); - cipher.lock(cipher.k, res, keystore, function cb (err) { + cipher.lock(cipher.k, res, keystore, function cb(err) { console.log(err||'done!'); }); }); diff --git a/source/common/amqpClient.js b/source/common/amqpClient.js index d8f3368cc..b0ba5be98 100644 --- a/source/common/amqpClient.js +++ b/source/common/amqpClient.js @@ -3,13 +3,12 @@ // SPDX-License-Identifier: Apache-2.0 'use strict'; -var fs = require('fs'); -var amqp = require('amqplib'); -var log = require('./logger') - .logger.getLogger('AmqpClient'); -var cipher = require('./cipher'); -var TIMEOUT = 2000; -var REMOVAL_TIMEOUT = 7 * 24 * 3600 * 1000; +const fs = require('fs'); +const amqp = require('amqplib'); +const log = require('./logger') + .logger.getLogger('AmqpClient'); +const cipher = require('./cipher'); +const TIMEOUT = 2000; const RPC_EXC = { name: 'owtRpc', @@ -84,7 +83,7 @@ class RpcClient { const corrID = this.corrID++; this.callMap[corrID] = {}; this.callMap[corrID].fn = callbacks || { - callback: function () {} + callback: function() {}, }; this.callMap[corrID].timer = setTimeout(() => { if (this.callMap[corrID]) { @@ -143,9 +142,9 @@ class RpcClient { } this.callMap = {}; return this.bus.channel.cancel(this.consumerTag) - .catch((err) => { - log.error('Failed during close RpcClient:', this.replyQ); - }); + .catch(() => { + log.error('Failed during close RpcClient:', this.replyQ); + }); } } @@ -183,7 +182,7 @@ class RpcServer { }); } if (typeof this.methods[msg.method] === 'function') { - this.methods[msg.method].apply(this.methods, msg.args); + this.methods[msg.method](...msg.args); } else { log.warn('RPC server does not support this method:', msg.method); if (msg.replyTo && msg.corrID !== undefined) { @@ -211,9 +210,9 @@ class RpcServer { close() { this.ready = false; return this.bus.channel.cancel(this.consumerTag) - .catch((err) => { - log.error('Failed to during close RpcServer:', this.requestQ); - }); + .catch(() => { + log.error('Failed to during close RpcServer:', this.requestQ); + }); } } @@ -237,7 +236,7 @@ class TopicParticipant { this.queue = result.queue; this.ready = true; this.consumers.clear(); - this.subscriptions.forEach((sub, tag) => { + this.subscriptions.forEach((sub) => { this.subscribe(sub.patterns, sub.cb, () => {}); }); }); @@ -249,8 +248,8 @@ class TopicParticipant { if (this.queue && channel) { patterns.map((pattern) => { channel.bindQueue(this.queue, this.name, pattern) - .then(() => log.debug('Follow topic [' + pattern + '] ok.')) - .catch((err) => log.error('Failed to bind queue on topic')); + .then(() => log.debug('Follow topic [' + pattern + '] ok.')) + .catch(() => log.error('Failed to bind queue on topic')); }); channel.consume(this.queue, (rawMessage) => { try { @@ -260,7 +259,8 @@ class TopicParticipant { onMessage(msg); } } catch (error) { - log.error('Error processing topic message:', rawMessage, 'and error:', error); + log.error('Error processing topic message:', rawMessage, + 'and error:', error); } }).then((ok) => { this.consumers.set(patterns.toString(), ok.consumerTag); @@ -278,7 +278,7 @@ class TopicParticipant { if (this.queue && channel) { patterns.map((pattern) => { channel.unbindQueue(this.queue, this.name, pattern) - .catch((err) => log.error('Failed to unbind queue on topic')); + .catch(() => log.error('Failed to unbind queue on topic')); log.debug('Ignore topic [' + pattern + ']'); }); const consumerTag = this.consumers.get(patterns.toString()); @@ -286,7 +286,7 @@ class TopicParticipant { this.consumers.delete(patterns.toString()); this.subscriptions.delete(consumerTag); channel.cancel(consumerTag) - .catch((err) => log.error('Failed to cancel:', consumerTag)); + .catch(() => log.error('Failed to cancel:', consumerTag)); } } else { this.ready = false; @@ -313,10 +313,10 @@ class TopicParticipant { close() { this.ready = false; return this.bus.channel.deleteQueue(this.queue) - .catch((err) => { - log.error('Failed to destroy queue:', this.queue); - }) - .catch((err) => log.error('Failed to delete exchange:', this.name)); + .catch(() => { + log.error('Failed to destroy queue:', this.queue); + }) + .catch(() => log.error('Failed to delete exchange:', this.name)); } } @@ -343,7 +343,8 @@ class Monitor { log.debug('Received monitoring message:', msg); this.onMessage && this.onMessage(msg); } catch (error) { - log.error('Error processing monitored message:', msg, 'and error:', error); + log.error('Error processing monitored message:', rawMessage, + 'and error:', error); } }); }).then((ok) => { @@ -355,11 +356,11 @@ class Monitor { close() { this.ready = false; return this.bus.channel.cancel(this.consumerTag) - .catch((err) => { - log.error('Failed to cancel consumer on queue:', this.queue); - }) - .catch((err) => log.error('Failed to delete exchange:', this.name)); - }; + .catch((err) => { + log.error('Failed to cancel consumer on queue:', this.queue); + }) + .catch((err) => log.error('Failed to delete exchange:', this.name)); + } } class MonitoringTarget { @@ -371,9 +372,9 @@ class MonitoringTarget { setup() { return this.bus.channel.assertExchange( MONITOR_EXC.name, MONITOR_EXC.type, MONITOR_EXC.options) - .then(() => { - this.ready = true; - }); + .then(() => { + this.ready = true; + }); } notify(reason, message) { @@ -448,36 +449,36 @@ class AmqpCli { this.connection = conn; return conn.createChannel(); }) - .then((ch) => { - this.channel = ch; - this.channel.on('error', (e) => { - log.warn('Channel closed:', e); - this.channel = null; - }); - if (!this.connected) { - this.connected = true; - this.successCb(); - } else { - Promise.resolve().then(() => { - return (this.rpcServer && this.rpcServer.setup()); - }).then(() => { - return (this.rpcClient && this.rpcClient.setup()); - }).then(() => { - return (this.monitor && this.monitor.setup()); - }).then(() => { - return (this.monitoringTarget && this.monitoringTarget.setup()); - }).then(() => { - const setups = []; - this.topicParticipants.forEach((tp) => { - setups.push(tp.setup()); + .then((ch) => { + this.channel = ch; + this.channel.on('error', (e) => { + log.warn('Channel closed:', e); + this.channel = null; }); - return Promise.all(setups); - }).catch((e) => { - log.warn('Error after reconnect:', e); + if (!this.connected) { + this.connected = true; + this.successCb(); + } else { + Promise.resolve().then(() => { + return (this.rpcServer && this.rpcServer.setup()); + }).then(() => { + return (this.rpcClient && this.rpcClient.setup()); + }).then(() => { + return (this.monitor && this.monitor.setup()); + }).then(() => { + return (this.monitoringTarget && this.monitoringTarget.setup()); + }).then(() => { + const setups = []; + this.topicParticipants.forEach((tp) => { + setups.push(tp.setup()); + }); + return Promise.all(setups); + }).catch((e) => { + log.warn('Error after reconnect:', e); + }); + } }) - } - }) - .catch(this._errorHandler); + .catch(this._errorHandler); } _errorHandler(err) { @@ -499,8 +500,8 @@ class AmqpCli { if (!this.rpcClient) { this.rpcClient = new RpcClient(this); this.rpcClient.setup() - .then(() => onOk(this.rpcClient)) - .catch(onFailure); + .then(() => onOk(this.rpcClient)) + .catch(onFailure); } else { log.warn('RpcClient already setup'); onOk(this.rpcServer); @@ -511,8 +512,8 @@ class AmqpCli { if (!this.rpcServer) { this.rpcServer = new RpcServer(this, id, methods); this.rpcServer.setup() - .then(() => onOk(this.rpcServer)) - .catch(onFailure); + .then(() => onOk(this.rpcServer)) + .catch(onFailure); } else { log.warn('RpcServer already setup'); onOk(this.rpcServer); @@ -523,8 +524,8 @@ class AmqpCli { if (!this.monitor) { this.monitor = new Monitor(this, messageReceiver); this.monitor.setup() - .then(() => onOk(this.monitor)) - .catch(onFailure); + .then(() => onOk(this.monitor)) + .catch(onFailure); } else { log.warn('Monitor already setup'); onOk(this.rpcServer); @@ -536,8 +537,8 @@ class AmqpCli { this.monitoringTarget = new MonitoringTarget(this); this.monitoringTarget.setup() - .then(() => onOk(this.monitoringTarget)) - .catch(onFailure); + .then(() => onOk(this.monitoringTarget)) + .catch(onFailure); } else { log.warn('MonitoringTarget already setup'); onOk(this.rpcServer); @@ -549,13 +550,12 @@ class AmqpCli { const topicParticipant = new TopicParticipant(this, group); topicParticipant.setup() - .then(() => { - this.topicParticipants.set(group, topicParticipant); - onOk(topicParticipant); - }) - .catch(onFailure); - } - else { + .then(() => { + this.topicParticipants.set(group, topicParticipant); + onOk(topicParticipant); + }) + .catch(onFailure); + } else { log.warn('TopicParticipant already setup for:', group); onOk(this.topicParticipants.get(group)); } @@ -596,7 +596,7 @@ class AmqpCli { } } -module.exports = function () { +module.exports = function() { const amqpCli = new AmqpCli(); return amqpCli; }; diff --git a/source/common/cipher.js b/source/common/cipher.js index 228140704..a43214a69 100644 --- a/source/common/cipher.js +++ b/source/common/cipher.js @@ -4,56 +4,58 @@ 'use strict'; -var crypto = require('crypto'); -var algorithm = 'aes-256-ctr'; -var stream = require('stream'); -var fs = require('fs'); -var zlib = require('zlib'); -var iv = Buffer.from('3a613563c433a361a62a9efe4dd8462e', 'hex'); +const crypto = require('crypto'); +const algorithm = 'aes-256-ctr'; +const stream = require('stream'); +const fs = require('fs'); +const zlib = require('zlib'); +const iv = Buffer.from('3a613563c433a361a62a9efe4dd8462e', 'hex'); -function encrypt (password, text){ - var cipher = crypto.createCipheriv(algorithm, password, iv); - var enc = cipher.update(text, 'utf8', 'hex'); +function encrypt(password, text) { + const cipher = crypto.createCipheriv(algorithm, password, iv); + let enc = cipher.update(text, 'utf8', 'hex'); enc += cipher.final('hex'); return enc; } - -function decrypt (password, text){ - var decipher = crypto.createDecipheriv(algorithm, password, iv); - var dec = decipher.update(text, 'hex', 'utf8'); + +function decrypt(password, text) { + const decipher = crypto.createDecipheriv(algorithm, password, iv); + let dec = decipher.update(text, 'hex', 'utf8'); dec += decipher.final('utf8'); return dec; } -function lock (password, object, filename, cb) { - var s = new stream.Readable(); +function lock(password, object, filename, cb) { + const s = new stream.Readable(); s._read = function noop() {}; s.push(JSON.stringify(object)); s.push(null); - var out = fs.createWriteStream(filename); - out.on('error', function (e) { + const out = fs.createWriteStream(filename); + out.on('error', function(e) { cb(e); }); - out.on('finish', function () { + out.on('finish', function() { cb(null); }); - s.pipe(zlib.createGzip()).pipe(crypto.createCipheriv(algorithm, password, iv)).pipe(out); + s.pipe(zlib.createGzip()) + .pipe(crypto.createCipheriv(algorithm, password, iv)) + .pipe(out); } -function unlock (password, filename, cb) { - var s = fs.createReadStream(filename); - s.on('error', function (e) { +function unlock(password, filename, cb) { + const s = fs.createReadStream(filename); + s.on('error', function(e) { cb(e); }); - var unzip = zlib.createGunzip(); - var buf = ''; - unzip.on('data', function (chunk) { + const unzip = zlib.createGunzip(); + let buf = ''; + unzip.on('data', function(chunk) { buf += chunk.toString(); }); - unzip.on('end', function () { + unzip.on('end', function() { cb(null, JSON.parse(buf)); }); - unzip.on('error', function (e) { + unzip.on('error', function(e) { cb(e); }); s.pipe(crypto.createDecipheriv(algorithm, password, iv)).pipe(unzip); @@ -63,9 +65,11 @@ module.exports = { encrypt: encrypt, decrypt: decrypt, // Replace k with your key generator - k: Buffer.from('3d84a1efc77268c98bc6ca2921eb35a6d82a40a38696d25fbb64ff1733cd2523', 'hex'), + k: Buffer.from( + '3d84a1efc77268c98bc6ca2921eb35a6d82a40a38696d25fbb64ff1733cd2523', + 'hex'), astore: '.owt.authstore', kstore: '.owt.keystore', lock: lock, - unlock: unlock + unlock: unlock, }; diff --git a/source/common/clusterWorker.js b/source/common/clusterWorker.js index dcd414225..f16ea03eb 100644 --- a/source/common/clusterWorker.js +++ b/source/common/clusterWorker.js @@ -4,248 +4,263 @@ 'use strict'; -var logger = require('./logger').logger; -var makeRPC = require('./makeRPC').makeRPC; -var loadCollector = require('./loadCollector').LoadCollector; +const logger = require('./logger').logger; +const makeRPC = require('./makeRPC').makeRPC; +const loadCollector = require('./loadCollector').LoadCollector; // Logger -var log = logger.getLogger('ClusterWorker'); +const log = logger.getLogger('ClusterWorker'); -var genID = (function() { - function s4() { - return Math.floor((1 + Math.random()) * 0x10000) - .toString(16) - .substring(1); - } - return function() { - return s4() + s4() - /*+ '-' + s4() +const genID = (function() { + function s4() { + return Math.floor((1 + Math.random()) * 0x10000) + .toString(16) + .substring(1); + } + return function() { + return s4() + s4() + + /* + '-' + s4() + '-' + s4() + '-' + s4() - + '-'*/ + s4() + s4() + s4(); - }; + + '-'*/ s4() + s4() + s4(); + }; })(); -module.exports = function (spec) { - var that = {}; - - /*'unregistered' | 'registered' | 'recovering'*/ - var state = 'unregistered', - tasks = []; - - var rpcClient = spec.rpcClient, - id = spec.purpose + '-' + genID() + '@' + (spec.info.hostname || spec.info.ip), - purpose = spec.purpose, - info = spec.info, - cluster_name = spec.clusterName || 'owt-cluster', - join_retry = spec.joinRetry || 60, - keep_alive_period = 800/*MS*/, - keep_alive_interval = undefined, - on_join_ok = spec.onJoinOK || function () {log.debug('Join cluster successfully.');}, - on_join_failed = spec.onJoinFailed || function (reason) {log.debug('Join cluster failed. reason:', reason);}, - on_loss = spec.onLoss || function () {log.debug('Lost connection with cluster manager');}, - on_recovery = spec.onRecovery || function () {log.debug('Rejoin cluster successfully.');}, - on_overload = spec.onOverload || function () {log.debug('Overloaded!!');};; - - var previous_load = 0.99; - var reportLoad = function (load) { - if (load == previous_load) { - return; - } - previous_load = load; - if (state === 'registered') { - rpcClient.remoteCast( - cluster_name, - 'reportLoad', - [id, load]); - } +module.exports = function(spec) { + const that = {}; + + /* 'unregistered' | 'registered' | 'recovering'*/ + let state = 'unregistered'; + let tasks = []; + + const rpcClient = spec.rpcClient; + const id = spec.purpose + '-' + genID() + '@' + + (spec.info.hostname || spec.info.ip); + const purpose = spec.purpose; + const info = spec.info; + const cluster_name = spec.clusterName || 'owt-cluster'; + const join_retry = spec.joinRetry || 60; + const keep_alive_period = 800/* MS*/; + let keep_alive_interval = undefined; + const on_join_ok = spec.onJoinOK || function() { + log.debug('Join cluster successfully.'); + }; + const on_join_failed = spec.onJoinFailed || function(reason) { + log.debug('Join cluster failed. reason:', reason); + }; + const on_loss = spec.onLoss || function() { + log.debug('Lost connection with cluster manager'); + }; + const on_recovery = spec.onRecovery || function() { + log.debug('Rejoin cluster successfully.'); + }; + const on_overload = spec.onOverload || function() { + log.debug('Overloaded!!'); + }; + + let previous_load = 0.99; + const reportLoad = function(load) { + if (load == previous_load) { + return; + } + previous_load = load; + if (state === 'registered') { + rpcClient.remoteCast( + cluster_name, + 'reportLoad', + [id, load]); + } + + if ( + load > 0.98 + /* FIXME: Introduce a configuration item to specify the overload threshold here.*/ + ) { + on_overload(); + } + }; + + const load_collector = loadCollector({period: spec.loadCollection.period, + item: spec.loadCollection.item, + onLoad: reportLoad}); + + const join = function(on_ok, on_failed) { + makeRPC( + rpcClient, + cluster_name, + 'join', + [purpose, id, info], + function(result) { + state = 'registered'; + on_ok(result); + previous_load = 0.99; + keepAlive(); + }, on_failed); + }; - if (load > 0.98/*FIXME: Introduce a configuration item to specify the overload threshold here.*/) { - on_overload(); + const joinCluster = function(attempt) { + const tryJoin = function(countDown) { + log.debug('Try joining cluster', cluster_name, + ', retry count:', attempt - countDown); + join(function() { + on_join_ok(id); + log.info('Join cluster', cluster_name, 'OK.'); + }, function(error_reason) { + if (state === 'unregistered') { + log.info('Join cluster', cluster_name, 'failed.'); + if (countDown <= 0) { + log.error('Join cluster', cluster_name, + 'failed. reason:', error_reason); + on_join_failed(error_reason); + } else { + setTimeout(function() { + tryJoin(countDown - 1); + }, keep_alive_period); + } } + }); }; - var load_collector = loadCollector({period: spec.loadCollection.period, - item: spec.loadCollection.item, - onLoad: reportLoad}); - - var join = function (on_ok, on_failed) { - makeRPC( - rpcClient, - cluster_name, - 'join', - [purpose, id, info], - function (result) { - state = 'registered'; - on_ok(result); - previous_load = 0.99; - keepAlive(); - }, on_failed); - }; + tryJoin(attempt); + }; + + const keepAlive = function() { + keep_alive_interval && clearInterval(keep_alive_interval); - var joinCluster = function (attempt) { - var countDown = attempt; - - var tryJoin = function (countDown) { - log.debug('Try joining cluster', cluster_name, ', retry count:', attempt - countDown); - join(function (result) { - on_join_ok(id); - log.info('Join cluster', cluster_name, 'OK.'); - }, function (error_reason) { - if (state === 'unregistered') { - log.info('Join cluster', cluster_name, 'failed.'); - if (countDown <= 0) { - log.error('Join cluster', cluster_name, 'failed. reason:', error_reason); - on_join_failed(error_reason); - } else { - setTimeout(function () { - tryJoin(countDown - 1); - }, keep_alive_period); - } - } - }); - }; - - tryJoin(attempt); + const tryRecovery = function(on_success) { + clearInterval(keep_alive_interval); + keep_alive_interval = undefined; + state = 'recovering'; + + const tryJoining = function() { + log.debug('Try rejoining cluster', cluster_name, '....'); + join(function(result) { + log.debug('Rejoining result', result); + if (result === 'initializing') { + tasks.length > 0 && pickUpTasks(tasks); + } else { + on_loss(); + tasks = []; + } + on_success(); + }, function(reason) { + setTimeout(function() { + if (state === 'recovering') { + log.debug('Rejoin cluster', cluster_name, + 'failed. reason:', reason); + tryJoining(); + } + }, keep_alive_period); + }); + }; + + tryJoining(); }; - var keepAlive = function () { - keep_alive_interval && clearInterval(keep_alive_interval); - - var tryRecovery = function (on_success) { - clearInterval(keep_alive_interval); - keep_alive_interval = undefined; - state = 'recovering'; - - var tryJoining = function () { - log.debug('Try rejoining cluster', cluster_name, '....'); - join(function (result) { - log.debug('Rejoining result', result); - if (result === 'initializing') { - tasks.length > 0 && pickUpTasks(tasks); - } else { - on_loss(); - tasks = []; - } - on_success(); - }, function (reason) { - setTimeout(function() { - if (state === 'recovering') { - log.debug('Rejoin cluster', cluster_name, 'failed. reason:', reason); - tryJoining(); - } - }, keep_alive_period); + let loss_count = 0; + keep_alive_interval = setInterval(function() { + makeRPC( + rpcClient, + cluster_name, + 'keepAlive', + [id], + function(result) { + loss_count = 0; + if (result === 'whoareyou') { + if (state !== 'recovering') { + log.info('Unknown by cluster manager', cluster_name); + tryRecovery(function() { + log.info('Rejoin cluster', cluster_name, 'OK.'); }); - }; - - tryJoining(); - }; - - var loss_count = 0; - keep_alive_interval = setInterval(function () { - makeRPC( - rpcClient, - cluster_name, - 'keepAlive', - [id], - function (result) { - loss_count = 0; - if (result === 'whoareyou') { - if (state !== 'recovering') { - log.info('Unknown by cluster manager', cluster_name); - tryRecovery(function () { - log.info('Rejoin cluster', cluster_name, 'OK.'); - }); - } - } - }, function (error_reason) { - loss_count += 1; - if (loss_count > 3) { - if (state !== 'recovering') { - log.info('Lost connection with cluster', cluster_name); - tryRecovery(function () { - log.info('Rejoin cluster', cluster_name, 'OK.'); - on_recovery(id); - }); - } - } + } + } + }, function() { + loss_count += 1; + if (loss_count > 3) { + if (state !== 'recovering') { + log.info('Lost connection with cluster', cluster_name); + tryRecovery(function() { + log.info('Rejoin cluster', cluster_name, 'OK.'); + on_recovery(id); }); - }, keep_alive_period); - }; + } + } + }); + }, keep_alive_period); + }; - var pickUpTasks = function (taskList) { - rpcClient.remoteCast( - cluster_name, - 'pickUpTasks', - [id, taskList]); - }; + const pickUpTasks = function(taskList) { + rpcClient.remoteCast( + cluster_name, + 'pickUpTasks', + [id, taskList]); + }; - var layDownTask = function (task) { - rpcClient.remoteCast( - cluster_name, - 'layDownTask', - [id, task]); - }; + const layDownTask = function(task) { + rpcClient.remoteCast( + cluster_name, + 'layDownTask', + [id, task]); + }; - var doRejectTask = function (task) { - rpcClient.remoteCast( - cluster_name, - 'unschedule', - [id, task]); - }; + const doRejectTask = function(task) { + rpcClient.remoteCast( + cluster_name, + 'unschedule', + [id, task]); + }; - that.quit = function () { - if (state === 'registered') { - if (keep_alive_interval) { - clearInterval(keep_alive_interval); - keep_alive_interval = undefined; - } + that.quit = function() { + if (state === 'registered') { + if (keep_alive_interval) { + clearInterval(keep_alive_interval); + keep_alive_interval = undefined; + } - rpcClient.remoteCast( - cluster_name, - 'quit', - [id]); - } else if (state === 'recovering') { - keep_alive_interval && clearInterval(keep_alive_interval); - } + rpcClient.remoteCast( + cluster_name, + 'quit', + [id]); + } else if (state === 'recovering') { + keep_alive_interval && clearInterval(keep_alive_interval); + } - load_collector && load_collector.stop(); - }; + load_collector && load_collector.stop(); + }; - that.reportState = function (st) { - if (state === 'registered') { - rpcClient.remoteCast( - cluster_name, - 'reportState', - [id, st]); - } - }; + that.reportState = function(st) { + if (state === 'registered') { + rpcClient.remoteCast( + cluster_name, + 'reportState', + [id, st]); + } + }; - that.addTask = function (task) { - var i = tasks.indexOf(task); - if (i === -1) { - tasks.push(task); - if (state === 'registered') { - pickUpTasks([task]); - } - } - }; + that.addTask = function(task) { + const i = tasks.indexOf(task); + if (i === -1) { + tasks.push(task); + if (state === 'registered') { + pickUpTasks([task]); + } + } + }; - that.removeTask = function (task) { - var i = tasks.indexOf(task); - if (i !== -1) { - tasks.splice(i, 1); - if (state === 'registered') { - layDownTask(task); - } - } - }; + that.removeTask = function(task) { + const i = tasks.indexOf(task); + if (i !== -1) { + tasks.splice(i, 1); + if (state === 'registered') { + layDownTask(task); + } + } + }; - that.rejectTask = function (task) { - doRejectTask(task); - }; + that.rejectTask = function(task) { + doRejectTask(task); + }; - joinCluster(join_retry); - return that; + joinCluster(join_retry); + return that; }; diff --git a/source/common/loadCollector.js b/source/common/loadCollector.js index 67a19c50d..3a4e59eaf 100644 --- a/source/common/loadCollector.js +++ b/source/common/loadCollector.js @@ -4,203 +4,222 @@ 'use strict'; -var logger = require('./logger').logger; +const logger = require('./logger').logger; // Logger -var log = logger.getLogger('LoadCollector'); - -var child_process = require('child_process'); -var os = require('os'); - -var cpuCollector = function (period, onLoad) { - var olds = os.cpus(); - var begin = 0; - var end = olds.length - 1; - var interval = setInterval(function() { - var cpus = os.cpus(); - var idle = 0; - var total = 0; - for (let i = begin; i <= end; i++) { - for (let key in cpus[i].times) { - let diff = cpus[i].times[key] - olds[i].times[key]; - if (key === 'idle') { - idle += diff; - } - total += diff; - } +const log = logger.getLogger('LoadCollector'); + +const child_process = require('child_process'); +const os = require('os'); + +const cpuCollector = function(period, onLoad) { + let olds = os.cpus(); + const begin = 0; + const end = olds.length - 1; + const interval = setInterval(function() { + const cpus = os.cpus(); + let idle = 0; + let total = 0; + for (let i = begin; i <= end; i++) { + for (const key in cpus[i].times) { + const diff = cpus[i].times[key] - olds[i].times[key]; + if (key === 'idle') { + idle += diff; } - olds = cpus; - onLoad(1 - idle/total); - log.debug('cpu usage:', 1 - idle/total); - }, period); - - this.stop = function () { - log.debug("To stop cpu load collector."); - clearInterval(interval); - }; + total += diff; + } + } + olds = cpus; + onLoad(1 - idle/total); + log.debug('cpu usage:', 1 - idle/total); + }, period); + + this.stop = function() { + log.debug('To stop cpu load collector.'); + clearInterval(interval); + }; }; -var memCollector = function (period, onLoad) { - var interval = setInterval(function() { - var usage = 1 - os.freemem() / os.totalmem(); - onLoad(usage); - log.debug('mem usage:', usage); - }, period); - - this.stop = function () { - log.debug("To mem cpu load collector."); - clearInterval(interval); - }; +const memCollector = function(period, onLoad) { + const interval = setInterval(function() { + const usage = 1 - os.freemem() / os.totalmem(); + onLoad(usage); + log.debug('mem usage:', usage); + }, period); + + this.stop = function() { + log.debug('To mem cpu load collector.'); + clearInterval(interval); + }; }; -var diskCollector = function (period, drive, on_load) { - var interval = setInterval(function () { - var total = 1, free = 0; - child_process.exec("df -k '" + drive.replace(/'/g,"'\\''") + "'", function(err, stdout, stderr) { - if (err) { - log.error(stderr); - } else { - var lines = stdout.trim().split('\n'); - - var str_disk_info = lines[lines.length - 1].replace( /[\s\n\r]+/g,' '); - var disk_info = str_disk_info.split(' '); - - total = disk_info[1]; - free = disk_info[3]; - on_load(Math.round((1.0 - free / total) * 1000) / 1000); - } +const diskCollector = function(period, drive, on_load) { + const interval = setInterval(function() { + let total = 1; let free = 0; + child_process.exec('df -k \'' + drive.replace(/'/g, '\'\\\'\'') + '\'', + function(err, stdout, stderr) { + if (err) { + log.error(stderr); + } else { + const lines = stdout.trim().split('\n'); + + const str_disk_info = + lines[lines.length - 1].replace( /[\s\n\r]+/g, ' '); + const disk_info = str_disk_info.split(' '); + + total = disk_info[1]; + free = disk_info[3]; + on_load(Math.round((1.0 - free / total) * 1000) / 1000); + } }); - }, period); + }, period); - this.stop = function () { - log.debug("To stop disk load collector."); - clearInterval(interval); - }; + this.stop = function() { + log.debug('To stop disk load collector.'); + clearInterval(interval); + }; }; -var networkCollector = function (period, interf, max_scale, on_load) { - var rx_Mbps = 0, tx_Mbps = 0, rx_bytes = 0, tx_bytes = 0; - var meter = setInterval(function () { - child_process.exec("awk 'NR>2{if (index($1, \"" + interf + "\")==1){print $2, $10}}' /proc/net/dev", function (err, stdout, stderr) { - if (err) { - log.error(stderr); - } else { - var fields = stdout.trim().split(" "); - if (fields.length < 2) { - return log.warn('not ordinary network load data'); - } - var rx = Number(fields[0]), tx = Number(fields[1]); - if (rx >= rx_bytes && rx_bytes > 0) { - rx_Mbps = Math.round(((rx - rx_bytes) * 8 / 1048576) * 1000) / 1000; - } - - if (tx >= tx_bytes && tx_bytes > 0) { - tx_Mbps = Math.round(((tx - tx_bytes) * 8 / 1048576) * 1000) / 1000; - } - - rx_bytes = rx; - tx_bytes = tx; +const networkCollector = function(period, interf, max_scale, on_load) { + let rx_Mbps = 0; let tx_Mbps = 0; let rx_bytes = 0; let tx_bytes = 0; + let meter = setInterval(function() { + child_process.exec( + 'awk \'NR>2{if (index($1, "' + + interf + '")==1){print $2, $10}}\' /proc/net/dev', + function(err, stdout, stderr) { + if (err) { + log.error(stderr); + } else { + const fields = stdout.trim().split(' '); + if (fields.length < 2) { + return log.warn('not ordinary network load data'); + } + const rx = Number(fields[0]); const tx = Number(fields[1]); + if (rx >= rx_bytes && rx_bytes > 0) { + rx_Mbps = + Math.round(((rx - rx_bytes) * 8 / 1048576) * 1000) / 1000; } - }); - }, 1000); - - var reporter = setInterval(function () { - var rt_load = Math.round(Math.max(rx_Mbps / max_scale, tx_Mbps / max_scale) * 1000) / 1000; - on_load(rt_load); - }, period); - - this.stop = function () { - log.debug("To stop network load collector."); - meter && clearInterval(meter); - reporter && clearInterval(reporter); - meter = undefined; - reporter = undefined; - }; -}; -var gpuCollector = function (period, on_load) { - var child = child_process.exec('stdbuf -o0 metrics_monitor 100 1000'); - var cpu_load = 0, - cpu_collector = new cpuCollector(period, function (data) {cpu_load = data;}); - - var load = 0; - child.stdout.on('data', function (data) { - var usage_sum = 0, samples = 0; - var lines = data.toString().split('\n'); - - var i = lines.length > 10 ? lines.length - 10 : 0; - for (; i < lines.length; i++) { - var engine_list = lines[i].split('\t'); - var engine_max_usage = 0; - for (var engine of engine_list) { - var m = null; - if ((m = engine.match(/\s+usage:\s+(\d+\.\d+)/)) && m !== null && m.length > 1) { - var engine_usage = Number(m[1]); - if (engine_max_usage < engine_usage) - engine_max_usage = engine_usage; - } + if (tx >= tx_bytes && tx_bytes > 0) { + tx_Mbps = + Math.round(((tx - tx_bytes) * 8 / 1048576) * 1000) / 1000; } - usage_sum = usage_sum + engine_max_usage; - samples = samples + 1; - } - if (samples > 0) - load = (usage_sum / samples) / 100; - else - load = 0; - }); - - var interval = setInterval(function () { - var result = Math.max(load, cpu_load); - on_load(result); - }, period); - - this.stop = function () { - log.debug("To stop gpu load collector."); - cpu_collector && cpu_collector.stop(); - cpu_collector = undefined; - child && child.kill(); - child = undefined; - interval && clearInterval(interval); - interval = undefined; - }; + rx_bytes = rx; + tx_bytes = tx; + } + }); + }, 1000); + + let reporter = setInterval(function() { + const rt_load = + Math.round( + Math.max(rx_Mbps / max_scale, tx_Mbps / max_scale) * 1000) / 1000; + on_load(rt_load); + }, period); + + this.stop = function() { + log.debug('To stop network load collector.'); + meter && clearInterval(meter); + reporter && clearInterval(reporter); + meter = undefined; + reporter = undefined; + }; }; -exports.LoadCollector = function (spec) { - var that = {}; - - var period = spec.period || 1000, - item = spec.item, - on_load = spec.onLoad || function (load) {log.debug('Got', item.name, 'load:', load);}, - collector = undefined; - - that.stop = function () { - log.info("To stop load collector."); - collector && collector.stop(); - collector = undefined; - }; - - switch (item.name) { - case 'network': - collector = new networkCollector(period, item.interf, item.max_scale, on_load); - break; - case 'cpu': - collector = new cpuCollector(period, on_load); - break; - case 'gpu': - collector = new gpuCollector(period, on_load); - break; - case 'memory': - collector = new memCollector(period, on_load); - break; - case 'disk': - collector = new diskCollector(period, item.drive, on_load); - break; - default: - log.error('Unknown load item'); - return undefined; - //break; +const gpuCollector = function(period, on_load) { + let child = child_process.exec('stdbuf -o0 metrics_monitor 100 1000'); + let cpu_load = 0; + let cpu_collector = new cpuCollector(period, function(data) { + cpu_load = data; + }); + + let load = 0; + child.stdout.on('data', function(data) { + let usage_sum = 0; let samples = 0; + const lines = data.toString().split('\n'); + + let i = lines.length > 10 ? lines.length - 10 : 0; + for (; i < lines.length; i++) { + const engine_list = lines[i].split('\t'); + let engine_max_usage = 0; + for (const engine of engine_list) { + let m = null; + if ( + (m = engine.match(/\s+usage:\s+(\d+\.\d+)/)) && + m !== null && m.length > 1 + ) { + const engine_usage = Number(m[1]); + if (engine_max_usage < engine_usage) { + engine_max_usage = engine_usage; + } + } + } + usage_sum = usage_sum + engine_max_usage; + samples = samples + 1; + } + + if (samples > 0) { + load = (usage_sum / samples) / 100; + } else { + load = 0; } + }); + + let interval = setInterval(function() { + const result = Math.max(load, cpu_load); + on_load(result); + }, period); + + this.stop = function() { + log.debug('To stop gpu load collector.'); + cpu_collector && cpu_collector.stop(); + cpu_collector = undefined; + child && child.kill(); + child = undefined; + interval && clearInterval(interval); + interval = undefined; + }; +}; - return that; +exports.LoadCollector = function(spec) { + const that = {}; + + const period = spec.period || 1000; + const item = spec.item; + const on_load = spec.onLoad || function(load) { + log.debug('Got', item.name, 'load:', load); + }; + let collector = undefined; + + that.stop = function() { + log.info('To stop load collector.'); + collector && collector.stop(); + collector = undefined; + }; + + switch (item.name) { + case 'network': + collector = + new networkCollector(period, item.interf, item.max_scale, on_load); + break; + case 'cpu': + collector = new cpuCollector(period, on_load); + break; + case 'gpu': + collector = new gpuCollector(period, on_load); + break; + case 'memory': + collector = new memCollector(period, on_load); + break; + case 'disk': + collector = new diskCollector(period, item.drive, on_load); + break; + default: + log.error('Unknown load item'); + return undefined; + // break; + } + + return that; }; diff --git a/source/common/logger.js b/source/common/logger.js index 0a72c4851..dcbe07674 100644 --- a/source/common/logger.js +++ b/source/common/logger.js @@ -3,11 +3,11 @@ // SPDX-License-Identifier: Apache-2.0 'use strict'; -var log4js = require('log4js'); +const log4js = require('log4js'); log4js.configure('./log4js_configuration.json'); log4js.reconfigure = function() { log4js.configure('./log4js_configuration.json'); -} +}; exports.logger = log4js; diff --git a/source/common/makeRPC.js b/source/common/makeRPC.js index f51cc2ca4..a43ef04da 100644 --- a/source/common/makeRPC.js +++ b/source/common/makeRPC.js @@ -4,19 +4,28 @@ 'use strict'; -exports.makeRPC = function (rpcClient, remote_node, remote_function, parameters_list, on_ok, on_error) { +exports.makeRPC = + function( + rpcClient, + remote_node, + remote_function, + parameters_list, + on_ok, on_error, + ) { rpcClient.remoteCall( remote_node, remote_function, parameters_list, - {callback: function (result, error_reason) { - if (result === 'error') { - typeof on_error === 'function' && on_error(error_reason); - } else if (result === 'timeout') { - typeof on_error === 'function' && on_error('Timeout to make rpc to ' + remote_node + '.' + remote_function); - } else { - typeof on_ok === 'function' && on_ok(result); - } - }} + {callback: function(result, error_reason) { + if (result === 'error') { + typeof on_error === 'function' && on_error(error_reason); + } else if (result === 'timeout') { + typeof on_error === 'function' && + on_error('Timeout to make rpc to ' + remote_node + + '.' + remote_function); + } else { + typeof on_ok === 'function' && on_ok(result); + } + }}, ); -}; + }; diff --git a/source/common/rpcChannel.js b/source/common/rpcChannel.js index 91693150a..882144858 100644 --- a/source/common/rpcChannel.js +++ b/source/common/rpcChannel.js @@ -4,14 +4,14 @@ 'use strict'; -var RpcChannel = function(amqpClient) { - var that = {}; - var amqp_client = amqpClient; +const RpcChannel = function(amqpClient) { + const that = {}; + const amqp_client = amqpClient; - that.makeRPC = function (node, method, args, timeout, onStatus) { + that.makeRPC = function(node, method, args, timeout, onStatus) { return new Promise(function(resolve, reject) { - var callbacks = { - callback: function (result, error_reason) { + const callbacks = { + callback: function(result, error_reason) { if (result === 'error') { reject(error_reason ? error_reason : 'unknown reason'); } else if (result === 'timeout') { @@ -19,22 +19,21 @@ var RpcChannel = function(amqpClient) { } else { resolve(result); } - } + }, }; if (onStatus) { - callbacks.onStatus = function (status) { - onStatus(status).catch((e) => {}); + callbacks.onStatus = function(status) { + onStatus(status).catch(() => {}); }; } amqp_client.remoteCall( - node, - method, - args, - callbacks, - timeout - ); + node, + method, + args, + callbacks, + timeout); }); }; diff --git a/source/portal/client.js b/source/portal/client.js index 8817d3e77..eb2a3aa88 100644 --- a/source/portal/client.js +++ b/source/portal/client.js @@ -4,25 +4,25 @@ 'use strict'; -var log = require('./logger').logger.getLogger('Client'); -var ReqType = require('./versions/requestType'); -var dataAdapter = require('./versions/portalDataAdapter'); -const { v4: uuid } = require('uuid'); - -var idPattern = /^[0-9a-zA-Z\-]+$/; -function isValidIdString(str) { - return (typeof str === 'string') && idPattern.test(str); -} - -function safeCall () { - var callback = arguments[0]; +const log = require('./logger').logger.getLogger('Client'); +const ReqType = require('./versions/requestType'); +const dataAdapter = require('./versions/portalDataAdapter'); +const {v4: uuid} = require('uuid'); + +// var idPattern = /^[0-9a-zA-Z\-]+$/; +// function isValidIdString(str) { +// return (typeof str === 'string') && idPattern.test(str); +// } + +function safeCall(...args) { + const callback = args[0]; if (typeof callback === 'function') { - var args = Array.prototype.slice.call(arguments, 1); - callback.apply(null, args); + const callbackArgs = Array.prototype.slice.call(args, 1); + callback(...callbackArgs); } } -const getErrorMessage = function (err) { +const getErrorMessage = function(err) { if (typeof err === 'string') { return err; } else if (err && err.message) { @@ -33,13 +33,13 @@ const getErrorMessage = function (err) { } }; -var Client = function(clientId, sigConnection, portal, version) { - var that = { +const Client = function(clientId, sigConnection, portal, version) { + const that = { id: clientId, connection: sigConnection, - version: version + version: version, }; - var adapter = dataAdapter(version); + const adapter = dataAdapter(version); const sendMsg = (evt, data) => { that.connection.sendMessage(evt, data); @@ -53,7 +53,7 @@ var Client = function(clientId, sigConnection, portal, version) { }; }; - const idPattern = /^[0-9a-zA-Z\-]+$/; + const idPattern = /^[0-9a-zA-Z-]+$/; const validateId = (type, id) => { if ((typeof id === 'string') && idPattern.test(id)) { return Promise.resolve(id); @@ -68,139 +68,147 @@ var Client = function(clientId, sigConnection, portal, version) { const listenAt = (socket) => { socket.on('text', function(textReq, callback) { - if(!that.inRoom){ + if (!that.inRoom) { return safeCall(callback, 'error', 'Illegal request'); } return adapter.translateReq(ReqType.Text, textReq) - .then((req) => { - return portal.text(clientId, req.to, req.message); - }).then((result) => { - safeCall(callback, 'ok'); - }).catch(onError('text', callback)); + .then((req) => { + return portal.text(clientId, req.to, req.message); + }).then(() => { + safeCall(callback, 'ok'); + }).catch(onError('text', callback)); }); socket.on('publish', function(pubReq, callback) { - if(!that.inRoom){ + if (!that.inRoom) { return safeCall(callback, 'error', 'Illegal request'); } - //FIXME: move the id assignment to conference - var stream_id = uuidWithoutDash(); - var transportId; + // FIXME: move the id assignment to conference + const stream_id = uuidWithoutDash(); + let transportId; return adapter.translateReq(ReqType.Pub, pubReq) - .then((req) => { - if (req.transport && req.transport.type == 'quic') { - req.type = 'quic'; - if (!req.transport.id) { + .then((req) => { + if (req.transport && req.transport.type == 'quic') { + req.type = 'quic'; + if (!req.transport.id) { req.transport.id = uuidWithoutDash(); + } + transportId = req.transport.id; + } else { + req.type = 'webrtc'; // FIXME: For backend compatibility with v3.4 clients. + if (!req.transport || !req.transport.id) { + req.transport = {type: 'webrtc', id: stream_id}; + } } transportId = req.transport.id; - } else { - req.type = 'webrtc'; //FIXME: For backend compatibility with v3.4 clients. - if (!req.transport || !req.transport.id) { - req.transport = { type : 'webrtc', id : stream_id }; - } - } - transportId = req.transport.id; - return portal.publish(clientId, stream_id, req); - }).then((result) => { - safeCall(callback, 'ok', {id: stream_id, transportId}); - }).catch(onError('publish', callback)); + return portal.publish(clientId, stream_id, req); + }).then(() => { + safeCall(callback, 'ok', {id: stream_id, transportId}); + }).catch(onError('publish', callback)); }); socket.on('unpublish', function(unpubReq, callback) { - if(!that.inRoom){ + if (!that.inRoom) { return safeCall(callback, 'error', 'Illegal request'); } return validateId('stream id', unpubReq.id) - .then((streamId) => { - return portal.unpublish(clientId, streamId); - }).then((result) => { - safeCall(callback, 'ok'); - }).catch(onError('unpublish', callback)); + .then((streamId) => { + return portal.unpublish(clientId, streamId); + }).then(() => { + safeCall(callback, 'ok'); + }).catch(onError('unpublish', callback)); }); socket.on('stream-control', function(streamCtrlReq, callback) { - if(!that.inRoom){ + if (!that.inRoom) { return safeCall(callback, 'error', 'Illegal request'); } return adapter.translateReq(ReqType.StreamCtrl, streamCtrlReq) - .then((req) => { - return portal.streamControl(clientId, req.id, {operation: req.operation, data: req.data}); - }).then((result) => { - safeCall(callback, 'ok', result); - }).catch(onError('stream-control', callback)); + .then((req) => { + return portal.streamControl( + clientId, + req.id, + {operation: req.operation, data: req.data}, + ); + }).then((result) => { + safeCall(callback, 'ok', result); + }).catch(onError('stream-control', callback)); }); socket.on('subscribe', function(subReq, callback) { - if(!that.inRoom){ + if (!that.inRoom) { return safeCall(callback, 'error', 'Illegal request'); } - //FIXME: move the id assignment to conference - var subscription_id = uuidWithoutDash(); - var transportId; + // FIXME: move the id assignment to conference + const subscription_id = uuidWithoutDash(); + let transportId; return adapter.translateReq(ReqType.Sub, subReq) - .then((req) => { - if (req.transport && req.transport.type == 'quic') { - req.type = 'quic'; - if (!req.transport.id) { + .then((req) => { + if (req.transport && req.transport.type == 'quic') { + req.type = 'quic'; + if (!req.transport.id) { req.transport.id = uuidWithoutDash(); + } + transportId = req.transport.id; + } else { + req.type = 'webrtc'; // FIXME: For backend compatibility with v3.4 clients. + if (!req.transport || !req.transport.id) { + req.transport = {type: 'webrtc', id: subscription_id}; + } } transportId = req.transport.id; - } else { - req.type = 'webrtc'; //FIXME: For backend compatibility with v3.4 clients. - if (!req.transport || !req.transport.id) { - req.transport = { type : 'webrtc', id : subscription_id }; - } - } - transportId = req.transport.id; - return portal.subscribe(clientId, subscription_id, req); - }).then((result) => { - safeCall(callback, 'ok', {id: subscription_id, transportId}); - }).catch(onError('subscribe', callback)); + return portal.subscribe(clientId, subscription_id, req); + }).then(() => { + safeCall(callback, 'ok', {id: subscription_id, transportId}); + }).catch(onError('subscribe', callback)); }); socket.on('unsubscribe', function(unsubReq, callback) { - if(!that.inRoom){ + if (!that.inRoom) { return safeCall(callback, 'error', 'Illegal request'); } return validateId('subscription id', unsubReq.id) - .then((subscriptionId) => { - return portal.unsubscribe(clientId, subscriptionId); - }).then((result) => { - safeCall(callback, 'ok'); - }).catch(onError('unsubscribe', callback)); + .then((subscriptionId) => { + return portal.unsubscribe(clientId, subscriptionId); + }).then(() => { + safeCall(callback, 'ok'); + }).catch(onError('unsubscribe', callback)); }); socket.on('subscription-control', function(subCtrlReq, callback) { - if(!that.inRoom){ + if (!that.inRoom) { return safeCall(callback, 'error', 'Illegal request'); } return adapter.translateReq(ReqType.SubscriptionCtrl, subCtrlReq) - .then((req) => { - return portal.subscriptionControl(clientId, req.id, {operation: req.operation, data: req.data}); - }).then((result) => { - safeCall(callback, 'ok'); - }).catch(onError('subscription-control', callback)); + .then((req) => { + return portal.subscriptionControl( + clientId, + req.id, + {operation: req.operation, data: req.data}, + ); + }).then(() => { + safeCall(callback, 'ok'); + }).catch(onError('subscription-control', callback)); }); socket.on('soac', function(SOAC, callback) { - if(!that.inRoom){ + if (!that.inRoom) { return safeCall(callback, 'error', 'Illegal request'); } return adapter.translateReq(ReqType.SOAC, SOAC) - .then((soac) => { - return portal.onSessionSignaling(clientId, soac.id, soac.signaling); - }).then((result) => { - safeCall(callback, 'ok'); - }).catch(onError('soac', callback)); + .then((soac) => { + return portal.onSessionSignaling(clientId, soac.id, soac.signaling); + }).then(() => { + safeCall(callback, 'ok'); + }).catch(onError('soac', callback)); }); }; @@ -211,17 +219,17 @@ var Client = function(clientId, sigConnection, portal, version) { that.join = (token) => { return portal.join(clientId, token) - .then(function(result){ - that.inRoom = result.data.room.id; - that.tokenCode = result.tokenCode; - result.data.id = that.id; - const data = adapter.translateResp(ReqType.Join, result.data); - return data; - }) + .then(function(result) { + that.inRoom = result.data.room.id; + that.tokenCode = result.tokenCode; + result.data.id = that.id; + const data = adapter.translateResp(ReqType.Join, result.data); + return data; + }); }; that.leave = () => { - if(that.inRoom) { + if (that.inRoom) { return portal.leave(that.id).catch(() => { that.inRoom = undefined; that.tokenCode = undefined; diff --git a/source/portal/index.js b/source/portal/index.js index ad32d1e37..58c803a7f 100644 --- a/source/portal/index.js +++ b/source/portal/index.js @@ -2,36 +2,41 @@ // // SPDX-License-Identifier: Apache-2.0 -'use strict'; -var fs = require('fs'); -var toml = require('toml'); -var logger = require('./logger').logger; -var log = logger.getLogger('Main'); +const fs = require('fs'); +const toml = require('toml'); +const {logger} = require('./logger'); -var config; +const log = logger.getLogger('Main'); + +let config; try { config = toml.parse(fs.readFileSync('./portal.toml')); } catch (e) { - log.error('Parsing config error on line ' + e.line + ', column ' + e.column + ': ' + e.message); + log.error(`Parsing config error on line ${e.line}, + column ${e.column}: ${e.message}`); process.exit(1); } // Configuration default values config.portal = config.portal || {}; config.portal.ip_address = config.portal.ip_address || ''; -config.portal.hostname = config.portal.hostname|| ''; +config.portal.hostname = config.portal.hostname || ''; config.portal.port = config.portal.port || 8080; config.portal.via_host = config.portal.via_host || ''; config.portal.ssl = config.portal.ssl || false; config.portal.force_tls_v12 = config.portal.force_tls_v12 || false; -config.portal.reconnection_ticket_lifetime = config.portal.reconnection_ticket_lifetime || 600; -config.portal.reconnection_timeout = Number.isInteger(config.portal.reconnection_timeout) ? config.portal.reconnection_timeout : 60; +config.portal.reconnection_ticket_lifetime = + config.portal.reconnection_ticket_lifetime || 600; +config.portal.reconnection_timeout = + Number.isInteger(config.portal.reconnection_timeout) ? + config.portal.reconnection_timeout : 60; config.portal.cors = config.portal.cors || []; config.cluster = config.cluster || {}; config.cluster.name = config.cluster.name || 'owt-cluster'; config.cluster.join_retry = config.cluster.join_retry || 60; -config.cluster.report_load_interval = config.cluster.report_load_interval || 1000; +config.cluster.report_load_interval = + config.cluster.report_load_interval || 1000; config.cluster.max_load = config.cluster.max_load || 0.85; config.cluster.network_max_scale = config.cluster.network_max_scale || 1000; @@ -39,47 +44,46 @@ config.capacity = config.capacity || {}; config.capacity.isps = config.capacity.isps || []; config.capacity.regions = config.capacity.regions || []; - config.rabbit = config.rabbit || {}; config.rabbit.host = config.rabbit.host || 'localhost'; config.rabbit.port = config.rabbit.port || 5672; // Parse portal hostname and ip_address variables from ENV. if (config.portal.ip_address.indexOf('$') == 0) { - config.portal.ip_address = process.env[config.portal.ip_address.substr(1)]; - log.info('ENV: config.portal.ip_address=' + config.portal.ip_address); + config.portal.ip_address = process.env[config.portal.ip_address.substr(1)]; + log.info(`ENV: config.portal.ip_address=${config.portal.ip_address}`); } if (config.portal.hostname.indexOf('$') == 0) { - config.portal.hostname = process.env[config.portal.hostname.substr(1)]; - log.info('ENV: config.portal.hostname=' + config.portal.hostname); + config.portal.hostname = process.env[config.portal.hostname.substr(1)]; + log.info(`ENV: config.portal.hostname=${config.portal.hostname}`); } -if(process.env.owt_via_host !== undefined) { - config.portal.via_host = process.env.owt_via_host; - log.info('ENV: config.portal.via_address=' + config.portal.via_host); +if (process.env.owt_via_host !== undefined) { + config.portal.via_host = process.env.owt_via_host; + log.info(`ENV: config.portal.via_address=${config.portal.via_host}`); } global.config = config; +const amqper = require('./amqpClient')(); -var amqper = require('./amqpClient')(); -var rpcClient; -var socketio_server; -var portal; -var worker; +let rpcClient; +let socketio_server; +let portal; +let worker; -var ip_address; +let ip_address; (function getPublicIP() { - var BINDED_INTERFACE_NAME = config.portal.networkInterface; - var interfaces = require('os').networkInterfaces(), - addresses = [], - k, - k2, - address; + const BINDED_INTERFACE_NAME = config.portal.networkInterface; + const interfaces = require('os').networkInterfaces(); + const addresses = []; + let k; + let k2; + let address; for (k in interfaces) { - if (interfaces.hasOwnProperty(k)) { + if (Object.prototype.hasOwnProperty.call(interfaces, k)) { for (k2 in interfaces[k]) { - if (interfaces[k].hasOwnProperty(k2)) { + if (Object.prototype.hasOwnProperty.call(interfaces[k], k2)) { address = interfaces[k][k2]; if (address.family === 'IPv4' && !address.internal) { if (k === BINDED_INTERFACE_NAME || !BINDED_INTERFACE_NAME) { @@ -88,7 +92,7 @@ var ip_address; } if (address.family === 'IPv6' && !address.internal) { if (k === BINDED_INTERFACE_NAME || !BINDED_INTERFACE_NAME) { - addresses.push('[' + address.address + ']'); + addresses.push(`[${address.address}]`); } } } @@ -96,212 +100,236 @@ var ip_address; } } - if (config.portal.ip_address === '' || config.portal.ip_address === undefined){ + if ( + config.portal.ip_address === ''|| + config.portal.ip_address === undefined + ) { ip_address = addresses[0]; } else { ip_address = config.portal.ip_address; } -})(); +}()); -var dropAll = function() { +const dropAll = function() { socketio_server && socketio_server.drop('all'); }; -var getTokenKey = function(id, on_key, on_error) { - var dataAccess = require('./data_access'); - dataAccess.token.key(id).then(function (key) { +const getTokenKey = function(id, on_key, on_error) { + const dataAccess = require('./data_access'); + dataAccess.token.key(id).then((key) => { on_key(key); - }).catch(function (err) { - log.info('Failed to get token key. err:', (err && err.message) ? err.message : err); + }).catch((err) => { + log.info('Failed to get token key. err:', + (err && err.message) ? err.message : err); on_error(err); }); }; -var joinCluster = function (on_ok) { - var joinOK = on_ok; +const joinCluster = function(on_ok) { + const joinOK = on_ok; - var joinFailed = function (reason) { + const joinFailed = function(reason) { log.error('portal join cluster failed. reason:', reason); worker && worker.quit(); process.exit(); }; - var loss = function () { + const loss = function() { log.info('portal lost.'); dropAll(); }; - var recovery = function () { + const recovery = function() { log.info('portal recovered.'); }; - var spec = {rpcClient: rpcClient, - purpose: 'portal', - clusterName: config.cluster.name, - joinRetry: config.cluster.join_retry, - info: {ip: ip_address, - hostname: config.portal.hostname, - port: config.portal.port, - via_host: config.portal.via_host, - ssl: config.portal.ssl, - state: 2, - max_load: config.cluster.max_load, - capacity: config.capacity - }, - onJoinOK: joinOK, - onJoinFailed: joinFailed, - onLoss: loss, - onRecovery: recovery, - loadCollection: {period: config.cluster.report_load_interval, - item: {name: 'cpu'}} - }; + const spec = { + rpcClient, + purpose: 'portal', + clusterName: config.cluster.name, + joinRetry: config.cluster.join_retry, + info: { + ip: ip_address, + hostname: config.portal.hostname, + port: config.portal.port, + via_host: config.portal.via_host, + ssl: config.portal.ssl, + state: 2, + max_load: config.cluster.max_load, + capacity: config.capacity, + }, + onJoinOK: joinOK, + onJoinFailed: joinFailed, + onLoss: loss, + onRecovery: recovery, + loadCollection: { + period: config.cluster.report_load_interval, + item: {name: 'cpu'}, + }, + }; worker = require('./clusterWorker')(spec); }; -var refreshTokenKey = function(id, portal, tokenKey) { - var interval = setInterval(function() { - getTokenKey(id, function(newTokenKey) { +const refreshTokenKey = function(id, portal, tokenKey) { + const interval = setInterval(() => { + getTokenKey(id, (newTokenKey) => { (socketio_server === undefined) && clearInterval(interval); if (newTokenKey !== tokenKey) { log.info('Token key updated!'); portal.updateTokenKey(newTokenKey); tokenKey = newTokenKey; } - }, function() { + }, () => { (socketio_server === undefined) && clearInterval(interval); log.warn('Keep trying...'); }); }, 6 * 1000); }; -var serviceObserver = { - onJoin: function(tokenCode) { +const serviceObserver = { + onJoin(tokenCode) { worker && worker.addTask(tokenCode); }, - onLeave: function(tokenCode) { + onLeave(tokenCode) { worker && worker.removeTask(tokenCode); - } + }, }; -var startServers = function(id, tokenKey) { - var rpcChannel = require('./rpcChannel')(rpcClient); - var rpcReq = require('./rpcRequest')(rpcChannel); - - portal = require('./portal')({tokenKey: tokenKey, - tokenServer: 'ManagementApi', - clusterName: config.cluster.name, - selfRpcId: id}, - rpcReq); - socketio_server = require('./socketIOServer')({port: config.portal.port, - cors: config.portal.cors, - ssl: config.portal.ssl, - forceTlsv12: config.portal.force_tls_v12, - keystorePath: config.portal.keystorePath, - reconnectionTicketLifetime: config.portal.reconnection_ticket_lifetime, - reconnectionTimeout: config.portal.reconnection_timeout, - pingInterval: config.portal.ping_interval, - pingTimeout: config.portal.ping_timeout}, - portal, - serviceObserver); +const startServers = function(id, tokenKey) { + const rpcChannel = require('./rpcChannel')(rpcClient); + const rpcReq = require('./rpcRequest')(rpcChannel); + + portal = require('./portal')({ + tokenKey, + tokenServer: 'ManagementApi', + clusterName: config.cluster.name, + selfRpcId: id, + }, + rpcReq); + socketio_server = require('./socketIOServer')({ + port: config.portal.port, + cors: config.portal.cors, + ssl: config.portal.ssl, + forceTlsv12: config.portal.force_tls_v12, + keystorePath: config.portal.keystorePath, + reconnectionTicketLifetime: config.portal.reconnection_ticket_lifetime, + reconnectionTimeout: config.portal.reconnection_timeout, + pingInterval: config.portal.ping_interval, + pingTimeout: config.portal.ping_timeout, + }, + portal, + serviceObserver); return socketio_server.start() - .then(function() { - log.info('start socket.io server ok.'); - refreshTokenKey(id, portal, tokenKey); - }) - .catch(function(err) { - log.error('Failed to start servers, reason:', err && err.message); - throw err; - }); + .then(() => { + log.info('start socket.io server ok.'); + refreshTokenKey(id, portal, tokenKey); + }) + .catch((err) => { + log.error('Failed to start servers, reason:', err && err.message); + throw err; + }); }; -var stopServers = function() { +const stopServers = function() { socketio_server && socketio_server.stop(); socketio_server = undefined; worker && worker.quit(); worker = undefined; }; -var rpcPublic = { - drop: function(participantId, callback) { +const rpcPublic = { + drop(participantId, callback) { socketio_server && socketio_server.drop(participantId); callback('callback', 'ok'); }, - notify: function(participantId, event, data, callback) { + notify(participantId, event, data, callback) { // The "notify" is called on socket.io server, // but one client ID should not be exists in both servers, // there must be one failure, ignore this notify error here. - var notifyFail = (err) => {}; - socketio_server && socketio_server.notify(participantId, event, data).catch(notifyFail); + const notifyFail = () => {}; + socketio_server && + socketio_server.notify(participantId, event, data).catch(notifyFail); callback('callback', 'ok'); }, validateAndDeleteWebTransportToken: (token, callback) => { - if(portal.validateAndDeleteWebTransportToken(token)) { - callback('callback','ok'); + if (portal.validateAndDeleteWebTransportToken(token)) { + callback('callback', 'ok'); } else { callback('callback', 'error', 'Invalid token for WebTransport.'); } }, - broadcast: function(controller, excludeList, event, data, callback) { - socketio_server && socketio_server.broadcast(controller, excludeList, event, data); + broadcast(controller, excludeList, event, data, callback) { + socketio_server && + socketio_server.broadcast(controller, excludeList, event, data); callback('callback', 'ok'); - } + }, }; -amqper.connect(config.rabbit, function () { - amqper.asRpcClient(function(rpcClnt) { +amqper.connect(config.rabbit, () => { + amqper.asRpcClient((rpcClnt) => { rpcClient = rpcClnt; log.info('portal initializing as rpc client ok'); - joinCluster(function(id) { + joinCluster((id) => { log.info('portal join cluster ok, with rpcID:', id); - amqper.asRpcServer(id, rpcPublic, function(rpcSvr) { - log.info('portal initializing as rpc server ok'); - amqper.asMonitor(function (data) { - if (data.reason === 'abnormal' || data.reason === 'error' || data.reason === 'quit') { - if (portal !== undefined) { - if (data.message.purpose === 'conference') { - return portal.getParticipantsByController(data.message.type, data.message.id) - .then(function (impactedParticipants) { - impactedParticipants.forEach(function(participantId) { - log.error('Fault on conference controller(type:', data.message.type, 'id:', data.message.id, ') of participant', participantId, 'was detected, drop it.'); - socketio_server && socketio_server.drop(participantId); - }); + amqper.asRpcServer(id, rpcPublic, () => { + log.info('portal initializing as rpc server ok'); + amqper.asMonitor((data) => { + if ( + data.reason === 'abnormal' || + data.reason === 'error' || + data.reason === 'quit' + ) { + if (portal !== undefined) { + if (data.message.purpose === 'conference') { + return portal.getParticipantsByController(data.message.type, + data.message.id) + .then((impactedParticipants) => { + impactedParticipants.forEach((participantId) => { + log.error('Fault on conference controller(type:', + data.message.type, + 'id:', data.message.id, + ') of participant', participantId, + 'was detected, drop it.'); + socketio_server && socketio_server.drop(participantId); }); - } - } + }); } - }, function (monitor) { - log.info(id + ' as monitor ready'); - getTokenKey(id, function(tokenKey) { - startServers(id, tokenKey); - }, function() { - log.error('portal getting token failed.'); - stopServers(); - process.exit(); - }); - }, function(reason) { - log.error('portal initializing as rpc client failed, reason:', reason); - stopServers(); - process.exit(); - }); - }, function(reason) { + } + } + }, () => { + log.info(`${id} as monitor ready`); + getTokenKey(id, (tokenKey) => { + startServers(id, tokenKey); + }, () => { + log.error('portal getting token failed.'); + stopServers(); + process.exit(); + }); + }, (reason) => { + log.error('portal initializing as rpc client failed, reason:', + reason); + stopServers(); + process.exit(); + }); + }, (reason) => { log.error('portal initializing as rpc client failed, reason:', reason); stopServers(); process.exit(); }); }); - }, function(reason) { + }, (reason) => { log.error('portal initializing as rpc client failed, reason:', reason); stopServers(); process.exit(); }); -}, function(reason) { - log.error('portal connect to rabbitMQ server failed, reason:', reason); - process.exit(); +}, (reason) => { + log.error('portal connect to rabbitMQ server failed, reason:', reason); + process.exit(); }); -['SIGINT', 'SIGTERM'].map(function (sig) { - process.on(sig, async function () { +['SIGINT', 'SIGTERM'].map((sig) => { + process.on(sig, async () => { log.warn('Exiting on', sig); stopServers(); amqper.disconnect(); @@ -309,18 +337,18 @@ amqper.connect(config.rabbit, function () { }); }); -process.on('SIGPIPE', function () { +process.on('SIGPIPE', () => { log.warn('SIGPIPE!!'); }); -process.on('exit', function () { +process.on('exit', () => { log.info('Process exit'); }); process.on('unhandledRejection', (reason) => { - log.info('Reason: ' + reason); + log.info(`Reason: ${reason}`); }); -process.on('SIGUSR2', function () { +process.on('SIGUSR2', () => { logger.reconfigure(); }); diff --git a/source/portal/legacyClient.js b/source/portal/legacyClient.js index 24b9a1902..ed0ea602b 100644 --- a/source/portal/legacyClient.js +++ b/source/portal/legacyClient.js @@ -4,113 +4,67 @@ 'use strict'; -var url = require('url'); -var log = require('./logger').logger.getLogger('LegacyClient'); - -//FIXME: to keep compatible to previous MCU, should be removed later. -var resolutionName2Value = { - 'cif': {width: 352, height: 288}, - 'vga': {width: 640, height: 480}, - 'svga': {width: 800, height: 600}, - 'xga': {width: 1024, height: 768}, - 'r640x360': {width: 640, height: 360}, - 'hd720p': {width: 1280, height: 720}, - 'sif': {width: 320, height: 240}, - 'hvga': {width: 480, height: 320}, - 'r480x360': {width: 480, height: 360}, - 'qcif': {width: 176, height: 144}, - 'r192x144': {width: 192, height: 144}, - 'hd1080p': {width: 1920, height: 1080}, - 'uhd_4k': {width: 3840, height: 2160}, - 'r360x360': {width: 360, height: 360}, - 'r480x480': {width: 480, height: 480}, - 'r720x720': {width: 720, height: 720} +const url = require('url'); +const log = require('./logger').logger.getLogger('LegacyClient'); + +// FIXME: to keep compatible to previous MCU, should be removed later. +const resolutionName2Value = { + 'cif': {width: 352, height: 288}, + 'vga': {width: 640, height: 480}, + 'svga': {width: 800, height: 600}, + 'xga': {width: 1024, height: 768}, + 'r640x360': {width: 640, height: 360}, + 'hd720p': {width: 1280, height: 720}, + 'sif': {width: 320, height: 240}, + 'hvga': {width: 480, height: 320}, + 'r480x360': {width: 480, height: 360}, + 'qcif': {width: 176, height: 144}, + 'r192x144': {width: 192, height: 144}, + 'hd1080p': {width: 1920, height: 1080}, + 'uhd_4k': {width: 3840, height: 2160}, + 'r360x360': {width: 360, height: 360}, + 'r480x480': {width: 480, height: 480}, + 'r720x720': {width: 720, height: 720}, }; -var resolutionValue2Name = { - 'r352x288': 'cif', - 'r640x480': 'vga', - 'r800x600': 'svga', - 'r1024x768': 'xga', - 'r640x360': 'r640x360', - 'r1280x720': 'hd720p', - 'r320x240': 'sif', - 'r480x320': 'hvga', - 'r480x360': 'r480x360', - 'r176x144': 'qcif', - 'r192x144': 'r192x144', - 'r1920x1080': 'hd1080p', - 'r3840x2160': 'uhd_4k', - 'r360x360': 'r360x360', - 'r480x480': 'r480x480', - 'r720x720': 'r720x720' -}; - -function widthHeight2Resolution(width, height) { - var k = 'r' + width + 'x' + height; - return resolutionValue2Name[k] ? resolutionValue2Name[k] : k; -} - function resolution2WidthHeight(resolution) { - var r = resolution.indexOf('r'), - x = resolution.indexOf('x'), - w = (r === 0 && x > 1 ? Number(resolution.substring(1, x)) : 640), - h = (r === 0 && x > 1 ? Number(resolution.substring(x, resolution.length)) : 480); - return resolutionName2Value[resolution] ? resolutionName2Value[resolution] : {width: w, height: h}; + const r = resolution.indexOf('r'); + const x = resolution.indexOf('x'); + const w = (r === 0 && x > 1 ? Number(resolution.substring(1, x)) : 640); + const h = + (r === 0 && x > 1 ? + Number(resolution.substring(x, resolution.length)) : 480); + return resolutionName2Value[resolution] ? + resolutionName2Value[resolution] : {width: w, height: h}; } -var ql2brl = { +const ql2brl = { 'bestquality': 'x1.4', 'betterquality': 'x1.2', 'standard': undefined, 'betterspeed': 'x0.8', - 'bestspeed': 'x0.6' + 'bestspeed': 'x0.6', }; -function qualityLevel2BitrateLevel (ql) { +function qualityLevel2BitrateLevel(ql) { ql = ql.toLowerCase(); return ql2brl[ql] ? ql2brl[ql] : undefined; } -var idPattern = /^[0-9a-zA-Z\-]+$/; +const idPattern = /^[0-9a-zA-Z-]+$/; function isValidIdString(str) { return (typeof str === 'string') && idPattern.test(str); } -var formatDate = function(date, format) { - var dateTime = { - 'M+': date.getMonth() + 1, - 'd+': date.getDate(), - 'h+': date.getHours(), - 'm+': date.getMinutes(), - 's+': date.getSeconds(), - 'q+': Math.floor((date.getMonth() + 3) / 3), - 'S+': date.getMilliseconds() - }; - - if (/(y+)/i.test(format)) { - format = format.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)); - } - - for (var k in dateTime) { - if (new RegExp('(' + k + ')').test(format)) { - format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? - dateTime[k] : ('00' + dateTime[k]).substr(('' + dateTime[k]).length)); - } - } - - return format; -}; - -function safeCall () { - var callback = arguments[0]; +function safeCall(...args) { + const callback = args[0]; if (typeof callback === 'function') { - var args = Array.prototype.slice.call(arguments, 1); - callback.apply(null, args); + const callbackArgs = Array.prototype.slice.call(args, 1); + callback(...callbackArgs); } } -const getErrorMessage = function (err) { +const getErrorMessage = function(err) { if (typeof err === 'string') { return err; } else if (err && err.message) { @@ -121,19 +75,23 @@ const getErrorMessage = function (err) { } }; -var LegacyClient = function(clientId, sigConnection, portal) { - var that = { +const LegacyClient = function(clientId, sigConnection, portal) { + const that = { id: clientId, - connection: sigConnection + connection: sigConnection, }; - let published = {/*StreamId: {type: "webrtc" | "streamingIn", mix: boolean(IfMix)}*/}; //FIXME: for compatibility purpose for old clients(such as v3.4.x) - let ref2subId = {/*PeerId | StreamingOutURL | RecorderId: SubscriptionId}*/}; //FIXME: for compatibility purpose for old clients(such as v3.4.x) - let subId2ref = {/*SubscriptionId: PeerId | StreamingOutURL | RecorderId}*/}; //FIXME: for compatibility purpose for old clients(such as v3.4.x) + const published = + {/* StreamId: {type: "webrtc" | "streamingIn", mix: boolean(IfMix)}*/}; // FIXME: for compatibility purpose for old clients(such as v3.4.x) + const ref2subId = + {/* PeerId | StreamingOutURL | RecorderId: SubscriptionId}*/}; // FIXME: for compatibility purpose for old clients(such as v3.4.x) + const subId2ref = + {/* SubscriptionId: PeerId | StreamingOutURL | RecorderId}*/}; // FIXME: for compatibility purpose for old clients(such as v3.4.x) const getViewLabelFromStreamId = (streamId) => { - var bar_pos = streamId.indexOf("-"); - return ((bar_pos >= 0) && (bar_pos < (streamId.length - 1))) ? streamId.substring(bar_pos + 1) : streamId; + const bar_pos = streamId.indexOf('-'); + return ((bar_pos >= 0) && (bar_pos < (streamId.length - 1))) ? + streamId.substring(bar_pos + 1) : streamId; }; const sendMsg = (evt, data) => { @@ -142,30 +100,35 @@ var LegacyClient = function(clientId, sigConnection, portal) { const listenAt = (socket) => { socket.on('publish', function(options, url, callback) { - if(!that.inRoom){ + if (!that.inRoom) { return safeCall(callback, 'error', 'Illegal request'); } - var stream_id = Math.round(Math.random() * 1000000000000000000) + ''; - var pub_info = {}; + const stream_id = Math.round(Math.random() * 1000000000000000000) + ''; + const pub_info = {}; if (options.state === 'erizo') { pub_info.type = 'webrtc'; pub_info.media = { audio: (options.audio === false ? false : {source: 'mic'}), - video: (options.video === false ? false : {source: (options.video && options.video.device === 'screen') ? 'screen-cast' : 'camera', parameters: {framerate: 0}}) - } - pub_info.media.video && pub_info.media.video.parameters && (pub_info.media.video.parameters.resolution = {width: 0, height: 0}); + video: (options.video === false ? + false : { + source: (options.video && options.video.device === 'screen') ? + 'screen-cast' : 'camera', parameters: {framerate: 0}}), + }; + pub_info.media.video && pub_info.media.video.parameters && + (pub_info.media.video.parameters.resolution = + {width: 0, height: 0}); } else if (options.state === 'url') { pub_info.type = 'streaming'; pub_info.connection = { url: url, transportProtocol: options.transport || 'tcp', - bufferSize: options.bufferSize || 2048 + bufferSize: options.bufferSize || 2048, }; pub_info.media = { audio: (options.audio === undefined ? 'auto' : !!options.audio), - video: (options.video === undefined ? 'auto' : !!options.video) + video: (options.video === undefined ? 'auto' : !!options.video), }; } else { return safeCall(callback, 'error', 'stream type(options.state) error.'); @@ -174,84 +137,87 @@ var LegacyClient = function(clientId, sigConnection, portal) { options.attributes && (pub_info.attributes = options.attributes); return portal.publish(clientId, stream_id, pub_info) - .then(function(result) { - if (options.state === 'erizo') { - safeCall(callback, 'initializing', stream_id); - published[stream_id] = {type: 'webrtc', mix: !(options.unmix || (options.video && options.video.device === 'screen'))}; - } else { - safeCall(callback, 'success', stream_id); - published[stream_id] = {type: 'streamingIn', mix: !options.unmix}; - } - }) - .catch(function(err) { - const err_message = getErrorMessage(err); - log.info('portal.publish failed:', err_message); - safeCall(callback, 'error', err_message); - }); + .then(function() { + if (options.state === 'erizo') { + safeCall(callback, 'initializing', stream_id); + published[stream_id] = + {type: 'webrtc', + mix: !(options.unmix || + (options.video && options.video.device === 'screen'))}; + } else { + safeCall(callback, 'success', stream_id); + published[stream_id] = {type: 'streamingIn', mix: !options.unmix}; + } + }) + .catch(function(err) { + const err_message = getErrorMessage(err); + log.info('portal.publish failed:', err_message); + safeCall(callback, 'error', err_message); + }); }); socket.on('unpublish', function(streamId, callback) { - if(!that.inRoom){ + if (!that.inRoom) { return safeCall(callback, 'error', 'Illegal request'); } return portal.unpublish(clientId, streamId) - .then(function() { - safeCall(callback, 'success'); - published[streamId] && (delete published[streamId]); - }).catch(function(err) { - const err_message = getErrorMessage(err); - log.info('portal.unpublish failed:', err_message); - safeCall(callback, 'error', err_message); - }); + .then(function() { + safeCall(callback, 'success'); + published[streamId] && (delete published[streamId]); + }).catch(function(err) { + const err_message = getErrorMessage(err); + log.info('portal.unpublish failed:', err_message); + safeCall(callback, 'error', err_message); + }); }); socket.on('mix', function(options, callback) { - if(!that.inRoom){ + if (!that.inRoom) { return safeCall(callback, 'error', 'Illegal request'); } - var streamId = options.streamId; + const streamId = options.streamId; return Promise.all(options.mixStreams.map((mixStreamId) => { - var view_label = (getViewLabelFromStreamId(mixStreamId) || 'common'); - return portal.streamControl(clientId, - streamId, - { - operation: 'mix', - data: view_label - }); - })).then((result) => { - safeCall(callback, 'success'); - }).catch((err) => { - const err_message = getErrorMessage(err); - log.info('portal.mix failed:', err_message); - safeCall(callback, 'error', err_message); - }); + const view_label = (getViewLabelFromStreamId(mixStreamId) || 'common'); + return portal.streamControl(clientId, + streamId, + { + operation: 'mix', + data: view_label, + }); + })).then(() => { + safeCall(callback, 'success'); + }).catch((err) => { + const err_message = getErrorMessage(err); + log.info('portal.mix failed:', err_message); + safeCall(callback, 'error', err_message); + }); }); socket.on('unmix', function(options, callback) { - if(!that.inRoom){ + if (!that.inRoom) { return safeCall(callback, 'error', 'Illegal request'); } - var streamId = options.streamId; + const streamId = options.streamId; return Promise.all(options.mixStreams.map((mixStreamId) => { - var view_label = (getViewLabelFromStreamId(mixStreamId) || 'common'); - return portal.streamControl(clientId, - streamId, - { - operation: 'unmix', - data: view_label - }); - })).then((result) => { - safeCall(callback, 'success'); - }).catch((err) => { - const err_message = getErrorMessage(err); - log.info('portal.unmix failed:', err_message); - safeCall(callback, 'error', err_message); - }); + const view_label = (getViewLabelFromStreamId(mixStreamId) || 'common'); + return portal.streamControl(clientId, + streamId, + { + operation: 'unmix', + data: view_label, + }); + })).then(() => { + safeCall(callback, 'success'); + }).catch((err) => { + const err_message = getErrorMessage(err); + log.info('portal.unmix failed:', err_message); + safeCall(callback, 'error', err_message); + }); }); socket.on('setVideoBitrate', function(options, callback) { @@ -259,7 +225,7 @@ var LegacyClient = function(clientId, sigConnection, portal) { }); socket.on('subscribe', function(options, unused, callback) { - if(!that.inRoom){ + if (!that.inRoom) { return safeCall(callback, 'error', 'Illegal request'); } @@ -267,78 +233,96 @@ var LegacyClient = function(clientId, sigConnection, portal) { return safeCall(callback, 'error', 'Invalid stream id'); } - var peer_id = options.streamId; + const peer_id = options.streamId; if (ref2subId[peer_id]) { return safeCall(callback, 'error', 'Subscription is ongoing'); } - var subscription_id = Math.round(Math.random() * 1000000000000000000) + ''; + const subscription_id = + Math.round(Math.random() * 1000000000000000000) + ''; ref2subId[peer_id] = subscription_id; subId2ref[subscription_id] = peer_id; - var sub_desc = {type: 'webrtc', media: {}}; - (options.audio || options.audio === undefined) && (sub_desc.media.audio = {from: options.streamId}); - (options.video || options.video === undefined) && (sub_desc.media.video = {from: options.streamId}); - (options.video && options.video.resolution && (typeof options.video.resolution.width === 'number') && (typeof options.video.resolution.height === 'number')) && - (sub_desc.media.video.parameters || (sub_desc.media.video.parameters = {})) && (sub_desc.media.video.parameters.resolution = options.video.resolution); + const sub_desc = {type: 'webrtc', media: {}}; + (options.audio || options.audio === undefined) && + (sub_desc.media.audio = {from: options.streamId}); + (options.video || options.video === undefined) && + (sub_desc.media.video = {from: options.streamId}); + (options.video && options.video.resolution && + (typeof options.video.resolution.width === 'number') && + (typeof options.video.resolution.height === 'number')) && + (sub_desc.media.video.parameters || + (sub_desc.media.video.parameters = {})) && + (sub_desc.media.video.parameters.resolution = + options.video.resolution); options.video && (typeof options.video.resolution === 'string') && - (sub_desc.media.video.parameters || (sub_desc.media.video.parameters = {})) && (sub_desc.media.video.parameters.resolution = resolution2WidthHeight(options.video.resolution)); - options.video && options.video.quality_level && (sub_desc.media.video.parameters || (sub_desc.media.video.parameters = {})) && (sub_desc.media.video.parameters.bitrate = qualityLevel2BitrateLevel(options.video.quality_level)); + (sub_desc.media.video.parameters || + (sub_desc.media.video.parameters = {})) && + (sub_desc.media.video.parameters.resolution = + resolution2WidthHeight(options.video.resolution)); + options.video && options.video.quality_level && + (sub_desc.media.video.parameters || + (sub_desc.media.video.parameters = {})) && + (sub_desc.media.video.parameters.bitrate = + qualityLevel2BitrateLevel(options.video.quality_level)); if (!sub_desc.media.audio && !sub_desc.media.video) { - return safeCall(callback, 'error', 'bad options'); + return safeCall(callback, 'error', 'bad options'); } - return portal.subscribe(clientId, subscription_id, sub_desc - ).then(function(result) { - safeCall(callback, 'initializing', peer_id); - log.debug('portal.subscribe succeeded'); - }).catch(function(err) { - const err_message = getErrorMessage(err); - log.info('portal.subscribe failed:', err_message); - safeCall(callback, 'error', err_message); - }); + return portal.subscribe(clientId, subscription_id, sub_desc) + .then(function() { + safeCall(callback, 'initializing', peer_id); + log.debug('portal.subscribe succeeded'); + }).catch(function(err) { + const err_message = getErrorMessage(err); + log.info('portal.subscribe failed:', err_message); + safeCall(callback, 'error', err_message); + }); }); socket.on('unsubscribe', function(streamId, callback) { log.debug('on:unsubscribe, streamId:', streamId); - if(!that.inRoom){ + if (!that.inRoom) { return safeCall(callback, 'error', 'Illegal request'); } - var peer_id = streamId; + const peer_id = streamId; if (!ref2subId[peer_id]) { return safeCall(callback, 'error', 'Subscription does NOT exist'); } - var subscription_id = ref2subId[peer_id]; + const subscription_id = ref2subId[peer_id]; delete ref2subId[peer_id]; delete subId2ref[subscription_id]; - return portal.unsubscribe(clientId, subscription_id) - .then(function() { - safeCall(callback, 'success'); - }).catch(function(err) { - const err_message = getErrorMessage(err); - log.info('portal.unsubscribe failed:', err_message); - safeCall(callback, 'error', err_message); - }); + return portal.unsubscribe(clientId, subscription_id) + .then(function() { + safeCall(callback, 'success'); + }).catch(function(err) { + const err_message = getErrorMessage(err); + log.info('portal.unsubscribe failed:', err_message); + safeCall(callback, 'error', err_message); + }); }); - socket.on('signaling_message', function(message, to_to_deprecated, callback) { - if(!that.inRoom){ - return safeCall(callback, 'error', 'Illegal request'); - } + socket.on('signaling_message', + function(message, to_to_deprecated, callback) { + if (!that.inRoom) { + return safeCall(callback, 'error', 'Illegal request'); + } - var session_id = (ref2subId[message.streamId] ? ref2subId[message.streamId] : message.streamId); - if (session_id) { - portal.onSessionSignaling(clientId, session_id, message.msg); - } - safeCall(callback, 'ok'); - }); + const session_id = + (ref2subId[message.streamId] ? + ref2subId[message.streamId] : message.streamId); + if (session_id) { + portal.onSessionSignaling(clientId, session_id, message.msg); + } + safeCall(callback, 'ok'); + }); socket.on('addExternalOutput', function(options, callback) { - if(!that.inRoom){ + if (!that.inRoom) { return safeCall(callback, 'error', 'Illegal request'); } @@ -348,56 +332,83 @@ var LegacyClient = function(clientId, sigConnection, portal) { return safeCall(callback, 'error', 'Invalid RTSP/RTMP server url'); } - var parsed_url = url.parse(options.url); - if ((parsed_url.protocol !== 'rtsp:' && parsed_url.protocol !== 'rtmp:' && parsed_url.protocol !== 'http:') || !parsed_url.slashes || !parsed_url.host) { + const parsed_url = url.parse(options.url); + if ( + (parsed_url.protocol !== 'rtsp:' && + parsed_url.protocol !== 'rtmp:' && + parsed_url.protocol !== 'http:') || + !parsed_url.slashes || + !parsed_url.host + ) { return safeCall(callback, 'error', 'Invalid RTSP/RTMP server url'); } - if (!(options.streamId === undefined || isValidIdString(options.streamId))) { + if ( + !(options.streamId === undefined || isValidIdString(options.streamId)) + ) { return safeCall(callback, 'error', 'Invalid stream id'); } - var streaming_url = parsed_url.format(); + const streaming_url = parsed_url.format(); if (ref2subId[streaming_url]) { return safeCall(callback, 'error', 'Streaming-out is ongoing'); } - var subscription_id = Math.round(Math.random() * 1000000000000000000) + ''; + const subscription_id = + Math.round(Math.random() * 1000000000000000000) + ''; ref2subId[streaming_url] = subscription_id; subId2ref[subscription_id] = streaming_url; - var target_stream_id = (options.streamId || that.commonViewStream); - var sub_desc = { + const target_stream_id = (options.streamId || that.commonViewStream); + const sub_desc = { type: 'streaming', media: { - audio: (options.audio === false ? false: {from: target_stream_id, format: {codec: options.audio && options.audio.codecs ? options.audio.codecs[0] : 'aac'}}), - video: (options.video === false ? false: {from: target_stream_id, format: {codec: options.video && options.video.codecs ? options.video.codecs[0] : 'h264'}}) + audio: (options.audio === false ? + false: {from: target_stream_id, + format: {codec: options.audio && options.audio.codecs ? + options.audio.codecs[0] : 'aac'}}), + video: (options.video === false ? + false: {from: target_stream_id, + format: {codec: options.video && options.video.codecs ? + options.video.codecs[0] : 'h264'}}), }, connection: { - url: parsed_url.format() - } + url: parsed_url.format(), + }, }; - if (sub_desc.media.audio && sub_desc.media.audio.format && (sub_desc.media.audio.format.codec === 'aac' || sub_desc.media.audio.format.codec === 'opus')) { + if ( + sub_desc.media.audio && sub_desc.media.audio.format && + (sub_desc.media.audio.format.codec === 'aac' || + sub_desc.media.audio.format.codec === 'opus') + ) { sub_desc.media.audio.format.sampleRate = 48000; sub_desc.media.audio.format.channelNum = 2; } - ((sub_desc.media.video) && options.resolution && (typeof options.resolution.width === 'number') && (typeof options.resolution.height === 'number')) && - (sub_desc.media.video.parameters || (sub_desc.media.video.parameters = {})) && (sub_desc.media.video.parameters.resolution = options.resolution); - (sub_desc.media.video && (typeof options.resolution === 'string')) && (sub_desc.media.video.parameters || (sub_desc.media.video.parameters = {})) && (sub_desc.media.video.parameters.resolution = resolution2WidthHeight(options.resolution)); - - return portal.subscribe(clientId, subscription_id, sub_desc - ).then((result) => { - log.debug('portal.subscribe succeeded'); - safeCall(callback, 'success', {url: sub_desc.connection.url}); - }).catch(function(err) { - const err_message = getErrorMessage(err); - log.info('portal.subscribe failed:', err_message); - safeCall(callback, 'error', err_message); - }); + ((sub_desc.media.video) && options.resolution && + (typeof options.resolution.width === 'number') && + (typeof options.resolution.height === 'number')) && + (sub_desc.media.video.parameters || + (sub_desc.media.video.parameters = {})) && + (sub_desc.media.video.parameters.resolution = options.resolution); + (sub_desc.media.video && (typeof options.resolution === 'string')) && + (sub_desc.media.video.parameters || + (sub_desc.media.video.parameters = {})) && + (sub_desc.media.video.parameters.resolution = + resolution2WidthHeight(options.resolution)); + + return portal.subscribe(clientId, subscription_id, sub_desc, + ).then(() => { + log.debug('portal.subscribe succeeded'); + safeCall(callback, 'success', {url: sub_desc.connection.url}); + }).catch(function(err) { + const err_message = getErrorMessage(err); + log.info('portal.subscribe failed:', err_message); + safeCall(callback, 'error', err_message); + }); }); socket.on('updateExternalOutput', function(options, callback) { - if(!that.inRoom){ + if (!that.inRoom) { return safeCall(callback, 'error', 'Illegal request'); } @@ -407,21 +418,28 @@ var LegacyClient = function(clientId, sigConnection, portal) { return safeCall(callback, 'error', 'Invalid RTSP/RTMP server url'); } - var parsed_url = url.parse(options.url); - if ((parsed_url.protocol !== 'rtsp:' && parsed_url.protocol !== 'rtmp:' && parsed_url.protocol !== 'http:') || !parsed_url.slashes || !parsed_url.host) { + const parsed_url = url.parse(options.url); + if ( + (parsed_url.protocol !== 'rtsp:' && + parsed_url.protocol !== 'rtmp:' && + parsed_url.protocol !== 'http:') || + !parsed_url.slashes || !parsed_url.host + ) { return safeCall(callback, 'error', 'Invalid RTSP/RTMP server url'); } - if (!(options.streamId === undefined || isValidIdString(options.streamId))) { + if ( + !(options.streamId === undefined || isValidIdString(options.streamId)) + ) { return safeCall(callback, 'error', 'Invalid stream id'); } - var streaming_url = options.url; - var subscription_id = ref2subId[streaming_url]; + const streaming_url = options.url; + const subscription_id = ref2subId[streaming_url]; if (!subscription_id) { return safeCall(callback, 'error', 'Streaming-out does NOT exist'); } - var update = {}; + const update = {}; if (options.streamId) { update.audio = {from: options.streamId}; @@ -434,22 +452,27 @@ var LegacyClient = function(clientId, sigConnection, portal) { if (options.resolution) { update.video = (update.video || {}); update.video.parameters = {}; - (typeof options.resolution.width === 'number') && (typeof options.resolution.height === 'number') && (update.video.parameters.resolution = options.resolution); - (typeof options.resolution === 'string') && (update.video.parameters.resolution = resolution2WidthHeight(options.resolution)); + (typeof options.resolution.width === 'number') && + (typeof options.resolution.height === 'number') && + (update.video.parameters.resolution = options.resolution); + (typeof options.resolution === 'string') && + (update.video.parameters.resolution = + resolution2WidthHeight(options.resolution)); } - return portal.subscriptionControl(clientId, subscription_id, {operation: 'update', data: update} - ).then(function(subscriptionId) { - safeCall(callback, 'success', {url: options.url}); - }).catch(function(err) { - const err_message = getErrorMessage(err); - log.info('portal.subscriptionControl failed:', err_message); - safeCall(callback, 'error', err_message); - }); + return portal.subscriptionControl(clientId, + subscription_id, {operation: 'update', data: update}, + ).then(function() { + safeCall(callback, 'success', {url: options.url}); + }).catch(function(err) { + const err_message = getErrorMessage(err); + log.info('portal.subscriptionControl failed:', err_message); + safeCall(callback, 'error', err_message); + }); }); socket.on('removeExternalOutput', function(options, callback) { - if(!that.inRoom){ + if (!that.inRoom) { return safeCall(callback, 'error', 'Illegal request'); } @@ -459,60 +482,83 @@ var LegacyClient = function(clientId, sigConnection, portal) { return safeCall(callback, 'error', 'Invalid RTSP/RTMP server url'); } - var streaming_url = options.url; + const streaming_url = options.url; if (!ref2subId[streaming_url]) { return safeCall(callback, 'error', 'Streaming-out does NOT exist'); } - var subscription_id = ref2subId[streaming_url]; + const subscription_id = ref2subId[streaming_url]; delete ref2subId[streaming_url]; delete subId2ref[subscription_id]; return portal.unsubscribe(clientId, subscription_id) - .then(function() { - safeCall(callback, 'success', {url: options.url}); - }, function(err) { - const err_message = getErrorMessage(err); - log.info('portal.unsubscribe failed:', err_message); - safeCall(callback, 'error', 'Invalid RTSP/RTMP server url'); - }).catch(function(err) { - const err_message = getErrorMessage(err); - log.info('portal.unsubscribe failed:', err_message); - safeCall(callback, 'error', err_message); - }); + .then(function() { + safeCall(callback, 'success', {url: options.url}); + }, function(err) { + const err_message = getErrorMessage(err); + log.info('portal.unsubscribe failed:', err_message); + safeCall(callback, 'error', 'Invalid RTSP/RTMP server url'); + }).catch(function(err) { + const err_message = getErrorMessage(err); + log.info('portal.unsubscribe failed:', err_message); + safeCall(callback, 'error', err_message); + }); }); socket.on('startRecorder', function(options, callback) { - if(!that.inRoom){ + if (!that.inRoom) { return safeCall(callback, 'error', 'Illegal request'); } - if (!(options.recorderId === undefined || isValidIdString(options.recorderId))) { + if ( + !(options.recorderId === undefined || + isValidIdString(options.recorderId)) + ) { return safeCall(callback, 'error', 'Invalid recorder id'); } - if (!(options.audioStreamId === undefined || isValidIdString(options.audioStreamId))) { + if ( + !(options.audioStreamId === undefined || + isValidIdString(options.audioStreamId)) + ) { return safeCall(callback, 'error', 'Invalid audio stream id'); } - if (!(options.videoStreamId === undefined || isValidIdString(options.videoStreamId))) { + if ( + !(options.videoStreamId === undefined || + isValidIdString(options.videoStreamId)) + ) { return safeCall(callback, 'error', 'Invalid video stream id'); } - var unspecifiedStreamIds = (options.audioStreamId === undefined && options.videoStreamId === undefined); + const unspecifiedStreamIds = + (options.audioStreamId === undefined && + options.videoStreamId === undefined); - if ((options.audioStreamId || unspecifiedStreamIds) && (options.audioCodec !== undefined) && (['pcmu', 'opus', 'aac'].indexOf(options.audioCodec) < 0)) { + if ( + (options.audioStreamId || unspecifiedStreamIds) && + (options.audioCodec !== undefined) && + (['pcmu', 'opus', 'aac'].indexOf(options.audioCodec) < 0) + ) { return safeCall(callback, 'error', 'Invalid audio codec'); } - if ((options.videoStreamId || unspecifiedStreamIds) && (options.videoCodec !== undefined) && (['vp8', 'h264'].indexOf(options.videoCodec) < 0)) { + if ( + (options.videoStreamId || unspecifiedStreamIds) && + (options.videoCodec !== undefined) && + (['vp8', 'h264'].indexOf(options.videoCodec) < 0) + ) { return safeCall(callback, 'error', 'Invalid video codec'); } - //Behavior Change: The 'startRecorder' request with options.recorderId being specified will be considered - //as a contineous recording request in v3.5 and later releases. + let subscription_id; + // Behavior Change: The 'startRecorder' request with options.recorderId being specified will be considered + // as a contineous recording request in v3.5 and later releases. if (options.recorderId) { - if ((options.audioStreamId === undefined) && (options.videoStreamId === undefined)) { + if ( + (options.audioStreamId === undefined) && + (options.videoStreamId === undefined) + ) { options.audioStreamId = that.commonViewStream; options.videoStreamId = that.commonViewStream; } @@ -521,100 +567,118 @@ var LegacyClient = function(clientId, sigConnection, portal) { return safeCall(callback, 'error', 'Recording does NOT exist'); } - var subscription_id = options.recorderId; - var update = { + subscription_id = options.recorderId; + const update = { operation: 'update', - data: {} + data: {}, }; - options.audioStreamId && (update.data.audio = {from: options.audioStreamId}); - options.videoStreamId && (update.data.video = {from: options.videoStreamId}); + options.audioStreamId && + (update.data.audio = {from: options.audioStreamId}); + options.videoStreamId && + (update.data.video = {from: options.videoStreamId}); return portal.subscriptionControl(clientId, subscription_id, update) - .then((result) => { - safeCall(callback, 'success', {recorderId: options.recorderId, path: ""}); - }).catch(function(err) { - const err_message = getErrorMessage(err); - log.info('portal.subscribe failed:', err_message); - safeCall(callback, 'error', err_message); - }); + .then(() => { + safeCall(callback, 'success', + {recorderId: options.recorderId, path: ''}); + }).catch(function(err) { + const err_message = getErrorMessage(err); + log.info('portal.subscribe failed:', err_message); + safeCall(callback, 'error', err_message); + }); } - //Behavior Change: The options.path and options.interval parameters will be ignored in v3.5 and later releases. - var recorder_id = Math.round(Math.random() * 1000000000000000000) + ''; - var subscription_id = recorder_id; + // Behavior Change: The options.path and options.interval parameters will be ignored in v3.5 and later releases. + const recorder_id = Math.round(Math.random() * 1000000000000000000) + ''; + subscription_id = recorder_id; ref2subId[recorder_id] = subscription_id; subId2ref[subscription_id] = recorder_id; - var sub_desc = { + const sub_desc = { type: 'recording', media: { audio: false, - video: false + video: false, }, connection: { - container: 'auto' - } + container: 'auto', + }, }; - (options.audioStreamId || unspecifiedStreamIds) && (sub_desc.media.audio = {from: options.audioStreamId || that.commonViewStream}); + (options.audioStreamId || unspecifiedStreamIds) && + (sub_desc.media.audio = + {from: options.audioStreamId || that.commonViewStream}); sub_desc.media.audio && (sub_desc.media.audio.format = ((a) => { if (a) { if (a === 'opus' || a === 'aac') { return {codec: a, sampleRate: 48000, channelNum: 2}; } else { - return {codec: a} + return {codec: a}; } } else { return {codec: 'opus', sampleRate: 48000, channelNum: 2}; } })(options.audioCodec)); - (options.videoStreamId || unspecifiedStreamIds) && (sub_desc.media.video = {from: options.videoStreamId || that.commonViewStream}); - sub_desc.media.video && (sub_desc.media.video.format = {codec: (options.videoCodec || 'vp8')}); + (options.videoStreamId || unspecifiedStreamIds) && + (sub_desc.media.video = + {from: options.videoStreamId || that.commonViewStream}); + sub_desc.media.video && + (sub_desc.media.video.format = + {codec: (options.videoCodec || 'vp8')}); return portal.subscribe(clientId, subscription_id, sub_desc) - .then(function(result) { - log.debug('portal.subscribe succeeded, result:', result); - var container = ((options.audioCodec === 'aac' && (!options.videoCodec || (options.videoCodec === 'h264'))) ? 'mp4' : 'mkv'); - var recording_file = subscription_id + '.' + container; - safeCall(callback, 'success', {recorderId: recorder_id, path: recording_file, host: 'unknown'}); - }).catch(function(err) { - const err_message = getErrorMessage(err); - log.info('portal.subscribe failed:', err_message); - safeCall(callback, 'error', err_message); - }); + .then(function(result) { + log.debug('portal.subscribe succeeded, result:', result); + const container = + ((options.audioCodec === 'aac' && + (!options.videoCodec || (options.videoCodec === 'h264'))) ? + 'mp4' : 'mkv'); + const recording_file = subscription_id + '.' + container; + safeCall(callback, 'success', + {recorderId: recorder_id, + path: recording_file, host: 'unknown'}); + }).catch(function(err) { + const err_message = getErrorMessage(err); + log.info('portal.subscribe failed:', err_message); + safeCall(callback, 'error', err_message); + }); }); socket.on('stopRecorder', function(options, callback) { - if(!that.inRoom){ + if (!that.inRoom) { return safeCall(callback, 'error', 'Illegal request'); } - if (options.recorderId === undefined || !isValidIdString(options.recorderId)) { + if ( + options.recorderId === undefined || + !isValidIdString(options.recorderId) + ) { return safeCall(callback, 'error', 'Invalid recorder id'); } - var recorder_id = options.recorderId; + const recorder_id = options.recorderId; if (!ref2subId[recorder_id]) { return safeCall(callback, 'error', 'Recording does NOT exist'); } - var subscription_id = ref2subId[recorder_id]; + const subscription_id = ref2subId[recorder_id]; delete ref2subId[recorder_id]; delete subId2ref[subscription_id]; return portal.unsubscribe(clientId, subscription_id) - .then(function() { - safeCall(callback, 'success', {recorderId: options.recorderId, host: 'unknown'}); - }).catch(function(err) { - const err_message = getErrorMessage(err); - log.info('portal.unsubscribe failed:', err_message); - safeCall(callback, 'error', err_message); - }); + .then(function() { + safeCall(callback, 'success', + {recorderId: options.recorderId, host: 'unknown'}); + }).catch(function(err) { + const err_message = getErrorMessage(err); + log.info('portal.unsubscribe failed:', err_message); + safeCall(callback, 'error', err_message); + }); }); socket.on('getRegion', function(options, callback) { - if(!that.inRoom){ + if (!that.inRoom) { return safeCall(callback, 'error', 'Illegal request'); } @@ -622,19 +686,22 @@ var LegacyClient = function(clientId, sigConnection, portal) { return safeCall(callback, 'error', 'Invalid stream id'); } - var view_label = (options.mixStreamId ? getViewLabelFromStreamId(options.mixStreamId) : 'common'); - return portal.streamControl(clientId, options.id, {operation: 'get-region', data: view_label}) - .then(function(result) { - safeCall(callback, 'success', {region: result.region}); - }).catch(function(err) { - const err_message = getErrorMessage(err); - log.info('portal.streamControl failed:', err_message); - safeCall(callback, 'error', err_message); - }); + const view_label = + (options.mixStreamId ? + getViewLabelFromStreamId(options.mixStreamId) : 'common'); + return portal.streamControl(clientId, options.id, + {operation: 'get-region', data: view_label}) + .then(function(result) { + safeCall(callback, 'success', {region: result.region}); + }).catch(function(err) { + const err_message = getErrorMessage(err); + log.info('portal.streamControl failed:', err_message); + safeCall(callback, 'error', err_message); + }); }); socket.on('setRegion', function(options, callback) { - if(!that.inRoom){ + if (!that.inRoom) { return safeCall(callback, 'error', 'Illegal request'); } @@ -646,19 +713,23 @@ var LegacyClient = function(clientId, sigConnection, portal) { return safeCall(callback, 'error', 'Invalid region id'); } - var view_label = (options.mixStreamId ? getViewLabelFromStreamId(options.mixStreamId) : 'common'); - return portal.streamControl(clientId, options.id, {operation: 'set-region', data: {view: view_label, region: options.region}}) - .then(function() { - safeCall(callback, 'success'); - }).catch(function(err) { - const err_message = getErrorMessage(err); - log.info('portal.streamControl failed:', err_message); - safeCall(callback, 'error', err_message); - }); + const view_label = + (options.mixStreamId ? + getViewLabelFromStreamId(options.mixStreamId) : 'common'); + return portal.streamControl(clientId, options.id, + {operation: 'set-region', + data: {view: view_label, region: options.region}}) + .then(function() { + safeCall(callback, 'success'); + }).catch(function(err) { + const err_message = getErrorMessage(err); + log.info('portal.streamControl failed:', err_message); + safeCall(callback, 'error', err_message); + }); }); socket.on('mute', function(options, callback) { - if(!that.inRoom){ + if (!that.inRoom) { return safeCall(callback, 'error', 'Illegal request'); } @@ -670,18 +741,19 @@ var LegacyClient = function(clientId, sigConnection, portal) { return safeCall(callback, 'error', `invalid track ${options.track}`); } - return portal.streamControl(clientId, options.streamId, {operation: 'pause', data: options.track}) - .then(function() { - safeCall(callback, 'success'); - }).catch(function(err) { - const err_message = getErrorMessage(err); - log.info('portal.streamControl failed:', err_message); - safeCall(callback, 'error', err_message); - }); + return portal.streamControl(clientId, options.streamId, + {operation: 'pause', data: options.track}) + .then(function() { + safeCall(callback, 'success'); + }).catch(function(err) { + const err_message = getErrorMessage(err); + log.info('portal.streamControl failed:', err_message); + safeCall(callback, 'error', err_message); + }); }); socket.on('unmute', function(options, callback) { - if(!that.inRoom){ + if (!that.inRoom) { return safeCall(callback, 'error', 'Illegal request'); } @@ -693,18 +765,19 @@ var LegacyClient = function(clientId, sigConnection, portal) { return safeCall(callback, 'error', `invalid track ${options.track}`); } - return portal.streamControl(clientId, options.streamId, {operation: 'play', data: options.track}) - .then(function() { - safeCall(callback, 'success'); - }).catch(function(err) { - const err_message = getErrorMessage(err); - log.info('portal.streamControl failed:', err_message); - safeCall(callback, 'error', err_message); - }); + return portal.streamControl(clientId, options.streamId, + {operation: 'play', data: options.track}) + .then(function() { + safeCall(callback, 'success'); + }).catch(function(err) { + const err_message = getErrorMessage(err); + log.info('portal.streamControl failed:', err_message); + safeCall(callback, 'error', err_message); + }); }); socket.on('setPermission', function(options, callback) { - if(!that.inRoom){ + if (!that.inRoom) { return safeCall(callback, 'error', 'Illegal request'); } @@ -715,11 +788,12 @@ var LegacyClient = function(clientId, sigConnection, portal) { if (!options.action) { return safeCall(callback, 'error', 'no action specified'); } - safeCall(callback, 'error', 'Please use REST interface to set permissions'); - }) + safeCall(callback, 'error', + 'Please use REST interface to set permissions'); + }); socket.on('customMessage', function(msg, callback) { - if(!that.inRoom){ + if (!that.inRoom) { return safeCall(callback, 'error', 'Illegal request'); } @@ -730,14 +804,14 @@ var LegacyClient = function(clientId, sigConnection, portal) { } return portal.text(clientId, msg.receiver, msg.data) - .then(function() { - safeCall(callback, 'success'); - }).catch(function(err) { - const err_message = getErrorMessage(err); - log.info('portal.text failed:', err_message); - safeCall(callback, 'error', err_message); - }); - case 'control': + .then(function() { + safeCall(callback, 'success'); + }).catch(function(err) { + const err_message = getErrorMessage(err); + log.info('portal.text failed:', err_message); + safeCall(callback, 'error', err_message); + }); + case 'control': { if (typeof msg.payload !== 'object') { return safeCall(callback, 'error', 'Invalid payload'); } @@ -746,39 +820,45 @@ var LegacyClient = function(clientId, sigConnection, portal) { return safeCall(callback, 'error', 'Invalid connection id'); } - if (typeof msg.payload.action !== 'string' || !(/^((audio)|(video))-((in)|(out))-((on)|(off))$/.test(msg.payload.action))) { + if ( + typeof msg.payload.action !== 'string' || + !(/^((audio)|(video))-((in)|(out))-((on)|(off))$/ + .test(msg.payload.action)) + ) { return safeCall(callback, 'error', 'Invalid action'); } - var cmdOpts = msg.payload.action.split('-'), - track = cmdOpts[0], - direction = (cmdOpts[1] === 'out' ? 'in' : 'out'), - operation = (cmdOpts[2] === 'on' ? 'play' : 'pause'); + const cmdOpts = msg.payload.action.split('-'); + const track = cmdOpts[0]; + const operation = (cmdOpts[2] === 'on' ? 'play' : 'pause'); if (cmdOpts[1] === 'out') { - return portal.streamControl(clientId, msg.payload.streamId, {operation: operation, data: track}) - .then(() => { - safeCall(callback, 'success'); - }).catch((err) => { - const err_message = getErrorMessage(err); - log.info('portal.streamControl failed:', err_message); - safeCall(callback, 'error', err_message); - }); + return portal.streamControl(clientId, msg.payload.streamId, + {operation: operation, data: track}) + .then(() => { + safeCall(callback, 'success'); + }).catch((err) => { + const err_message = getErrorMessage(err); + log.info('portal.streamControl failed:', err_message); + safeCall(callback, 'error', err_message); + }); } else { - var peer_id = msg.payload.streamId; - var subscription_id = ref2subId[peer_id]; + const peer_id = msg.payload.streamId; + const subscription_id = ref2subId[peer_id]; if (subscription_id === undefined) { return safeCall(callback, 'error', 'Subscription does NOT exist'); } - return portal.subscriptionControl(clientId, subscription_id, {operation: operation, data: track}) - .then(function() { - safeCall(callback, 'success'); - }).catch(function(err) { - const err_message = getErrorMessage(err); - log.info('portal.subscriptionControl failed:', err_message); - safeCall(callback, 'error', err_message); - }); + return portal.subscriptionControl(clientId, subscription_id, + {operation: operation, data: track}) + .then(function() { + safeCall(callback, 'success'); + }).catch(function(err) { + const err_message = getErrorMessage(err); + log.info('portal.subscriptionControl failed:', err_message); + safeCall(callback, 'error', err_message); + }); } + } default: return safeCall(callback, 'error', 'Invalid message type'); } @@ -787,7 +867,12 @@ var LegacyClient = function(clientId, sigConnection, portal) { const notifyParticipantActivity = (participantActivity) => { if (participantActivity.action === 'join') { - sendMsg('user_join', {user: {id: participantActivity.data.id, name: participantActivity.data.user, role: participantActivity.data.role}}); + sendMsg('user_join', + {user: { + id: participantActivity.data.id, + name: participantActivity.data.user, + role: participantActivity.data.role, + }}); } else if (participantActivity.action === 'leave') { sendMsg('user_leave', {user: {id: participantActivity.data}}); } else { @@ -795,24 +880,24 @@ var LegacyClient = function(clientId, sigConnection, portal) { } }; - //FIXME: Client side need to handle the incompetibility, since the definition of region has been extended. + // FIXME: Client side need to handle the incompetibility, since the definition of region has been extended. const convertStreamRegion = (stream2region) => { - var calRational = (r) => (r.numerator / r.denominator); + const calRational = (r) => (r.numerator / r.denominator); return { streamID: stream2region.stream, id: stream2region.region.id, left: calRational(stream2region.region.area.left), top: calRational(stream2region.region.area.top), - relativeSize: calRational(stream2region.region.area.width) + relativeSize: calRational(stream2region.region.area.width), }; }; const convertStreamInfo = (st) => { - var stream = { + const stream = { id: st.id, audio: !!st.media.audio, video: st.media.video ? {} : false, - socket: '' + socket: '', }; if (st.info.attributes) { @@ -835,10 +920,13 @@ var LegacyClient = function(clientId, sigConnection, portal) { stream.video.device = 'mcu'; stream.video.resolutions = [st.media.video.parameters.resolution]; - st.media.video.optional && st.media.video.optional.parameters && st.media.video.optional.parameters.resolution && st.media.video.optional.parameters.resolution.forEach(function(reso) { - stream.video.resolutions.push(reso); - }); - } else if (st.media.video.source === 'screen-cast'){ + st.media.video.optional && st.media.video.optional.parameters && + st.media.video.optional.parameters.resolution && + st.media.video.optional.parameters.resolution + .forEach(function(reso) { + stream.video.resolutions.push(reso); + }); + } else if (st.media.video.source === 'screen-cast') { stream.video.device = 'screen'; } else if (st.media.video.source === 'camera') { stream.video.device = 'camera'; @@ -852,11 +940,14 @@ var LegacyClient = function(clientId, sigConnection, portal) { if (streamInfo.status === 'add') { sendMsg('add_stream', convertStreamInfo(streamInfo.data)); } else if (streamInfo.status === 'update') { - var st_update = {id: streamInfo.id}; - if ((streamInfo.data.field === 'audio.status') || (streamInfo.data.field === 'video.status')) {//Forward stream update + let st_update = {id: streamInfo.id}; + if ( + (streamInfo.data.field === 'audio.status') || + (streamInfo.data.field === 'video.status') + ) {// Forward stream update st_update.event = 'StateChange'; st_update.state = streamInfo.data.value; - } else if (streamInfo.data.field === 'video.layout') {//Mixed stream update + } else if (streamInfo.data.field === 'video.layout') {// Mixed stream update st_update.event = 'VideoLayoutChanged'; st_update.data = streamInfo.data.value.map(convertStreamRegion); } else { @@ -872,43 +963,52 @@ var LegacyClient = function(clientId, sigConnection, portal) { const notifySessionProgress = (sessionProgress) => { log.debug('notifySessionProgress, sessionProgress:', sessionProgress); - var id = sessionProgress.id; + const id = sessionProgress.id; + let peer_id; if (sessionProgress.status === 'soac') { if (published[id]) { - sendMsg('signaling_message_erizo', {streamId: id, mess: sessionProgress.data}); + sendMsg('signaling_message_erizo', + {streamId: id, mess: sessionProgress.data}); } else { - var peer_id = subId2ref[id]; + peer_id = subId2ref[id]; if (peer_id) { - sendMsg('signaling_message_erizo', {peerId: peer_id, mess: sessionProgress.data}); + sendMsg('signaling_message_erizo', + {peerId: peer_id, mess: sessionProgress.data}); } } } else if (sessionProgress.status === 'ready') { if (published[id]) { if (published[id].type === 'webrtc') { - sendMsg('signaling_message_erizo', {streamId: id, mess: {type: 'ready'}}); + sendMsg('signaling_message_erizo', + {streamId: id, mess: {type: 'ready'}}); } if (published[id].mix) { portal.streamControl(clientId, id, {operation: 'mix', data: 'common'}) - .catch((err) => { - log.info('Mix stream failed, reason:', getErrorMessage(err)); - }); + .catch((err) => { + log.info('Mix stream failed, reason:', getErrorMessage(err)); + }); } } else { - var peer_id = subId2ref[id]; + peer_id = subId2ref[id]; if (peer_id) { - sendMsg('signaling_message_erizo', {peerId: peer_id, mess: {type: 'ready'}}); + sendMsg('signaling_message_erizo', + {peerId: peer_id, mess: {type: 'ready'}}); } } } else if (sessionProgress.status === 'error') { - var ref = subId2ref[id]; + const ref = subId2ref[id]; if (ref) { if (ref === id) { - var recorder_id = id; + const recorder_id = id; log.debug('recorder error, recorder_id:', ref); portal.unsubscribe(clientId, id); sendMsg('remove_recorder', {id: recorder_id}); - } else if (ref.indexOf('rtsp') !== -1 || ref.indexOf('rtmp') !== -1 || ref.indexOf('http') !== -1) { + } else if ( + ref.indexOf('rtsp') !== -1 || + ref.indexOf('rtmp') !== -1 || + ref.indexOf('http') !== -1 + ) { sendMsg('connection_failed', {url: ref}); } else { sendMsg('connection_failed', {streamId: ref}); @@ -932,9 +1032,9 @@ var LegacyClient = function(clientId, sigConnection, portal) { return { id: ptt.id, name: ptt.user, - role: ptt.role + role: ptt.role, }; - }) + }), }; }; @@ -947,7 +1047,8 @@ var LegacyClient = function(clientId, sigConnection, portal) { } else if (event === 'progress') { notifySessionProgress(data); } else if (event === 'text') { - sendMsg('custom_message', {from: data.from, to: data.to, data: data.message }); + sendMsg('custom_message', + {from: data.from, to: data.to, data: data.message}); } else { sendMsg(event, data); } @@ -955,15 +1056,15 @@ var LegacyClient = function(clientId, sigConnection, portal) { that.join = (token) => { return portal.join(clientId, token) - .then(function(result){ - that.inRoom = result.data.room.id; - that.tokenCode = result.tokenCode; - return convertJoinResponse(result.data); - }); + .then(function(result) { + that.inRoom = result.data.room.id; + that.tokenCode = result.tokenCode; + return convertJoinResponse(result.data); + }); }; that.leave = () => { - if(that.inRoom) { + if (that.inRoom) { return portal.leave(that.id).catch(() => { that.inRoom = undefined; that.tokenCode = undefined; diff --git a/source/portal/portal.js b/source/portal/portal.js index a6a78d644..64afce785 100644 --- a/source/portal/portal.js +++ b/source/portal/portal.js @@ -4,19 +4,17 @@ 'use strict'; -var path = require('path'); -var url = require('url'); -var crypto = require('crypto'); -var log = require('./logger').logger.getLogger('Portal'); -var dataAccess = require('./data_access'); -const { v4 : uuid } = require('uuid'); -const vsprintf = require("sprintf-js").vsprintf; - -var Portal = function(spec, rpcReq) { - var that = {}, - token_key = spec.tokenKey, - cluster_name = spec.clusterName, - self_rpc_id = spec.selfRpcId; +const crypto = require('crypto'); +const log = require('./logger').logger.getLogger('Portal'); +const dataAccess = require('./data_access'); +const {v4: uuid} = require('uuid'); +const vsprintf = require('sprintf-js').vsprintf; + +const Portal = function(spec, rpcReq) { + const that = {}; + let token_key = spec.tokenKey; + const cluster_name = spec.clusterName; + const self_rpc_id = spec.selfRpcId; /* * {participantId: { @@ -24,48 +22,54 @@ var Portal = function(spec, rpcReq) { * controller: RpcId * }} */ - var participants = {}; + const participants = {}; // Key is participantId, value is token ID. const webTransportIds = new Map(); const calculateSignatureForWebTransportToken = (token) => { - const toSign = vsprintf('%s,%s,%s,%s,%s', [ - token.tokenId, - token.transportId, - token.participantId, - token.roomId, - token.issueTime - ]); - const signed = crypto.createHmac('sha256', token_key).update(toSign).digest('hex'); - return (Buffer.from(signed)).toString('base64'); + const toSign = vsprintf('%s,%s,%s,%s,%s', [ + token.tokenId, + token.transportId, + token.participantId, + token.roomId, + token.issueTime, + ]); + const signed = + crypto.createHmac('sha256', token_key).update(toSign).digest('hex'); + return (Buffer.from(signed)).toString('base64'); }; const generateWebTransportToken = (participantId, roomId) => { - const now = Date.now(); - const token = { - tokenId : uuid().replace(/-/g, ''), - transportId: uuid().replace(/-/g, ''), - participantId : participantId, - roomId: roomId, - issueTime : now, - }; - token.signature = calculateSignatureForWebTransportToken(token); - webTransportIds.set(participantId, token.tokenId); - return token; + const now = Date.now(); + const token = { + tokenId: uuid().replace(/-/g, ''), + transportId: uuid().replace(/-/g, ''), + participantId: participantId, + roomId: roomId, + issueTime: now, + }; + token.signature = calculateSignatureForWebTransportToken(token); + webTransportIds.set(participantId, token.tokenId); + return token; }; that.validateAndDeleteWebTransportToken = (token) => { - // |participants| is better to be a map. - if (!participants.hasOwnProperty(token.participantId)) { - return false; - } - if (!webTransportIds.has(token.participantId) || webTransportIds.get(token.participantId) !== token.tokenId) { - return false; - } - if (calculateSignatureForWebTransportToken(token) !== token.signature) { - return false; - } - webTransportIds.delete(token.participantId); - return true; + // |participants| is better to be a map. + if ( + !Object.prototype.hasOwnProperty.call(participants, token.participantId) + ) { + return false; + } + if ( + !webTransportIds.has(token.participantId) || + webTransportIds.get(token.participantId) !== token.tokenId + ) { + return false; + } + if (calculateSignatureForWebTransportToken(token) !== token.signature) { + return false; + } + webTransportIds.delete(token.participantId); + return true; }; that.updateTokenKey = function(tokenKey) { @@ -73,19 +77,22 @@ var Portal = function(spec, rpcReq) { }; that.join = function(participantId, token) { - log.debug('participant[', participantId, '] join with token:', JSON.stringify(token)); + log.debug('participant[', participantId, + '] join with token:', JSON.stringify(token)); if (participants[participantId]) { return Promise.reject('Participant already in room'); } - var calculateSignature = function (token) { - var toSign = token.tokenId + ',' + token.host + ',' + token.webTransportUrl, - signed = crypto.createHmac('sha256', token_key).update(toSign).digest('hex'); + const calculateSignature = function(token) { + const toSign = + token.tokenId + ',' + token.host + ',' + token.webTransportUrl; + const signed = + crypto.createHmac('sha256', token_key).update(toSign).digest('hex'); return (new Buffer(signed)).toString('base64'); }; - var validateToken = function (token) { - var signature = calculateSignature(token); + const validateToken = function(token) { + const signature = calculateSignature(token); if (signature !== token.signature) { return Promise.reject('Invalid token signature'); @@ -94,59 +101,79 @@ var Portal = function(spec, rpcReq) { } }; - var tokenCode, userInfo, role, origin, room_id, room_controller; + let tokenCode; + let userInfo; + let role; + let origin; + let room_id; + let room_controller; return validateToken(token) - .then(function(validToken) { - log.debug('token validation ok.'); - return dataAccess.token.delete(validToken.tokenId); - }) - .then(function(deleteTokenResult) { - log.debug('login ok.', deleteTokenResult); - tokenCode = deleteTokenResult.code; - userInfo = deleteTokenResult.user; - role = deleteTokenResult.role; - origin = deleteTokenResult.origin; - room_id = deleteTokenResult.room; - return rpcReq.getController(cluster_name, room_id); - }) - .then(function(controller) { - log.debug('got controller:', controller); - room_controller = controller; - return rpcReq.join(controller, room_id, {id: participantId, user: userInfo, role: role, portal: self_rpc_id, origin: origin}); - }) - .then(function(joinResult) { - log.debug('join ok, result:', joinResult); - participants[participantId] = { - in_room: room_id, - controller: room_controller - }; - - let webTransportToken = undefined; - if (token.webTransportUrl) { - webTransportToken = (Buffer.from(JSON.stringify(generateWebTransportToken(participantId, room_id)))).toString('base64'); - } - - return { - tokenCode: tokenCode, - data: { - user: userInfo, - role: role, - permission: joinResult.permission, - room: joinResult.room, - webTransportToken: webTransportToken + .then(function(validToken) { + log.debug('token validation ok.'); + return dataAccess.token.delete(validToken.tokenId); + }) + .then(function(deleteTokenResult) { + log.debug('login ok.', deleteTokenResult); + tokenCode = deleteTokenResult.code; + userInfo = deleteTokenResult.user; + role = deleteTokenResult.role; + origin = deleteTokenResult.origin; + room_id = deleteTokenResult.room; + return rpcReq.getController(cluster_name, room_id); + }) + .then(function(controller) { + log.debug('got controller:', controller); + room_controller = controller; + return rpcReq.join( + controller, + room_id, + { + id: participantId, + user: userInfo, + role: role, + portal: self_rpc_id, + origin: origin, + }, + ); + }) + .then(function(joinResult) { + log.debug('join ok, result:', joinResult); + participants[participantId] = { + in_room: room_id, + controller: room_controller, + }; + + let webTransportToken = undefined; + if (token.webTransportUrl) { + webTransportToken = + (Buffer.from( + JSON.stringify( + generateWebTransportToken(participantId, room_id)))) + .toString('base64'); } - }; - }); + + return { + tokenCode: tokenCode, + data: { + user: userInfo, + role: role, + permission: joinResult.permission, + room: joinResult.room, + webTransportToken: webTransportToken, + }, + }; + }); }; that.leave = function(participantId) { log.debug('participant leave:', participantId); if (participants[participantId]) { rpcReq.leave(participants[participantId].controller, participantId) - .catch(function(reason) { - log.info('Failed in leaving, ', reason.message ? reason.message : reason); - }); + .catch(function(reason) { + log.info('Failed in leaving, ', + reason.message ? reason.message : reason); + }); delete participants[participantId]; return Promise.resolve('ok'); } else { @@ -155,82 +182,103 @@ var Portal = function(spec, rpcReq) { }; that.publish = function(participantId, streamId, pubInfo) { - log.debug('publish, participantId:', participantId, 'streamId:', streamId, 'pubInfo:', pubInfo); + log.debug('publish, participantId:', participantId, + 'streamId:', streamId, + 'pubInfo:', pubInfo); if (participants[participantId] === undefined) { return Promise.reject('Participant has NOT joined'); } return rpcReq.publish(participants[participantId].controller, - participantId, - streamId, - pubInfo); + participantId, + streamId, + pubInfo); }; that.unpublish = function(participantId, streamId) { - log.debug('unpublish, participantId:', participantId, 'streamId:', streamId); + log.debug('unpublish, participantId:', participantId, + 'streamId:', streamId); if (participants[participantId] === undefined) { return Promise.reject('Participant has NOT joined'); } return rpcReq.unpublish(participants[participantId].controller, - participantId, - streamId); + participantId, + streamId); }; that.streamControl = function(participantId, streamId, commandInfo) { - log.debug('streamControl, participantId:', participantId, 'streamId:', streamId, 'command:', commandInfo); + log.debug('streamControl, participantId:', participantId, + 'streamId:', streamId, + 'command:', commandInfo); if (participants[participantId] === undefined) { return Promise.reject('Participant has NOT joined'); } return rpcReq.streamControl(participants[participantId].controller, - participantId, - streamId, - commandInfo); + participantId, + streamId, + commandInfo); }; that.subscribe = function(participantId, subscriptionId, subDesc) { - log.debug('subscribe, participantId:', participantId, 'subscriptionId:', subscriptionId, 'subDesc:', subDesc); + log.debug('subscribe, participantId:', participantId, + 'subscriptionId:', subscriptionId, + 'subDesc:', subDesc); if (participants[participantId] === undefined) { return Promise.reject('Participant has NOT joined'); } return rpcReq.subscribe(participants[participantId].controller, - participantId, - subscriptionId, - subDesc); + participantId, + subscriptionId, + subDesc); }; that.unsubscribe = function(participantId, subscriptionId) { - log.debug('unsubscribe, participantId:', participantId, 'subscriptionId:', subscriptionId); + log.debug('unsubscribe, participantId:', participantId, + 'subscriptionId:', subscriptionId); if (participants[participantId] === undefined) { return Promise.reject('Participant has NOT joined'); } - return rpcReq.unsubscribe(participants[participantId].controller, participantId, subscriptionId); + return rpcReq.unsubscribe(participants[participantId].controller, + participantId, + subscriptionId); }; - that.subscriptionControl = function(participantId, subscriptionId, commandInfo) { - log.debug('subscriptionControl, participantId:', participantId, 'subscriptionId:', subscriptionId, 'command:', commandInfo); - if (participants[participantId] === undefined) { - return Promise.reject('Participant has NOT joined'); - } + that.subscriptionControl = + function(participantId, subscriptionId, commandInfo) { + log.debug('subscriptionControl, participantId:', participantId, + 'subscriptionId:', subscriptionId, + 'command:', commandInfo); + if (participants[participantId] === undefined) { + return Promise.reject('Participant has NOT joined'); + } - return rpcReq.subscriptionControl(participants[participantId].controller, - participantId, - subscriptionId, - commandInfo); - }; + return rpcReq.subscriptionControl( + participants[participantId].controller, + participantId, + subscriptionId, + commandInfo, + ); + }; that.onSessionSignaling = function(participantId, sessionId, signaling) { - log.debug('onSessionSignaling, participantId:', participantId, 'sessionId:', sessionId, 'signaling:', signaling); + log.debug('onSessionSignaling, participantId:', participantId, + 'sessionId:', sessionId, + 'signaling:', signaling); - var participant = participants[participantId]; - if (participants[participantId] === undefined) { + const participant = participants[participantId]; + if (participant === undefined) { return Promise.reject('Participant has NOT joined'); } - - return rpcReq.onSessionSignaling(participants[participantId].controller, sessionId, signaling); + + return rpcReq.onSessionSignaling( + participant.controller, + sessionId, + signaling, + ); }; that.text = function(participantId, to, msg) { @@ -239,14 +287,22 @@ var Portal = function(spec, rpcReq) { return Promise.reject('Participant has NOT joined'); } - return rpcReq.text(participants[participantId].controller, participantId, to, msg); + return rpcReq.text( + participants[participantId].controller, + participantId, + to, + msg, + ); }; - that.getParticipantsByController = function (type, id) { - var result = []; - for (var participant_id in participants) { - if ((type === 'node' && participants[participant_id].controller === id) || - (type === 'worker' && participants[participant_id].controller.startsWith(id))) { + that.getParticipantsByController = function(type, id) { + const result = []; + for (const participant_id in participants) { + if ( + (type === 'node' && participants[participant_id].controller === id) || + (type === 'worker' && + participants[participant_id].controller.startsWith(id)) + ) { result.push(participant_id); } } diff --git a/source/portal/rpcRequest.js b/source/portal/rpcRequest.js index b108eca49..3a79f9056 100644 --- a/source/portal/rpcRequest.js +++ b/source/portal/rpcRequest.js @@ -4,14 +4,27 @@ 'use strict'; -var RpcRequest = function(rpcChannel) { - var that = {}; +const RpcRequest = function(rpcChannel) { + const that = {}; that.getController = function(clusterManager, roomId) { - return rpcChannel.makeRPC(clusterManager, 'schedule', ['conference', roomId, 'preference'/*TODO: specify preference*/, 30 * 1000]) - .then(function(controllerAgent) { - return rpcChannel.makeRPC(controllerAgent.id, 'getNode', [{room: roomId, task: roomId}]); - }); + return rpcChannel.makeRPC( + clusterManager, + 'schedule', + [ + 'conference', + roomId, + 'preference'/* TODO: specify preference*/, + 30 * 1000, + ], + ) + .then(function(controllerAgent) { + return rpcChannel.makeRPC( + controllerAgent.id, + 'getNode', + [{room: roomId, task: roomId}], + ); + }); }; that.join = function(controller, roomId, participant) { @@ -23,35 +36,71 @@ var RpcRequest = function(rpcChannel) { }; that.text = function(controller, fromWhom, toWhom, message) { - return rpcChannel.makeRPC(controller, 'text', [fromWhom, toWhom, message], 4000); + return rpcChannel.makeRPC( + controller, + 'text', + [fromWhom, toWhom, message], + 4000, + ); }; that.publish = function(controller, participantId, streamId, Options) { - return rpcChannel.makeRPC(controller, 'publish', [participantId, streamId, Options]); + return rpcChannel.makeRPC( + controller, + 'publish', + [participantId, streamId, Options], + ); }; that.unpublish = function(controller, participantId, streamId) { - return rpcChannel.makeRPC(controller, 'unpublish', [participantId, streamId]); + return rpcChannel.makeRPC( + controller, + 'unpublish', + [participantId, streamId], + ); }; that.streamControl = function(controller, participantId, streamId, command) { - return rpcChannel.makeRPC(controller, 'streamControl', [participantId, streamId, command], 4000); + return rpcChannel.makeRPC( + controller, + 'streamControl', + [participantId, streamId, command], + 4000, + ); }; - that.subscribe = function(controller, participantId, subscriptionId, Options) { - return rpcChannel.makeRPC(controller, 'subscribe', [participantId, subscriptionId, Options]); - }; + that.subscribe = + function(controller, participantId, subscriptionId, Options) { + return rpcChannel.makeRPC( + controller, + 'subscribe', + [participantId, subscriptionId, Options], + ); + }; that.unsubscribe = function(controller, participantId, subscriptionId) { - return rpcChannel.makeRPC(controller, 'unsubscribe', [participantId, subscriptionId]); + return rpcChannel.makeRPC( + controller, + 'unsubscribe', + [participantId, subscriptionId], + ); }; - that.subscriptionControl = function(controller, participantId, subscriptionId, command) { - return rpcChannel.makeRPC(controller, 'subscriptionControl', [participantId, subscriptionId, command]); - }; + that.subscriptionControl = + function(controller, participantId, subscriptionId, command) { + return rpcChannel.makeRPC( + controller, + 'subscriptionControl', + [participantId, subscriptionId, command], + ); + }; that.onSessionSignaling = function(controller, sessionId, signaling) { - return rpcChannel.makeRPC(controller, 'onSessionSignaling', [sessionId, signaling]); + return rpcChannel.makeRPC( + controller, + 'onSessionSignaling', + [sessionId, signaling], + ); }; return that; diff --git a/source/portal/socketIOServer.js b/source/portal/socketIOServer.js index d8d06156c..4687233be 100644 --- a/source/portal/socketIOServer.js +++ b/source/portal/socketIOServer.js @@ -4,23 +4,23 @@ 'use strict'; -var path = require('path'); -var log = require('./logger').logger.getLogger('SocketIOServer'); -var crypto = require('crypto'); -var vsprintf = require("sprintf-js").vsprintf; +const path = require('path'); +const log = require('./logger').logger.getLogger('SocketIOServer'); +const crypto = require('crypto'); +const vsprintf = require('sprintf-js').vsprintf; -var LegacyClient = require('./legacyClient'); -var Client = require('./client'); +const LegacyClient = require('./legacyClient'); +const Client = require('./client'); -function safeCall () { - var callback = arguments[0]; +function safeCall(...args) { + const callback = args[0]; if (typeof callback === 'function') { - var args = Array.prototype.slice.call(arguments, 1); - callback.apply(null, args); + const callbackArgs = Array.prototype.slice.call(args, 1); + callback(...callbackArgs); } } -const getErrorMessage = function (err) { +const getErrorMessage = function(err) { if (typeof err === 'string') { return err; } else if (err && err.message) { @@ -31,38 +31,54 @@ const getErrorMessage = function (err) { } }; -var Connection = function(spec, socket, reconnectionKey, portal, dock) { - var that = { +const Connection = function(spec, socket, reconnectionKey, portal, dock) { + const that = { socket: socket, }; // With value of (undefined | 'initialized' | 'connecting' | 'connected' | 'waiting_for_reconnecting') - var state; - var client_id; - var protocol_version; - var waiting_for_reconnecting_timer = null; - var pending_messages = []; - - let reconnection = { - enabled: false + let state; + let client_id; + let protocol_version; + let waiting_for_reconnecting_timer = null; + let pending_messages = []; + + const reconnection = { + enabled: false, }; - const validateUserAgent = function(ua){ - if(!ua||!ua.sdk||!ua.sdk.version||!ua.sdk.type||!ua.runtime||!ua.runtime.version||!ua.runtime.name||!ua.os||!ua.os.version||!ua.os.name){ + const validateUserAgent = function(ua) { + if ( + !ua|| + !ua.sdk|| + !ua.sdk.version|| + !ua.sdk.type|| + !ua.runtime|| + !ua.runtime.version|| + !ua.runtime.name|| + !ua.os|| + !ua.os.version|| + !ua.os.name + ) { return Promise.reject('User agent info is incorrect'); } - return Promise.resolve(ua.sdk.type === 'Objective-C' || ua.sdk.type === 'C++' || ua.sdk.type === 'Android' || ua.sdk.type == 'JavaScript') + return Promise.resolve( + ua.sdk.type === 'Objective-C' || + ua.sdk.type === 'C++' || + ua.sdk.type === 'Android' || + ua.sdk.type == 'JavaScript', + ); }; const calculateSignature = function(ticket) { const to_sign = vsprintf('%s,%s,%s', [ ticket.participantId, ticket.notBefore, - ticket.notAfter + ticket.notAfter, ]); const signed = crypto.createHmac('sha256', reconnectionKey) - .update(to_sign) - .digest('hex'); + .update(to_sign) + .digest('hex'); return (new Buffer(signed)).toString('base64'); }; @@ -73,38 +89,38 @@ var Connection = function(spec, socket, reconnectionKey, portal, dock) { ticketId: Math.random().toString(36).substring(2), notBefore: now, // Unit for reconnectionTicketLifetime is second. - notAfter: now + spec.reconnectionTicketLifetime * 1000 + notAfter: now + spec.reconnectionTicketLifetime * 1000, }; reconnection.ticket.signature = calculateSignature(reconnection.ticket); return (new Buffer(JSON.stringify(reconnection.ticket))).toString('base64'); }; - const validateReconnectionTicket = function(ticket) { - if(!reconnection.enabled) { - return Promise.reject('Reconnection is not allowed.'); - } - if(ticket.participantId!==client_id){ - return Promise.reject('Participant ID is not matched.'); - } - let signature = calculateSignature(ticket); - if(signature!=ticket.signature){ - return Promise.reject('Invalid reconnection ticket signature'); - } - const now = Date.now(); - if(nowticket.notAfter){ - return Promise.reject('Ticket is expired.'); - } - if(disconnect_timeout){ - clearTimeout(disconnect_timeout); - disconnect_timeout=undefined; - } - disconnected = true; - socket.disconnect(true); - return Promise.resolve(); - }; + // const validateReconnectionTicket = function(ticket) { + // if(!reconnection.enabled) { + // return Promise.reject('Reconnection is not allowed.'); + // } + // if(ticket.participantId!==client_id){ + // return Promise.reject('Participant ID is not matched.'); + // } + // let signature = calculateSignature(ticket); + // if(signature!=ticket.signature){ + // return Promise.reject('Invalid reconnection ticket signature'); + // } + // const now = Date.now(); + // if(nowticket.notAfter){ + // return Promise.reject('Ticket is expired.'); + // } + // if(disconnect_timeout){ + // clearTimeout(disconnect_timeout); + // disconnect_timeout=undefined; + // } + // disconnected = true; + // socket.disconnect(true); + // return Promise.resolve(); + // }; const drainPendingMessages = () => { - for(let message of pending_messages){ + for (const message of pending_messages) { if (message && message.event) { that.sendMessage(message.event, message.data); } @@ -115,7 +131,7 @@ var Connection = function(spec, socket, reconnectionKey, portal, dock) { const forceClientLeave = () => { log.debug('forceClientLeave, client_id:', client_id); if (client_id) { - const client = dock.getClient(client_id) + const client = dock.getClient(client_id); if (client && client.connection === that) { client.leave(); dock.onClientLeft(client_id); @@ -138,14 +154,14 @@ var Connection = function(spec, socket, reconnectionKey, portal, dock) { state = 'connecting'; client_id = socket.id + ''; - var client; + let client; if (login_info.protocol === undefined) { protocol_version = 'legacy'; client = new LegacyClient(client_id, that, portal); } else if (login_info.protocol === '1.0' || login_info.protocol === '1.1' || login_info.protocol === '1.2') { - //FIXME: Reject connection from 3.5 client + // FIXME: Reject connection from 3.5 client if (login_info.userAgent && login_info.userAgent.sdk && login_info.userAgent.sdk.version === '3.5') { safeCall(callback, 'error', 'Deprecated client version'); @@ -159,35 +175,37 @@ var Connection = function(spec, socket, reconnectionKey, portal, dock) { } return validateUserAgent(login_info.userAgent) - .then((reconnEnabled) => { - reconnection.enabled = reconnEnabled; - return new Promise(function(resolve){ - resolve(JSON.parse((new Buffer(login_info.token, 'base64')).toString())); - }); - }).then((token) => { - return client.join(token); - }).then((result) => { - if (state === 'connecting') { - if(reconnection.enabled){ - result.reconnectionTicket = generateReconnectionTicket(); + .then((reconnEnabled) => { + reconnection.enabled = reconnEnabled; + return new Promise(function(resolve) { + resolve(JSON.parse( + (new Buffer(login_info.token, 'base64')).toString()), + ); + }); + }).then((token) => { + return client.join(token); + }).then((result) => { + if (state === 'connecting') { + if (reconnection.enabled) { + result.reconnectionTicket = generateReconnectionTicket(); + } + state = 'connected'; + dock.onClientJoined(client_id, client); + safeCall(callback, okWord(), result); + } else { + client.leave(client_id); + state = 'initialized'; + safeCall(callback, 'error', 'Participant early left'); + log.info('Login failed:', 'Participant early left'); + socket.disconnect(); } - state = 'connected'; - dock.onClientJoined(client_id, client); - safeCall(callback, okWord(), result); - } else { - client.leave(client_id); + }).catch((err) => { state = 'initialized'; - safeCall(callback, 'error', 'Participant early left'); - log.info('Login failed:', 'Participant early left'); + const err_message = getErrorMessage(err); + safeCall(callback, 'error', err_message); + log.info('Login failed:', err_message); socket.disconnect(); - } - }).catch((err) => { - state = 'initialized'; - const err_message = getErrorMessage(err); - safeCall(callback, 'error', err_message); - log.info('Login failed:', err_message); - socket.disconnect(); - }); + }); }); socket.on('relogin', function(reconnectionTicket, callback) { @@ -196,12 +214,14 @@ var Connection = function(spec, socket, reconnectionKey, portal, dock) { } state = 'connecting'; - var client; - var reconnection_ticket; + let client; + let reconnection_ticket; new Promise((resolve) => { - resolve(JSON.parse((new Buffer(reconnectionTicket, 'base64')).toString())); + resolve( + JSON.parse((new Buffer(reconnectionTicket, 'base64')).toString()), + ); }).then((ticket) => { - var now = Date.now(); + const now = Date.now(); if (ticket.notBefore > now || ticket.notAfter < now) { return Promise.reject('Ticket is expired'); } else if (ticket.signature !== calculateSignature(ticket)) { @@ -219,7 +239,10 @@ var Connection = function(spec, socket, reconnectionKey, portal, dock) { }).then((connectionInfo) => { if (!connectionInfo.reconnection.enabled) { return Promise.reject('Reconnection is not allowed'); - } else if (connectionInfo.reconnection.ticket.participantId !== reconnection_ticket.participantId) { + } else if ( + connectionInfo.reconnection.ticket.participantId !== + reconnection_ticket.participantId + ) { return Promise.reject('Participant ID is not matched'); } else { client_id = connectionInfo.clientId + ''; @@ -229,7 +252,7 @@ var Connection = function(spec, socket, reconnectionKey, portal, dock) { return client.resetConnection(that); } }).then(() => { - let ticket = generateReconnectionTicket(); + const ticket = generateReconnectionTicket(); state = 'connected'; safeCall(callback, okWord(), ticket); drainPendingMessages(); @@ -243,20 +266,20 @@ var Connection = function(spec, socket, reconnectionKey, portal, dock) { }); }); - socket.on('refreshReconnectionTicket', function(callback){ - if(state !== 'connected') { + socket.on('refreshReconnectionTicket', function(callback) { + if (state !== 'connected') { return safeCall(callback, 'error', 'Illegal request'); } - if(!reconnection.enabled) { - return safeCall(callback,'error','Reconnection is not enabled.'); + if (!reconnection.enabled) { + return safeCall(callback, 'error', 'Reconnection is not enabled.'); } - let ticket = generateReconnectionTicket(); + const ticket = generateReconnectionTicket(); safeCall(callback, okWord(), ticket); }); - socket.on('logout', function(callback){ + socket.on('logout', function(callback) { reconnection.enabled = false; state = 'initialized'; if (client_id) { @@ -300,11 +323,11 @@ var Connection = function(spec, socket, reconnectionKey, portal, dock) { pendingMessages: pending_messages, clientId: client_id, protocolVersion: protocol_version, - reconnection: reconnection + reconnection: reconnection, }; }; - that.sendMessage = function (event, data) { + that.sendMessage = function(event, data) { log.debug('sendMessage, event:', event, 'data:', data); if (state === 'connected') { try { @@ -321,7 +344,8 @@ var Connection = function(spec, socket, reconnectionKey, portal, dock) { log.debug('close it, client_id:', client_id); ifLeave && forceClientLeave(); - waiting_for_reconnecting_timer && clearTimeout(waiting_for_reconnecting_timer); + waiting_for_reconnecting_timer && + clearTimeout(waiting_for_reconnecting_timer); waiting_for_reconnecting_timer = null; try { @@ -338,13 +362,13 @@ var Connection = function(spec, socket, reconnectionKey, portal, dock) { }; -var SocketIOServer = function(spec, portal, observer) { - var that = {}; - var io; - var clients = {}; +const SocketIOServer = function(spec, portal, observer) { + const that = {}; + let io; + let clients = {}; // A Socket.IO server has a unique reconnection key. Client cannot reconnect to another Socket.IO server in the cluster. - var reconnection_key = require('crypto').randomBytes(64).toString('hex'); - var sioOptions = {}; + const reconnection_key = require('crypto').randomBytes(64).toString('hex'); + const sioOptions = {}; // TODO: remove allowEIO3 sioOptions.allowEIO3 = true; if (spec.pingInterval) { @@ -363,25 +387,29 @@ var SocketIOServer = function(spec, portal, observer) { }; } - var startInsecure = function(port) { - var server = require('http').createServer().listen(port); + const startInsecure = function(port) { + const server = require('http').createServer().listen(port); io = require('socket.io')(server, sioOptions); run(); return Promise.resolve('ok'); }; - var startSecured = function(port, keystorePath, forceTlsv12) { + const startSecured = function(port, keystorePath, forceTlsv12) { return new Promise(function(resolve, reject) { - var cipher = require('./cipher'); - var keystore = path.resolve(path.dirname(keystorePath), cipher.kstore); + const cipher = require('./cipher'); + const keystore = path.resolve(path.dirname(keystorePath), cipher.kstore); cipher.unlock(cipher.k, keystore, function(err, passphrase) { if (!err) { - var option = {pfx: require('fs').readFileSync(keystorePath), passphrase: passphrase}; + const option = { + pfx: require('fs').readFileSync(keystorePath), + passphrase: passphrase, + }; if (forceTlsv12) { - var constants = require('constants'); - option.secureOptions = (constants.SSL_OP_NO_TLSv1 | constants.SSL_OP_NO_TLSv1_1); + const constants = require('constants'); + option.secureOptions = + (constants.SSL_OP_NO_TLSv1 | constants.SSL_OP_NO_TLSv1_1); } - var server = require('https').createServer(option).listen(port); + const server = require('https').createServer(option).listen(port); io = require('socket.io')(server, sioOptions); run(); resolve('ok'); @@ -392,9 +420,9 @@ var SocketIOServer = function(spec, portal, observer) { }); }; - var run = function() { + const run = function() { io.sockets.on('connection', function(socket) { - var conn = Connection(spec, socket, reconnection_key, portal, that); + const conn = Connection(spec, socket, reconnection_key, portal, that); setTimeout(() => { if (!conn.isInService()) { @@ -435,7 +463,7 @@ var SocketIOServer = function(spec, portal, observer) { }; that.stop = function() { - for(var pid in clients) { + for (const pid in clients) { clients[pid].drop(); } clients = {}; @@ -444,7 +472,9 @@ var SocketIOServer = function(spec, portal, observer) { }; that.notify = function(participantId, event, data) { - log.debug('notify participant:', participantId, 'event:', event, 'data:', data); + log.debug('notify participant:', participantId, + 'event:', event, + 'data:', data); if (clients[participantId]) { clients[participantId].notify(event, data); return Promise.resolve('ok'); @@ -454,20 +484,23 @@ var SocketIOServer = function(spec, portal, observer) { }; that.broadcast = function(controller, excludeList, event, data) { - log.debug('broadcast controller:', controller, 'exclude:', excludeList, 'event:', event, 'data:', data); + log.debug('broadcast controller:', controller, + 'exclude:', excludeList, + 'event:', event, + 'data:', data); portal.getParticipantsByController('node', controller) - .then(function (receivers) { - for (let clientId of receivers) { - if (!excludeList.includes(clientId)) { - clients[clientId].notify(event, data); + .then(function(receivers) { + for (const clientId of receivers) { + if (!excludeList.includes(clientId)) { + clients[clientId].notify(event, data); + } } - } - }); - } + }); + }; that.drop = function(participantId) { if (participantId === 'all') { - for(var pid in clients) { + for (const pid in clients) { clients[pid].drop(); } } else if (clients[participantId]) { From f9b6f55025f860968cf35298bdfd291bb72bd040 Mon Sep 17 00:00:00 2001 From: DWJ01 <1521974869@qq.com> Date: Wed, 7 Apr 2021 03:20:50 +0800 Subject: [PATCH 6/6] Fix linting problems in portal code --- source/common/amqpClient.js | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/source/common/amqpClient.js b/source/common/amqpClient.js index c740c19d4..2cfd8d4cd 100644 --- a/source/common/amqpClient.js +++ b/source/common/amqpClient.js @@ -146,19 +146,12 @@ class RpcClient { clearTimeout(this.callMap[i].timer); } this.callMap = {}; -<<<<<<< HEAD - return this.bus.channel.cancel(this.consumerTag) - .catch(() => { - log.error('Failed during close RpcClient:', this.replyQ); - }); -======= if (this.consumerTag) { return this.bus.channel.cancel(this.consumerTag) .catch((err) => { log.error('Failed during close RpcClient:', this.replyQ); }); } ->>>>>>> 37bc75675b9b28e638abc532b3ef0b37704eb4e3 } } @@ -334,20 +327,12 @@ class TopicParticipant { close() { this.ready = false; -<<<<<<< HEAD - return this.bus.channel.deleteQueue(this.queue) - .catch(() => { - log.error('Failed to destroy queue:', this.queue); - }) - .catch(() => log.error('Failed to delete exchange:', this.name)); -======= if (this.queue) { return this.bus.channel.deleteQueue(this.queue) .catch((err) => { log.error('Failed to destroy queue:', this.queue); }); } ->>>>>>> 37bc75675b9b28e638abc532b3ef0b37704eb4e3 } } @@ -386,14 +371,6 @@ class Monitor { close() { this.ready = false; -<<<<<<< HEAD - return this.bus.channel.cancel(this.consumerTag) - .catch((err) => { - log.error('Failed to cancel consumer on queue:', this.queue); - }) - .catch((err) => log.error('Failed to delete exchange:', this.name)); - } -======= if (this.consumerTag) { return this.bus.channel.cancel(this.consumerTag) .catch((err) => { @@ -401,7 +378,6 @@ class Monitor { }); } }; ->>>>>>> 37bc75675b9b28e638abc532b3ef0b37704eb4e3 } class MonitoringTarget {