UNPKG

opentok

Version:
559 lines (503 loc) 15.4 kB
var requestRoot = require('request'); var request = requestRoot; var _ = require('lodash'); var generateJwt = require('./generateJwt'); var pkg = require('../package.json'); var Stream = require('./stream'); var Broadcast = require('./broadcast'); var defaultConfig = { apiKey: null, apiSecret: null, apiUrl: 'https://api.opentok.com', endpoints: { createSession: '/session/create', getStream: '/v2/project/<%apiKey%>/session/<%sessionId%>/stream/<%streamId%>', listStreams: '/v2/project/<%apiKey%>/session/<%sessionId%>/stream', setArchiveLayout: '/v2/project/<%apiKey%>/archive/<%archiveId%>/layout', setStreamClassLists: '/v2/project/<%apiKey%>/session/<%sessionId%>/stream', dial: '/v2/project/<%apiKey%>/dial', playDTMFToSession: '/v2/project/<%apiKey%>/session/<%sessionId%>/play-dtmf', playDTMFToClient: '/v2/project/<%apiKey%>/session/<%sessionId%>/connection/<%connectionId%>/play-dtmf', forceMuteStream: '/v2/project/<%apiKey%>/session/<%sessionId%>/stream/<%streamId%>/mute', forceMute: '/v2/project/<%apiKey%>/session/<%sessionId%>/mute', startBroadcast: '/v2/project/<%apiKey%>/broadcast', stopBroadcast: '/v2/project/<%apiKey%>/broadcast/<%broadcastId%>/stop', getBroadcast: '/v2/project/<%apiKey%>/broadcast/<%broadcastId%>', patchBroadcast: '/v2/project/<%apiKey%>/broadcast/<%broadcastId%>/streams', setBroadcastLayout: '/v2/project/<%apiKey%>/broadcast/<%broadcastId%>/layout', listBroadcasts: '/v2/project/<%apiKey%>/broadcast' }, request: { timeout: 20000 // 20 seconds }, auth: { expire: 300 } }; var Client = function (c) { this.c = {}; this.config(_.defaults(c, defaultConfig)); }; Client.prototype.config = function (c) { _.merge(this.c, c); if (this.c.endpoints && this.c.endpoints.dial && this.c.apiKey) { this.c.endpoints.dial = this.c.endpoints.dial.replace( /<%apiKey%>/g, this.c.apiKey ); } if ('request' in this.c) { request = requestRoot.defaults(this.c.request); } return this.c; }; Client.prototype.createSession = function (opts, cb) { request.post( { // TODO: only works while apiUrl is always up to the domain, without the ending slash url: this.c.apiUrl + this.c.endpoints.createSession, form: opts, json: true, headers: this.generateHeaders() }, function (err, resp, body) { if (err) { return cb(new Error('The request failed: ' + err)); } // handle client errors if (resp.statusCode === 403) { return cb(new Error('An authentication error occurred: (' + resp.statusCode + ') ' + JSON.stringify(body))); } // handle server errors if (resp.statusCode >= 500 && resp.statusCode <= 599) { return cb(new Error('A server error occurred: (' + resp.statusCode + ') ' + JSON.stringify(body))); } // check if the returned object is valid JSON if (typeof body !== 'object') { return cb(new Error('Server returned invalid JSON')); } return cb(null, body); } ); }; Client.prototype.startArchive = function () {}; Client.prototype.stopArchive = function () {}; Client.prototype.getArchive = function () {}; Client.prototype.listArchives = function () {}; Client.prototype.deleteArchive = function () {}; Client.prototype.playDTMF = function (opts, cb) { var url; if (opts.sessionId) { url = this.c.apiUrl + this.c.endpoints.playDTMFToSession .replace(/<%apiKey%>/g, this.c.apiKey) .replace(/<%sessionId%>/g, opts.sessionId); } if (opts.connectionId) { url = this.c.apiUrl + this.c.endpoints.playDTMFToClient .replace(/<%apiKey%>/g, this.c.apiKey) .replace(/<%sessionId%>/g, opts.sessionId) .replace(/<%connectionId%>/g, opts.connectionId); } request.post( { url: url, json: { digits: opts.digits }, headers: this.generateHeaders() }, function (err, resp, body) { if (err) return cb(new Error('The request failed: ' + err)); if (resp.statusCode === 200) { // Success return cb(null); } return cb(new Error('(' + resp.statusCode + ') ' + JSON.stringify(body))); } ); }; Client.prototype.forceMuteStream = function (opts, cb) { var url = this.c.apiUrl + this.c.endpoints.forceMuteStream .replace(/<%apiKey%>/g, this.c.apiKey) .replace(/<%sessionId%>/g, opts.sessionId) .replace(/<%streamId%>/g, opts.streamId); request.post( { url: url, headers: this.generateHeaders() }, function (err, resp, body) { if (err) return cb(new Error('The request failed: ' + err)); if (resp.statusCode === 200) { // Success return cb(null); } return cb(new Error('(' + resp.statusCode + ') ' + JSON.stringify(body))); } ); }; Client.prototype.forceMuteAll = function (opts, cb) { var url = this.c.apiUrl + this.c.endpoints.forceMute .replace(/<%apiKey%>/g, this.c.apiKey) .replace(/<%sessionId%>/g, opts.sessionId); opts.options.active = true; request.post( { url: url, json: opts.options, headers: this.generateHeaders() }, function (err, resp, body) { if (err) return cb(new Error('The request failed: ' + err)); if (resp.statusCode === 200) { // Success return cb(null); } return cb(new Error('(' + resp.statusCode + ') ' + JSON.stringify(body))); } ); }; Client.prototype.disableForceMute = function (opts, cb) { var url = this.c.apiUrl + this.c.endpoints.forceMute .replace(/<%apiKey%>/g, this.c.apiKey) .replace(/<%sessionId%>/g, opts.sessionId); var options = { active: false }; request.post( { url: url, json: options, headers: this.generateHeaders() }, function (err, resp, body) { if (err) return cb(new Error('The request failed: ' + err)); if (resp.statusCode === 200) { // Success return cb(null); } return cb(new Error('(' + resp.statusCode + ') ' + JSON.stringify(body))); } ); }; Client.prototype.setArchiveLayout = function setArchiveLayout(opts, cb) { var url = this.c.apiUrl + this.c.endpoints.setArchiveLayout .replace(/<%apiKey%>/g, this.c.apiKey) .replace(/<%archiveId%>/g, opts.archiveId); request.put( { url: url, headers: this.generateHeaders(), json: true, body: { type: opts.type, stylesheet: opts.stylesheet || undefined, screenshareType: opts.screenshareType || undefined } }, function requestCallback(err, resp, body) { if (err) { return cb(new Error('The request failed: ' + err)); } if (resp.statusCode === 200) { return cb(null, body); } return cb(new Error('(' + resp.statusCode + ') ' + body.message)); } ); }; Client.prototype.startBroadcast = function (opts, cb) { var url = this.c.apiUrl + this.c.endpoints.startBroadcast.replace(/<%apiKey%>/g, this.c.apiKey); request.post( { url: url, json: opts, headers: this.generateHeaders() }, function (err, resp, body) { if (err) return cb(new Error('The request failed: ' + err)); if (resp.statusCode === 200) { // Success return cb(null, JSON.stringify(body)); } return cb(new Error('(' + resp.statusCode + ') ' + JSON.stringify(body))); } ); }; Client.prototype.patchBroadcast = function patchBroadcast(broadcastId, opts, cb) { var url = this.c.apiUrl + this.c.endpoints.patchBroadcast.replace(/<%apiKey%>/g, this.c.apiKey) .replace(/<%broadcastId%>/g, broadcastId); request.patch({ url: url, json: opts, headers: this.generateHeaders() }, function (err, resp, body) { if (err) return cb(new Error('The request failed')); if (resp.statusCode === 200) { return cb(null, JSON.stringify(body)); } return cb(new Error('(' + resp.statusCode + ') ' + JSON.stringify(body))); }); }; Client.prototype.stopBroadcast = function (broadcastId, cb) { var url = this.c.apiUrl + this.c.endpoints.stopBroadcast .replace(/<%apiKey%>/g, this.c.apiKey) .replace(/<%broadcastId%>/g, broadcastId); request.post( { url: url, headers: this.generateHeaders() }, function (err, resp, body) { if (err) return cb(new Error('The request failed: ' + err)); if (resp.statusCode === 200) { // Success return cb(null, body); } return cb(new Error('(' + resp.statusCode + ') ' + JSON.parse(body).message)); } ); }; Client.prototype.getBroadcast = function getBroadcast(broadcastId, cb) { var url = this.c.apiUrl + this.c.endpoints.getBroadcast .replace(/<%apiKey%>/g, this.c.apiKey) .replace(/<%broadcastId%>/g, broadcastId); request.get( { url: url, headers: this.generateHeaders() }, function requestCallback(err, resp, body) { if (err) { return cb(new Error('The request failed: ' + err)); } if (resp.statusCode === 200) { return cb(null, body); } return cb(new Error('(' + resp.statusCode + ') ' + body ? body.message : '')); } ); }; Client.prototype.listBroadcasts = function listBroadcasts(queryString, cb) { var baseUrl = this.c.apiUrl + this.c.endpoints.listBroadcasts.replace(/<%apiKey%>/g, this.c.apiKey); var url = queryString.length > 0 ? baseUrl + '?' + queryString : baseUrl; var parsedBody; request.get( { url: url, headers: this.generateHeaders() }, function requestCallback(err, resp, body) { if (err) { return cb(new Error('The request failed: ' + err)); } if (resp.statusCode === 200) { parsedBody = JSON.parse(body); return cb( null, parsedBody.items.map(function itemIterator(item) { return new Broadcast(Client, JSON.stringify(item)); }), parsedBody.count ); } return cb(new Error('(' + resp.statusCode + ') ' + body ? body.message : '')); } ); }; Client.prototype.setBroadcastLayout = function setBroadcastLayout(opts, cb) { var url = this.c.apiUrl + this.c.endpoints.setBroadcastLayout .replace(/<%apiKey%>/g, this.c.apiKey) .replace(/<%broadcastId%>/g, opts.broadcastId); request.put( { url: url, headers: this.generateHeaders(), json: true, body: { type: opts.type, stylesheet: opts.stylesheet || undefined, screenshareType: opts.screenshareType || undefined } }, function requestCallback(err, resp, body) { if (err) { return cb(new Error('The request failed: ' + err)); } if (resp.statusCode === 200) { return cb(null, body); } return cb(new Error('(' + resp.statusCode + ') ' + body.message)); } ); }; Client.prototype.setStreamClassLists = function setStreamClassLists( sessionId, classListArray, cb ) { var url = this.c.apiUrl + this.c.endpoints.setStreamClassLists .replace(/<%apiKey%>/, this.c.apiKey) .replace(/<%sessionId%>/g, sessionId); request.put( { url: url, headers: this.generateHeaders(), json: true, body: { items: classListArray } }, function requestCallback(err, resp, body) { if (err) return cb(new Error('The request failed: ' + err)); // handle client errors switch (resp.statusCode) { case 200: return cb(null, body); case 400: return cb(new Error('Invalid session ID or stream ID (400).')); case 403: return cb(new Error('Invalid API key or secret (403).')); default: if (resp.statusCode >= 500 && resp.statusCode <= 599) { // handle server errors return cb(new Error('A server error occurred: (' + resp.statusCode + ') ' + JSON.stringify(body))); } } return cb(new Error('An unexpected error occurred: (' + resp.statusCode + ') ' + JSON.stringify(body))); } ); }; Client.prototype.dial = function (opts, cb) { request.post( { // TODO: only works while apiUrl is always up to the domain, without the ending slash url: this.c.apiUrl + this.c.endpoints.dial, json: opts, headers: this.generateHeaders() }, function (err, resp, body) { if (err) return cb(new Error('The request failed: ' + err)); // handle client errors if (resp.statusCode === 400) { if (body.code === 15204) { return cb(new Error('SIP Interconnect for Video is not enabled in this project')); } return cb(new Error('Bad session ID, token, SIP credentials, or SIP URI (sip:user@domain.tld)')); } if (resp.statusCode === 403) { return cb(new Error('Invalid API key or secret')); } if (resp.statusCode === 409) { return cb(new Error('Only Routed Sessions are allowed to initiate SIP Calls.')); } // handle server errors if (resp.statusCode >= 500 && resp.statusCode <= 599) { return cb(new Error('A server error occurred: (' + resp.statusCode + ') ' + body)); } // Parse data from server return cb(null, body); } ); }; Client.prototype.getStream = function getStream(sessionId, streamId, cb) { var url = this.c.apiUrl + this.c.endpoints.getStream .replace(/<%apiKey%>/g, this.c.apiKey) .replace(/<%streamId%>/g, streamId) .replace(/<%sessionId%>/g, sessionId); request.get( { url: url, headers: this.generateHeaders() }, function requestCallback(err, resp, body) { if (err) { return cb(new Error('The request failed: ' + err)); } if (resp.statusCode === 200) { return cb(null, body); } return cb(new Error('(' + resp.statusCode + ') ' + body.message)); } ); }; Client.prototype.listStreams = function listStreams(sessionId, cb) { var url = this.c.apiUrl + this.c.endpoints.listStreams .replace(/<%apiKey%>/g, this.c.apiKey) .replace(/<%sessionId%>/g, sessionId); request.get( { url: url, headers: this.generateHeaders() }, function requestCallback(err, resp, body) { if (err) { return cb(new Error('The request failed: ' + err)); } if (resp.statusCode === 200) { return cb( null, JSON.parse(body).items.map(function itemIterator(item) { return new Stream(JSON.stringify(item)); }) ); } return cb(new Error('(' + resp.statusCode + ') ' + body.message)); } ); }; Client.prototype.generateHeaders = function () { return { 'User-Agent': 'OpenTok-Node-SDK/' + pkg.version + (this.c.uaAddendum ? ' ' + this.c.uaAddendum : ''), 'X-OPENTOK-AUTH': generateJwt(this.c), Accept: 'application/json' }; }; module.exports = Client;