TT#5036 Create http client to access janus admin api

Change-Id: I2d71a012529d9e589737fad9c518265f3ed8d27a
changes/64/9164/1
Hans-Peter Herzog 10 years ago
parent 63a8657ce0
commit 2bd852cd15

@ -0,0 +1,12 @@
root = true
[*.{js,ts,json,html,css,scss,less,md,gitignore,editorconfig}]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false

24
.gitignore vendored

@ -0,0 +1,24 @@
# Eclipse
.classpath
.project
.settings/
# Intellij
.idea/
*.iml
*.iws
# Mac
.DS_Store
# Maven
log/
target/
# Node.js
node_modules/
npm-debug.log
# Bower
bower_components/

@ -0,0 +1,100 @@
JanusAdmin
===========
JanusAdmin is a node.js http client, that implements the entire admin interface of the Janus WebRTC Gateway.
Usage
-------------
var JanusAdmin = require('janus-admin').JanusAdmin;
var admin = new JanusAdmin({
url: 'http://janus-admin:7088',
secret: '*****'
});
Methods
---------------
### List sessions
admin.listSessions().then((res)=>{
console.log(res.sessions)
}).catch((err)=>{
...
});
### List handles
admin.listHandles(sessionId).then((res)=>{
console.log(res.handles)
}).catch((err)=>{
...
});
### Show single handle
admin.handleInfo(sessionId, handleId).then((res)=>{
console.log(res.info)
}).catch((err)=>{
...
});
### Set the log level
admin.setLogLevel([0...7]).then((res)=>{
console.log(res.level)
}).catch((err)=>{
...
});
### Set locking debug
admin.setLockingDebug([0,1]).then((res)=>{
console.log(res.debug)
}).catch((err)=>{
...
});
Methods (token based authentication)
------------------------------------
### Add token
admin.addToken(token).then((res)=>{
console.log(res.plugins);
}).catch((err)=>{
...
});
### Allow token
admin.allowToken(token, plugins).then((res)=>{
console.log(res.plugins);
}).catch((err)=>{
...
});
### Disallow token
admin.disallowToken(token, plugins).then((res)=>{
console.log(res.plugins);
}).catch((err)=>{
...
});
### List all tokens
admin.listTokens().then((res)=>{
console.log(res.tokens);
}).catch((err)=>{
...
});
### Remove token
adminClient.removeToken(token).then((res)=>{
...
}).catch((err)=>{
...
});

@ -0,0 +1,26 @@
{
"name": "janus-admin",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "mocha -R spec",
"test-dev": "mocha -R spec -w"
},
"author": "Hans-Peter Herzog",
"license": "ISC",
"description": "Http client to access the janus admin endpoint",
"devDependencies": {
"body-parser": "^1.15.2",
"express": "^4.14.0",
"mocha": "^3.1.2"
},
"dependencies": {
"chai": "^3.5.0",
"debug-logger": "^0.4.1",
"lodash": "^4.16.4",
"superagent": "^2.3.0",
"uuid": "^2.0.3",
"validator": "^6.1.0",
"yargs": "^6.3.0"
}
}

