@twilio/voice-sdk
Version:
Twilio's JavaScript Voice SDK
291 lines • 22.1 kB
JavaScript
;
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
// @ts-nocheck
var events_1 = require("events");
var log_1 = require("./log");
var request_1 = require("./request");
/**
* Builds Endpoint Analytics (EA) event payloads and sends them to
* the EA server.
* @constructor
* @param {String} productName - Name of the product publishing events.
* @param {String} token - The JWT token to use to authenticate with
* the EA server.
* @param {EventPublisher.Options} options
* @property {Boolean} isEnabled - Whether or not this publisher is publishing
* to the server. Currently ignores the request altogether, in the future this
* may store them in case publishing is re-enabled later. Defaults to true.
*/
/**
* @typedef {Object} EventPublisher.Options
* @property {Object} [metadata=undefined] - A publisher_metadata object to send
* with each payload.
* @property {String} [host='eventgw.twilio.com'] - The host address of the EA
* server to publish to.
* @property {Object|Function} [defaultPayload] - A default payload to extend
* when creating and sending event payloads. Also takes a function that
* should return an object representing the default payload. This is
* useful for fields that should always be present when they are
* available, but are not always available.
*/
var EventPublisher = /** @class */ (function (_super) {
__extends(EventPublisher, _super);
function EventPublisher(productName, token, options) {
var _this = _super.call(this) || this;
if (!(_this instanceof EventPublisher)) {
return new EventPublisher(productName, token, options);
}
// Apply default options
options = Object.assign({ defaultPayload: function () { return {}; } }, options);
var defaultPayload = options.defaultPayload;
if (typeof defaultPayload !== 'function') {
defaultPayload = function () { return Object.assign({}, options.defaultPayload); };
}
var isEnabled = true;
var metadata = Object.assign({ app_name: undefined, app_version: undefined }, options.metadata);
Object.defineProperties(_this, {
_defaultPayload: { value: defaultPayload },
_host: { value: options.host, writable: true },
_isEnabled: {
get: function () { return isEnabled; },
set: function (_isEnabled) { isEnabled = _isEnabled; },
},
_log: { value: new log_1.default('EventPublisher') },
_request: { value: options.request || request_1.default, writable: true },
_token: { value: token, writable: true },
isEnabled: {
enumerable: true,
get: function () { return isEnabled; },
},
metadata: {
enumerable: true,
get: function () { return metadata; },
},
productName: { enumerable: true, value: productName },
token: {
enumerable: true,
get: function () { return this._token; },
},
});
return _this;
}
return EventPublisher;
}(events_1.EventEmitter));
/**
* Post to an EA server.
* @private
* @param {String} endpointName - Endpoint to post the event to
* @param {String} level - ['debug', 'info', 'warning', 'error']
* @param {String} group - The name of the group the event belongs to.
* @param {String} name - The designated event name.
* @param {?Object} [payload=null] - The payload to pass. This will be extended
* onto the default payload object, if one exists.
* @param {?Connection} [connection=null] - The {@link Connection} which is posting this payload.
* @param {?Boolean} [force=false] - Whether or not to send this even if
* publishing is disabled.
* @returns {Promise} Fulfilled if the HTTP response is 20x.
*/
EventPublisher.prototype._post = function _post(endpointName, level, group, name, payload, connection, force) {
var _this = this;
if ((!this.isEnabled && !force) || !this._host) {
this._log.debug('Publishing cancelled', JSON.stringify({ isEnabled: this.isEnabled, force: force, host: this._host }));
return Promise.resolve();
}
if (!connection || ((!connection.parameters || !connection.parameters.CallSid) && !connection.outboundConnectionId)) {
if (!connection) {
this._log.debug('Publishing cancelled. Missing connection object');
}
else {
this._log.debug('Publishing cancelled. Missing connection info', JSON.stringify({
outboundConnectionId: connection.outboundConnectionId, parameters: connection.parameters,
}));
}
return Promise.resolve();
}
var event = {
group: group,
level: level.toUpperCase(),
name: name,
payload: (payload && payload.forEach) ?
payload.slice(0) : Object.assign(this._defaultPayload(connection), payload),
payload_type: 'application/json',
private: false,
publisher: this.productName,
timestamp: (new Date()).toISOString(),
};
if (this.metadata) {
event.publisher_metadata = this.metadata;
}
if (endpointName === 'EndpointEvents') {
this._log.debug('Publishing insights', JSON.stringify({ endpointName: endpointName, event: event, force: force, host: this._host }));
}
var requestParams = {
body: event,
headers: {
'Content-Type': 'application/json',
'X-Twilio-Token': this.token,
},
url: "https://".concat(this._host, "/v4/").concat(endpointName),
};
return new Promise(function (resolve, reject) {
_this._request.post(requestParams, function (err) {
if (err) {
_this.emit('error', err);
reject(err);
}
else {
resolve();
}
});
}).catch(function (e) {
_this._log.error("Unable to post ".concat(group, " ").concat(name, " event to Insights. Received error: ").concat(e));
});
};
/**
* Post an event to the EA server. Use this method when the level
* is dynamic. Otherwise, it's better practice to use the sugar
* methods named for the specific level.
* @param {String} level - ['debug', 'info', 'warning', 'error']
* @param {String} group - The name of the group the event belongs to.
* @param {String} name - The designated event name.
* @param {?Object} [payload=null] - The payload to pass. This will be extended
* onto the default payload object, if one exists.
* @param {?Connection} [connection=null] - The {@link Connection} which is posting this payload.
* @returns {Promise} Fulfilled if the HTTP response is 20x.
*/
EventPublisher.prototype.post = function post(level, group, name, payload, connection, force) {
return this._post('EndpointEvents', level, group, name, payload, connection, force);
};
/**
* Post a debug-level event to the EA server.
* @param {String} group - The name of the group the event belongs to.
* @param {String} name - The designated event name.
* @param {?Object} [payload=null] - The payload to pass. This will be extended
* onto the default payload object, if one exists.
* @param {?Connection} [connection=null] - The {@link Connection} which is posting this payload.
* @returns {Promise} Fulfilled if the HTTP response is 20x.
*/
EventPublisher.prototype.debug = function debug(group, name, payload, connection) {
return this.post('debug', group, name, payload, connection);
};
/**
* Post an info-level event to the EA server.
* @param {String} group - The name of the group the event belongs to.
* @param {String} name - The designated event name.
* @param {?Object} [payload=null] - The payload to pass. This will be extended
* onto the default payload object, if one exists.
* @param {?Connection} [connection=null] - The {@link Connection} which is posting this payload.
* @returns {Promise} Fulfilled if the HTTP response is 20x.
*/
EventPublisher.prototype.info = function info(group, name, payload, connection) {
return this.post('info', group, name, payload, connection);
};
/**
* Post a warning-level event to the EA server.
* @param {String} group - The name of the group the event belongs to.
* @param {String} name - The designated event name.
* @param {?Object} [payload=null] - The payload to pass. This will be extended
* onto the default payload object, if one exists.
* @param {?Connection} [connection=null] - The {@link Connection} which is posting this payload.
* @returns {Promise} Fulfilled if the HTTP response is 20x.
*/
EventPublisher.prototype.warn = function warn(group, name, payload, connection) {
return this.post('warning', group, name, payload, connection);
};
/**
* Post an error-level event to the EA server.
* @param {String} group - The name of the group the event belongs to.
* @param {String} name - The designated event name.
* @param {?Object} [payload=null] - The payload to pass. This will be extended
* onto the default payload object, if one exists.
* @param {?Connection} [connection=null] - The {@link Connection} which is posting this payload.
* @returns {Promise} Fulfilled if the HTTP response is 20x.
*/
EventPublisher.prototype.error = function error(group, name, payload, connection) {
return this.post('error', group, name, payload, connection);
};
/**
* Post a metrics event to the EA server.
* @param {String} group - The name of the group the event belongs to.
* @param {String} name - The designated event name.
* @param {Array<Object>} metrics - The metrics to post.
* @param {?Object} [customFields] - Custom fields to append to each payload.
* @returns {Promise} Fulfilled if the HTTP response is 20x.
*/
EventPublisher.prototype.postMetrics = function postMetrics(group, name, metrics, customFields, connection) {
var _this = this;
return new Promise(function (resolve) {
var samples = metrics
.map(formatMetric)
.map(function (sample) { return Object.assign(sample, customFields); });
resolve(_this._post('EndpointMetrics', 'info', group, name, samples, connection));
});
};
/**
* Update the host address of the insights server to publish to.
* @param {String} host - The new host address of the insights server.
*/
EventPublisher.prototype.setHost = function setHost(host) {
this._host = host;
};
/**
* Update the token to use to authenticate requests.
* @param {string} token
* @returns {void}
*/
EventPublisher.prototype.setToken = function setToken(token) {
this._token = token;
};
/**
* Enable the publishing of events.
*/
EventPublisher.prototype.enable = function enable() {
this._isEnabled = true;
};
/**
* Disable the publishing of events.
*/
EventPublisher.prototype.disable = function disable() {
this._isEnabled = false;
};
function formatMetric(sample) {
return {
audio_codec: sample.codecName,
audio_level_in: sample.audioInputLevel,
audio_level_out: sample.audioOutputLevel,
bytes_received: sample.bytesReceived,
bytes_sent: sample.bytesSent,
call_volume_input: sample.inputVolume,
call_volume_output: sample.outputVolume,
jitter: sample.jitter,
mos: sample.mos && (Math.round(sample.mos * 100) / 100),
packets_lost: sample.packetsLost,
packets_lost_fraction: sample.packetsLostFraction &&
(Math.round(sample.packetsLostFraction * 100) / 100),
packets_received: sample.packetsReceived,
rtt: sample.rtt,
timestamp: (new Date(sample.timestamp)).toISOString(),
total_bytes_received: sample.totals.bytesReceived,
total_bytes_sent: sample.totals.bytesSent,
total_packets_lost: sample.totals.packetsLost,
total_packets_received: sample.totals.packetsReceived,
total_packets_sent: sample.totals.packetsSent,
};
}
exports.default = EventPublisher;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXZlbnRwdWJsaXNoZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9saWIvdHdpbGlvL2V2ZW50cHVibGlzaGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsY0FBYztBQUNkLGlDQUFzQztBQUN0Qyw2QkFBd0I7QUFDeEIscUNBQWdDO0FBRWhDOzs7Ozs7Ozs7OztHQVdHO0FBQ0g7Ozs7Ozs7Ozs7O0dBV0c7QUFDSDtJQUE2QixrQ0FBWTtJQUN2Qyx3QkFBWSxXQUFXLEVBQUUsS0FBSyxFQUFFLE9BQU87UUFDckMsWUFBQSxNQUFLLFdBQUUsU0FBQztRQUVSLElBQUksQ0FBQyxDQUFDLEtBQUksWUFBWSxjQUFjLENBQUMsRUFBRSxDQUFDO1lBQ3RDLE9BQU8sSUFBSSxjQUFjLENBQUMsV0FBVyxFQUFFLEtBQUssRUFBRSxPQUFPLENBQUMsQ0FBQztRQUN6RCxDQUFDO1FBRUQsd0JBQXdCO1FBQ3hCLE9BQU8sR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLEVBQUUsY0FBYyxnQkFBSyxPQUFPLEVBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBRXZFLElBQUksY0FBYyxHQUFHLE9BQU8sQ0FBQyxjQUFjLENBQUM7UUFFNUMsSUFBSSxPQUFPLGNBQWMsS0FBSyxVQUFVLEVBQUUsQ0FBQztZQUN6QyxjQUFjLEdBQUcsY0FBTSxPQUFBLE1BQU0sQ0FBQyxNQUFNLENBQUMsRUFBRyxFQUFFLE9BQU8sQ0FBQyxjQUFjLENBQUMsRUFBMUMsQ0FBMEMsQ0FBQztRQUNwRSxDQUFDO1FBRUQsSUFBSSxTQUFTLEdBQUcsSUFBSSxDQUFDO1FBQ3JCLElBQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLFdBQVcsRUFBRSxTQUFTLEVBQUUsRUFBRSxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUM7UUFFbEcsTUFBTSxDQUFDLGdC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