@ -0,0 +1,230 @@
'use strict';
var validator = require('validator');
var _ = require('lodash');
var createId = require('uuid').v4;
var assert = require('chai').assert;
var userAgent = require('superagent');
var Response = require('./response').Response;
var ResponseError = require('./error').ResponseError;
/**
* @class
*/
class Admin {
constructor(options) {
assert.property(options, 'url', 'Missing option url');
assert(validator.isURL(options.url), 'Invalid url');
assert.property(options, 'secret');
this.url = options.url;
this.secret = options.secret;
this.userAgent = options.userAgent || userAgent;
}
makeUrl(path) {
return this.url + path;
}
request(req, options) {
return new Promise((resolve, reject)=>{
var path = _.get(options, 'path', '/admin');
req.admin_secret = this.secret;
req.transaction = createId();
this.userAgent.post(this.makeUrl(path)).type('json').send(req).end((err, res)=>{
if(_.isObject(err)) {
return reject(err);
}
var response = new Response(req, res.body);
if(response.isSuccess()) {
resolve(response);
} else {
reject(new ResponseError(response));
}
});
});
}
listSessions() {
return new Promise((resolve, reject)=>{
this.request({
janus: 'list_sessions'
}).then((res)=>{
resolve({
sessions: _.get(res.getResponse(), 'sessions', []),
response: res
});
}).catch((err)=>{
reject(err);
});
});
}
listHandles(sessionId) {
return new Promise((resolve, reject)=>{
assert.isString(sessionId);
this.request({
janus: 'list_handles'
}, {
path: '/admin/' + sessionId
}).then((res)=>{
resolve({
handles: _.get(res.getResponse(), 'handles', []),
response: res
});
}).catch((err)=>{
reject(err);
});
});
}
handleInfo(sessionId, handleId) {
return new Promise((resolve, reject)=>{
assert.isString(sessionId);
assert.isString(handleId);
this.request({
janus: 'handle_info'
}, {
path: '/admin/' + sessionId + '/' + handleId
}).then((res)=>{
resolve({
info: _.get(res.getResponse(), 'info', {}),
response: res
});
}).catch((err)=>{
reject(err);
});
});
}
setLogLevel(level) {
return new Promise((resolve, reject)=>{
assert.isNumber(level);
assert(_.inRange(level, 0, 8), 'Invalid log level');
this.request({
janus: 'set_log_level',
level: level
}).then((res)=>{
resolve({
level: res.getResponse().level,
response: res
});
}).catch((err)=>{
reject(err);
});
});
}
setLockingDebug(debug) {
return new Promise((resolve, reject)=>{
assert.isNumber(debug);
this.request({
janus: 'set_locking_debug',
debug: debug
}).then((res)=>{
resolve({
debug: res.getResponse().debug,
response: res
});
}).catch((err)=>{
reject(err);
});
});
}
addToken(token, plugins) {
return new Promise((resolve, reject)=>{
assert.isString(token);
var request = {
janus: 'add_token',
token: token
};
if(_.isArray(plugins)) {
request.plugins = plugins;
}
this.request(request).then((res)=>{
resolve({
plugins: res.getResponse().data.plugins,
response: res
});
}).catch((err)=>{
reject(err);
});
});
}
allowToken(token, plugins) {
return new Promise((resolve, reject)=>{
assert.isString(token);
assert.isArray(plugins);
assert(plugins.length > 0, 'Need at least one plugin to allow');
this.request({
janus: 'allow_token',
token: token,
plugins: plugins
}).then((res)=>{
resolve({
plugins: res.getResponse().data.plugins,
response: res
});
}).catch((err)=>{
reject(err);
});
});
}
disallowToken(token, plugins) {
return new Promise((resolve, reject)=>{
assert.isString(token);
assert.isArray(plugins);
assert(plugins.length > 0, 'Need at least one plugin to disallow');
this.request({
janus: 'disallow_token',
token: token,
plugins: plugins
}).then((res)=>{
resolve({
plugins: res.getResponse().data.plugins,
response: res
});
}).catch((err)=>{
reject(err);
});
});
}
listTokens() {
return new Promise((resolve, reject)=>{
this.request({
janus: 'list_tokens'
}).then((res)=>{
resolve({
tokens: res.getResponse().data.tokens,
response: res
});
}).catch((err)=>{
reject(err);
});
});
}
removeToken(token) {
return new Promise((resolve, reject)=>{
this.request({
janus: 'remove_token',
token: token
}).then((res)=>{
resolve({
response: res
});
}).catch((err)=>{
reject(err);
});
});
}
}
module.exports.JanusAdmin = Admin;

@ -0,0 +1,20 @@
'use strict';
var assert = require('chai').assert;
/**
* @class
*/
class ResponseError extends Error {
constructor(res) {
super();
assert.equal(res.isError(), true, 'No error found in response');
this.name = this.constructor.name;
this.message = res.getErrorMessage();
this.code = res.getErrorCode();
this.response = res;
}
}
module.exports.ResponseError = ResponseError;

@ -0,0 +1,225 @@
'use strict';
process.env.DEBUG = '';
var _ = require('lodash');
var http = require('http');
var express = require('express');
var bodyParser = require('body-parser');
var logger = require('debug-logger')('mock:janus-admin-server');
/**
* @class
*/
class JanusAdminServer {
constructor(options) {
options = options || {};
this.port = options.port || 9000;
this.app = express();
this.http = null;
}
init() {
return new Promise((resolve, reject)=>{
var requestHandler = (req, res, next)=>{ this.dispatchRequest(req, res, next); }
this.app.use(bodyParser.json());
this.app.use((req, res, next)=>{
logger.info('Request', req.originalUrl, req.body);
next();
});
this.app.post('/admin', requestHandler);
this.app.post('/admin/:sessionId', requestHandler);
this.app.post('/admin/:sessionId/:handleId', requestHandler);
this.http = http.createServer(this.app);
this.http.listen(this.port, (err)=>{
if(_.isObject(err)) {
reject(err);
} else {
logger.info('Started');
resolve();
}
});
});
}
getUrl() {
return 'http://localhost:' + this.port;
}
getAdminSecret() {
return 'master';
}
dispatchRequest(req, res, next) {
switch(req.body.janus) {
case 'list_sessions':
this.listSessions(req, res, next);
break;
case 'list_handles':
this.listHandles(req, res, next);
break;
case 'handle_info':
this.handleInfo(req, res, next);
break;
case 'set_log_level':
this.setLogLevel(req, res, next);
break;
case 'set_locking_debug':
this.setLockingDebug(req, res, next);
break;
case 'add_token':
this.addToken(req, res, next);
break;
case 'allow_token':
this.allowToken(req, res, next);
break;
case 'disallow_token':
this.disallowToken(req, res, next);
break;
case 'list_tokens':
this.listTokens(req, res, next);
break;
case 'remove_token':
this.removeToken(req, res, next);
break;
}
}
listSessions(req, res, next) {
res.json({
janus: 'success',
transaction: req.body.transaction,
session: []
});
}
listHandles(req, res, next) {
res.json({
janus: 'success',
transaction: req.body.transaction,
session_id: req.params.sessionId,
handles: []
});
}
handleInfo(req, res, next) {
res.json({
janus: 'success',
transaction: req.body.transaction,
session_id: req.params.sessionId,
handle_id: req.params.handleId,
info: {
}
});
}
setLogLevel(req, res, next) {
res.json({
janus: 'success',
transaction: req.body.transaction,
level: req.body.level
});
}
setLockingDebug(req, res, next) {
res.json({
janus: 'success',
transaction: req.body.transaction,
debug: req.body.debug
});
}
addToken(req, res, next) {
var plugins = [
"janus.plugin.audiobridge",
"janus.plugin.voicemail",
"janus.plugin.echotest",
"janus.plugin.recordplay",
"janus.plugin.videoroom",
"janus.plugin.videocall",
"janus.plugin.streaming",
"janus.plugin.sip"
];
if(_.isArray(req.body.plugins)) {
plugins = req.body.plugins;
}
res.json({
"janus": "success",
"transaction": req.body.transaction,
"data": {
"plugins": plugins
}
});
}
allowToken(req, res, next) {
var plugins = [
"janus.plugin.audiobridge",
"janus.plugin.voicemail"
];
plugins = req.body.plugins.concat(plugins);
res.json({
"janus": "success",
"transaction": req.body.transaction,
"data": {
"plugins": plugins
}
});
}
disallowToken(req, res, next) {
var plugins = [
"janus.plugin.audiobridge",
"janus.plugin.voicemail"
];
res.json({
"janus": "success",
"transaction": req.body.transaction,
"data": {
"plugins": plugins
}
});
}
listTokens(req, res, next) {
res.json({
"janus": "success",
"transaction": req.body.transaction,
"data": {
"tokens": [
{
"token": "abcdef",
"allowed_plugins": [
"janus.plugin.audiobridge",
"janus.plugin.voicemail",
"janus.plugin.recordplay",
"janus.plugin.videocall",
"janus.plugin.streaming",
"janus.plugin.sip",
"janus.plugin.videoroom",
"janus.plugin.echotest"
]
}
]
}
});
}
removeToken(req, res, next) {
res.json({
"janus": "success",
"transaction": req.body.transaction
});
}
}
module.exports.JanusAdminServer = JanusAdminServer;

@ -0,0 +1,43 @@
'use strict';
var _ = require('lodash');
var assert = require('chai').assert;
/**
* @class
*/
class Response {
constructor(req, res) {
assert.property(res, 'janus', 'Invalid response');
this.request = req;
this.response = res;
}
getRequest() {
return this.request;
}
getResponse() {
return this.response;
}
isSuccess() {
return this.response.janus === 'success';
}
isError() {
return this.response.janus === 'error' && _.has(this.response, 'error');
}
getErrorCode() {
return _.get(this.response, 'error.code', null);
}
getErrorMessage() {
return _.get(this.response, 'error.reason', null);
}
}
module.exports.Response = Response;

@ -0,0 +1,168 @@
'use strict';
var Admin = require('../src/admin').JanusAdmin;
var assert = require('chai').assert;
var _ = require('lodash');
var JanusAdminServer = require('../src/mock/janus-admin-server').JanusAdminServer;
describe('Admin', function() {
var adminServer;
var adminClient;
before(function(done){
adminServer = new JanusAdminServer();
adminServer.init().then(()=>{
done();
}).catch((err)=>{
done(err);
});
});
beforeEach(function(){
adminClient = new Admin({
url: adminServer.getUrl(),
secret: adminServer.getAdminSecret()
});
});
it('should throw an error caused by missing option url', function(done){
try {
adminClient = new Admin({
secret: adminServer.getAdminSecret()
});
} catch(err) {
done();
}
});
it('should throw an error caused by invalid url', function(done){
try {
adminClient = new Admin({
url: 'foo',
secret: adminServer.getAdminSecret()
});
} catch(err) {
done();
}
});
it('should list all sessions', function(done){
adminClient.listSessions().then((res)=>{
assert.isArray(res.sessions);
done();
}).catch((err)=>{
done(err);
});
});
it('should list all handles', function(done){
adminClient.listHandles('123456').then((res)=>{
assert.isArray(res.handles);
done();
}).catch((err)=>{
done(err);
});
});
it('should fetch single handle', function(done){
adminClient.handleInfo('123456', '123456').then((res)=>{
assert.isObject(res.info);
done();
}).catch((err)=>{
done(err);
});
});
it('should set the log level', function(done){
adminClient.setLogLevel(7).then((res)=>{
assert.equal(res.level, 7);
done();
}).catch((err)=>{
done(err);
});
});
it('should throw an error, caused by wrong log level', function(done){
adminClient.setLogLevel(8).then(()=>{
done(new Error());
}).catch(()=>{
done();
});
});
it('should set locking debug', function(done){
adminClient.setLockingDebug(1).then((res)=>{
assert.equal(res.debug, 1);
done();
}).catch((err)=>{
done(err);
});
});
describe('Token based authentication',function(){
var exampleToken = 'abcdef';
var examplePlugins = [
'janus.plugin.videoroom',
'janus.plugin.echotest'
];
it('should add a new token', function(done){
adminClient.addToken(exampleToken).then((res)=>{
assert.isArray(res.plugins);
done();
}).catch((err)=>{
done(err);
});
});
it('should add a new token, that has access to a set of given plugins', function(done){
adminClient.addToken(exampleToken, examplePlugins).then((res)=>{
assert.isArray(res.plugins);
assert.deepEqual(examplePlugins, res.plugins);
done();
}).catch((err)=>{
done(err);
});
});
it('should allow a token to access a set of given plugins', function(done){
adminClient.allowToken(exampleToken, examplePlugins).then((res)=>{
assert.isArray(res.plugins);
assert.deepEqual(_.intersection(res.plugins, examplePlugins), examplePlugins);
done();
}).catch((err)=>{
done(err);
});
});
it('should disallow a token to access a set of given plugins', function(done){
adminClient.disallowToken(exampleToken, examplePlugins).then((res)=>{
assert.isArray(res.plugins);
assert.deepEqual(_.intersection(res.plugins, examplePlugins), []);
done();
}).catch((err)=>{
done(err);
});
});
it('should list all tokens', function(done){
adminClient.listTokens().then((res)=>{
assert.isArray(res.tokens);
done();
}).catch((err)=>{
done(err);
});
});
it('should remove a token', function(done){
adminClient.removeToken(exampleToken).then((res)=>{
done();
}).catch((err)=>{
done(err);
});
});
});
});
Loading…
Cancel
Save