mirror of
https://github.com/jambonz/jambonz-feature-server.git
synced 2025-12-19 04:17:44 +00:00
Feature/centralized configs (#310)
* [snyk] fix vulnerabilities * move all process.env in one config * update log level in config * check envs * fix imports in tests for microsoft, soniox, deepgram * fix import in gather-test * fix missing imports --------- Co-authored-by: Markus Frindt <m.frindt@cognigy.com>
This commit is contained in:
48
app.js
48
app.js
@@ -1,22 +1,26 @@
|
||||
const assert = require('assert');
|
||||
assert.ok(process.env.JAMBONES_MYSQL_HOST &&
|
||||
process.env.JAMBONES_MYSQL_USER &&
|
||||
process.env.JAMBONES_MYSQL_PASSWORD &&
|
||||
process.env.JAMBONES_MYSQL_DATABASE, 'missing JAMBONES_MYSQL_XXX env vars');
|
||||
assert.ok(process.env.DRACHTIO_PORT || process.env.DRACHTIO_HOST, 'missing DRACHTIO_PORT env var');
|
||||
assert.ok(process.env.DRACHTIO_SECRET, 'missing DRACHTIO_SECRET env var');
|
||||
assert.ok(process.env.JAMBONES_FREESWITCH, 'missing JAMBONES_FREESWITCH env var');
|
||||
assert.ok(process.env.JAMBONES_REDIS_HOST, 'missing JAMBONES_REDIS_HOST env var');
|
||||
assert.ok(process.env.JAMBONES_NETWORK_CIDR || process.env.K8S, 'missing JAMBONES_SUBNET env var');
|
||||
assert.ok(process.env.ENCRYPTION_SECRET || process.env.JWT_SECRET, 'missing ENCRYPTION_SECRET env var');
|
||||
const {
|
||||
DRACHTIO_PORT,
|
||||
DRACHTIO_HOST,
|
||||
DRACHTIO_SECRET,
|
||||
JAMBONES_OTEL_SERVICE_NAME,
|
||||
JAMBONES_LOGLEVEL,
|
||||
JAMBONES_CLUSTER_ID,
|
||||
JAMBONZ_CLEANUP_INTERVAL_MINS,
|
||||
getCleanupIntervalMins,
|
||||
K8S,
|
||||
NODE_ENV,
|
||||
checkEnvs,
|
||||
} = require('./lib/config');
|
||||
|
||||
checkEnvs();
|
||||
|
||||
const Srf = require('drachtio-srf');
|
||||
const srf = new Srf();
|
||||
const tracer = require('./tracer')(process.env.JAMBONES_OTEL_SERVICE_NAME || 'jambonz-feature-server');
|
||||
const tracer = require('./tracer')(JAMBONES_OTEL_SERVICE_NAME);
|
||||
const api = require('@opentelemetry/api');
|
||||
srf.locals = {...srf.locals, otel: {tracer, api}};
|
||||
|
||||
const opts = {level: process.env.JAMBONES_LOGLEVEL || 'info'};
|
||||
const opts = {level: JAMBONES_LOGLEVEL};
|
||||
const pino = require('pino');
|
||||
const logger = pino(opts, pino.destination({sync: false}));
|
||||
const {LifeCycleEvents, FS_UUID_SET_NAME} = require('./lib/utils/constants');
|
||||
@@ -36,8 +40,8 @@ const {
|
||||
const InboundCallSession = require('./lib/session/inbound-call-session');
|
||||
const SipRecCallSession = require('./lib/session/siprec-call-session');
|
||||
|
||||
if (process.env.DRACHTIO_HOST) {
|
||||
srf.connect({host: process.env.DRACHTIO_HOST, port: process.env.DRACHTIO_PORT, secret: process.env.DRACHTIO_SECRET });
|
||||
if (DRACHTIO_HOST) {
|
||||
srf.connect({host: DRACHTIO_HOST, port: DRACHTIO_PORT, secret: DRACHTIO_SECRET });
|
||||
srf.on('connect', (err, hp) => {
|
||||
const arr = /^(.*)\/(.*)$/.exec(hp.split(',').pop());
|
||||
srf.locals.localSipAddress = `${arr[2]}`;
|
||||
@@ -45,10 +49,10 @@ if (process.env.DRACHTIO_HOST) {
|
||||
});
|
||||
}
|
||||
else {
|
||||
logger.info(`listening for drachtio requests on port ${process.env.DRACHTIO_PORT}`);
|
||||
srf.listen({port: process.env.DRACHTIO_PORT, secret: process.env.DRACHTIO_SECRET});
|
||||
logger.info(`listening for drachtio requests on port ${DRACHTIO_PORT}`);
|
||||
srf.listen({port: DRACHTIO_PORT, secret: DRACHTIO_SECRET});
|
||||
}
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
if (NODE_ENV === 'test') {
|
||||
srf.on('error', (err) => {
|
||||
logger.info(err, 'Error connecting to drachtio');
|
||||
});
|
||||
@@ -113,13 +117,13 @@ function handle(signal) {
|
||||
const {removeFromSet} = srf.locals.dbHelpers;
|
||||
srf.locals.disabled = true;
|
||||
logger.info(`got signal ${signal}`);
|
||||
const setName = `${(process.env.JAMBONES_CLUSTER_ID || 'default')}:active-fs`;
|
||||
const setName = `${(JAMBONES_CLUSTER_ID || 'default')}:active-fs`;
|
||||
if (setName && srf.locals.localSipAddress) {
|
||||
logger.info(`got signal ${signal}, removing ${srf.locals.localSipAddress} from set ${setName}`);
|
||||
removeFromSet(setName, srf.locals.localSipAddress);
|
||||
}
|
||||
removeFromSet(FS_UUID_SET_NAME, srf.locals.fsUUID);
|
||||
if (process.env.K8S) {
|
||||
if (K8S) {
|
||||
srf.locals.lifecycleEmitter.operationalState = LifeCycleEvents.ScaleIn;
|
||||
}
|
||||
if (getCount() === 0) {
|
||||
@@ -128,7 +132,7 @@ function handle(signal) {
|
||||
}
|
||||
}
|
||||
|
||||
if (process.env.JAMBONZ_CLEANUP_INTERVAL_MINS) {
|
||||
if (JAMBONZ_CLEANUP_INTERVAL_MINS) {
|
||||
const {clearFiles} = require('./lib/utils/cron-jobs');
|
||||
|
||||
/* cleanup orphaned files or channels every so often */
|
||||
@@ -138,7 +142,7 @@ if (process.env.JAMBONZ_CLEANUP_INTERVAL_MINS) {
|
||||
} catch (err) {
|
||||
logger.error({err}, 'app.js: error clearing files');
|
||||
}
|
||||
}, 1000 * 60 * (process.env.JAMBONZ_CLEANUP_INTERVAL_MINS || 60));
|
||||
}, getCleanupIntervalMins());
|
||||
}
|
||||
|
||||
module.exports = {srf, logger, disconnect};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env node
|
||||
const bent = require('bent');
|
||||
const getJSON = bent('json');
|
||||
const PORT = process.env.HTTP_PORT || 3000;
|
||||
const {PORT} = require('../lib/config')
|
||||
|
||||
const sleep = (ms) => {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
|
||||
193
lib/config.js
Normal file
193
lib/config.js
Normal file
@@ -0,0 +1,193 @@
|
||||
const assert = require('assert');
|
||||
|
||||
const checkEnvs = () => {
|
||||
assert.ok(process.env.JAMBONES_MYSQL_HOST &&
|
||||
process.env.JAMBONES_MYSQL_USER &&
|
||||
process.env.JAMBONES_MYSQL_PASSWORD &&
|
||||
process.env.JAMBONES_MYSQL_DATABASE, 'missing JAMBONES_MYSQL_XXX env vars');
|
||||
assert.ok(process.env.DRACHTIO_PORT || process.env.DRACHTIO_HOST, 'missing DRACHTIO_PORT env var');
|
||||
assert.ok(process.env.DRACHTIO_SECRET, 'missing DRACHTIO_SECRET env var');
|
||||
assert.ok(process.env.JAMBONES_FREESWITCH, 'missing JAMBONES_FREESWITCH env var');
|
||||
assert.ok(process.env.JAMBONES_REDIS_HOST, 'missing JAMBONES_REDIS_HOST env var');
|
||||
assert.ok(process.env.JAMBONES_NETWORK_CIDR || process.env.K8S, 'missing JAMBONES_SUBNET env var');
|
||||
};
|
||||
|
||||
const NODE_ENV = process.env.NODE_ENV;
|
||||
|
||||
/* database mySQL */
|
||||
const JAMBONES_MYSQL_HOST = process.env.JAMBONES_MYSQL_HOST;
|
||||
const JAMBONES_MYSQL_USER = process.env.JAMBONES_MYSQL_USER;
|
||||
const JAMBONES_MYSQL_PASSWORD = process.env.JAMBONES_MYSQL_PASSWORD;
|
||||
const JAMBONES_MYSQL_DATABASE = process.env.JAMBONES_MYSQL_DATABASE;
|
||||
const JAMBONES_MYSQL_PORT = parseInt(process.env.JAMBONES_MYSQL_PORT, 10) || 3306;
|
||||
const JAMBONES_MYSQL_REFRESH_TTL = process.env.JAMBONES_MYSQL_REFRESH_TTL;
|
||||
const JAMBONES_MYSQL_CONNECTION_LIMIT = parseInt(process.env.JAMBONES_MYSQL_CONNECTION_LIMIT, 10) || 10;
|
||||
|
||||
/* redis */
|
||||
const JAMBONES_REDIS_HOST = process.env.JAMBONES_REDIS_HOST;
|
||||
const JAMBONES_REDIS_PORT = parseInt(process.env.JAMBONES_REDIS_PORT, 10) || 6379;
|
||||
|
||||
/* gather and hints */
|
||||
const JAMBONES_GATHER_EARLY_HINTS_MATCH = process.env.JAMBONES_GATHER_EARLY_HINTS_MATCH;
|
||||
const JAMBONZ_GATHER_EARLY_HINTS_MATCH = process.env.JAMBONZ_GATHER_EARLY_HINTS_MATCH;
|
||||
const JAMBONES_GATHER_CLEAR_GLOBAL_HINTS_ON_EMPTY_HINTS = process.env.JAMBONES_GATHER_CLEAR_GLOBAL_HINTS_ON_EMPTY_HINTS;
|
||||
|
||||
const SMPP_URL = process.env.SMPP_URL;
|
||||
|
||||
/* drachtio */
|
||||
const DRACHTIO_PORT = process.env.DRACHTIO_PORT;
|
||||
const DRACHTIO_HOST = process.env.DRACHTIO_HOST;
|
||||
const DRACHTIO_SECRET = process.env.DRACHTIO_SECRET;
|
||||
|
||||
/* freeswitch */
|
||||
const JAMBONES_API_BASE_URL = process.env.JAMBONES_API_BASE_URL;
|
||||
const JAMBONES_FREESWITCH = process.env.JAMBONES_FREESWITCH;
|
||||
const JAMBONES_FREESWITCH_MAX_CALL_DURATION_MINS = parseInt(process.env.JAMBONES_FREESWITCH_MAX_CALL_DURATION_MINS, 10)
|
||||
|| 180;
|
||||
|
||||
|
||||
const JAMBONES_SBCS = process.env.JAMBONES_SBCS;
|
||||
|
||||
/* websockets */
|
||||
const JAMBONES_WS_HANDSHAKE_TIMEOUT_MS = parseInt(process.env.JAMBONES_WS_HANDSHAKE_TIMEOUT_MS, 10) || 1500;
|
||||
const JAMBONES_WS_MAX_PAYLOAD = parseInt(process.env.JAMBONES_WS_MAX_PAYLOAD, 10) || 24 * 1024;
|
||||
|
||||
const MAX_RECONNECTS = 5;
|
||||
const RESPONSE_TIMEOUT_MS = parseInt(process.env.JAMBONES_WS_API_MSG_RESPONSE_TIMEOUT, 10) || 5000;
|
||||
|
||||
const JAMBONES_NETWORK_CIDR = process.env.JAMBONES_NETWORK_CIDR;
|
||||
const JAMBONES_TIME_SERIES_HOST = process.env.JAMBONES_TIME_SERIES_HOST;
|
||||
const JAMBONES_CLUSTER_ID = process.env.JAMBONES_CLUSTER_ID || 'default';
|
||||
const JAMBONES_ESL_LISTEN_ADDRESS = process.env.JAMBONES_ESL_LISTEN_ADDRESS;
|
||||
|
||||
/* tracing */
|
||||
const JAMBONES_OTEL_ENABLED = process.env.JAMBONES_OTEL_ENABLED;
|
||||
const JAMBONES_OTEL_SERVICE_NAME = process.env.JAMBONES_OTEL_SERVICE_NAME || 'jambonz-feature-server';
|
||||
const OTEL_EXPORTER_JAEGER_AGENT_HOST = process.env.OTEL_EXPORTER_JAEGER_AGENT_HOST;
|
||||
const OTEL_EXPORTER_ZIPKIN_URL = process.env.OTEL_EXPORTER_ZIPKIN_URL;
|
||||
const OTEL_EXPORTER_COLLECTOR_URL = process.env.OTEL_EXPORTER_COLLECTOR_URL;
|
||||
|
||||
const JAMBONES_LOGLEVEL = process.env.JAMBONES_LOGLEVEL || 'info';
|
||||
const JAMBONES_INJECT_CONTENT = process.env.JAMBONES_INJECT_CONTENT;
|
||||
|
||||
const PORT = parseInt(process.env.HTTP_PORT, 10) || 3000;
|
||||
const HTTP_PORT_MAX = parseInt(process.env.HTTP_PORT_MAX, 10);
|
||||
|
||||
const K8S = process.env.K8S;
|
||||
const K8S_SBC_SIP_SERVICE_NAME = process.env.K8S_SBC_SIP_SERVICE_NAME;
|
||||
|
||||
const JAMBONES_SUBNET = process.env.JAMBONES_SUBNET;
|
||||
|
||||
/* clean up */
|
||||
const JAMBONZ_CLEANUP_INTERVAL_MINS = process.env.JAMBONZ_CLEANUP_INTERVAL_MINS;
|
||||
const getCleanupIntervalMins = () => {
|
||||
const interval = parseInt(JAMBONZ_CLEANUP_INTERVAL_MINS, 10) || 60;
|
||||
return 1000 * 60 * interval;
|
||||
};
|
||||
|
||||
/* speech vendors */
|
||||
const AWS_REGION = process.env.AWS_REGION;
|
||||
const AWS_ACCESS_KEY_ID = process.env.AWS_ACCESS_KEY_ID;
|
||||
const AWS_SECRET_ACCESS_KEY = process.env.AWS_SECRET_ACCESS_KEY;
|
||||
const AWS_SNS_PORT = parseInt(process.env.AWS_SNS_PORT, 10) || 3001;
|
||||
const AWS_SNS_TOPIC_ARM = process.env.AWS_SNS_TOPIC_ARM;
|
||||
const AWS_SNS_PORT_MAX = parseInt(process.env.AWS_SNS_PORT_MAX, 10) || 3005;
|
||||
|
||||
const GCP_JSON_KEY = process.env.GCP_JSON_KEY;
|
||||
|
||||
const MICROSOFT_REGION = process.env.MICROSOFT_REGION;
|
||||
const MICROSOFT_API_KEY = process.env.MICROSOFT_API_KEY;
|
||||
|
||||
const SONIOX_API_KEY = process.env.SONIOX_API_KEY;
|
||||
|
||||
const DEEPGRAM_API_KEY = process.env.DEEPGRAM_API_KEY;
|
||||
|
||||
const ANCHOR_MEDIA_ALWAYS = process.env.ANCHOR_MEDIA_ALWAYS;
|
||||
const VMD_HINTS_FILE = process.env.VMD_HINTS_FILE;
|
||||
|
||||
/* security, secrets */
|
||||
const LEGACY_CRYPTO = !!process.env.LEGACY_CRYPTO;
|
||||
const JWT_SECRET = process.env.JWT_SECRET;
|
||||
const ENCRYPTION_SECRET = process.env.ENCRYPTION_SECRET;
|
||||
|
||||
/* HTTP/1 pool dispatcher */
|
||||
const HTTP_POOL = process.env.HTTP_POOL && parseInt(process.env.HTTP_POOL);
|
||||
const HTTP_POOLSIZE = parseInt(process.env.HTTP_POOLSIZE, 10) || 10;
|
||||
const HTTP_PIPELINING = parseInt(process.env.HTTP_PIPELINING, 10) || 1;
|
||||
const HTTP_TIMEOUT = 10000;
|
||||
|
||||
const OPTIONS_PING_INTERVAL = parseInt(process.env.OPTIONS_PING_INTERVAL, 10) || 30000;
|
||||
|
||||
module.exports = {
|
||||
JAMBONES_MYSQL_HOST,
|
||||
JAMBONES_MYSQL_USER,
|
||||
JAMBONES_MYSQL_PASSWORD,
|
||||
JAMBONES_MYSQL_DATABASE,
|
||||
JAMBONES_MYSQL_REFRESH_TTL,
|
||||
JAMBONES_MYSQL_CONNECTION_LIMIT,
|
||||
JAMBONES_MYSQL_PORT,
|
||||
|
||||
DRACHTIO_PORT,
|
||||
DRACHTIO_HOST,
|
||||
DRACHTIO_SECRET,
|
||||
|
||||
JAMBONES_GATHER_EARLY_HINTS_MATCH,
|
||||
JAMBONZ_GATHER_EARLY_HINTS_MATCH,
|
||||
JAMBONES_GATHER_CLEAR_GLOBAL_HINTS_ON_EMPTY_HINTS,
|
||||
JAMBONES_FREESWITCH,
|
||||
JAMBONES_REDIS_HOST,
|
||||
JAMBONES_REDIS_PORT,
|
||||
SMPP_URL,
|
||||
JAMBONES_NETWORK_CIDR,
|
||||
JAMBONES_API_BASE_URL,
|
||||
JAMBONES_TIME_SERIES_HOST,
|
||||
JAMBONES_INJECT_CONTENT,
|
||||
JAMBONES_ESL_LISTEN_ADDRESS,
|
||||
JAMBONES_SBCS,
|
||||
JAMBONES_OTEL_ENABLED,
|
||||
JAMBONES_OTEL_SERVICE_NAME,
|
||||
OTEL_EXPORTER_JAEGER_AGENT_HOST,
|
||||
OTEL_EXPORTER_ZIPKIN_URL,
|
||||
OTEL_EXPORTER_COLLECTOR_URL,
|
||||
|
||||
JAMBONES_LOGLEVEL,
|
||||
JAMBONES_CLUSTER_ID,
|
||||
PORT,
|
||||
HTTP_PORT_MAX,
|
||||
K8S,
|
||||
K8S_SBC_SIP_SERVICE_NAME,
|
||||
JAMBONES_SUBNET,
|
||||
NODE_ENV,
|
||||
JAMBONZ_CLEANUP_INTERVAL_MINS,
|
||||
getCleanupIntervalMins,
|
||||
checkEnvs,
|
||||
|
||||
AWS_REGION,
|
||||
AWS_ACCESS_KEY_ID,
|
||||
AWS_SECRET_ACCESS_KEY,
|
||||
AWS_SNS_PORT,
|
||||
AWS_SNS_TOPIC_ARM,
|
||||
AWS_SNS_PORT_MAX,
|
||||
|
||||
ANCHOR_MEDIA_ALWAYS,
|
||||
VMD_HINTS_FILE,
|
||||
JAMBONES_FREESWITCH_MAX_CALL_DURATION_MINS,
|
||||
|
||||
LEGACY_CRYPTO,
|
||||
JWT_SECRET,
|
||||
ENCRYPTION_SECRET,
|
||||
HTTP_POOL,
|
||||
HTTP_POOLSIZE,
|
||||
HTTP_PIPELINING,
|
||||
HTTP_TIMEOUT,
|
||||
OPTIONS_PING_INTERVAL,
|
||||
RESPONSE_TIMEOUT_MS,
|
||||
JAMBONES_WS_HANDSHAKE_TIMEOUT_MS,
|
||||
JAMBONES_WS_MAX_PAYLOAD,
|
||||
MAX_RECONNECTS,
|
||||
GCP_JSON_KEY,
|
||||
MICROSOFT_REGION,
|
||||
MICROSOFT_API_KEY,
|
||||
SONIOX_API_KEY,
|
||||
DEEPGRAM_API_KEY
|
||||
};
|
||||
@@ -10,6 +10,9 @@ const { normalizeJambones } = require('@jambonz/verb-specifications');
|
||||
const dbUtils = require('./utils/db-utils');
|
||||
const RootSpan = require('./utils/call-tracer');
|
||||
const listTaskNames = require('./utils/summarize-tasks');
|
||||
const {
|
||||
JAMBONES_MYSQL_REFRESH_TTL,
|
||||
} = require('./config');
|
||||
|
||||
module.exports = function(srf, logger) {
|
||||
const {
|
||||
@@ -242,7 +245,7 @@ module.exports = function(srf, logger) {
|
||||
*/
|
||||
|
||||
/* allow for caching data - when caching treat retrieved data as immutable */
|
||||
const app2 = process.env.JAMBONES_MYSQL_REFRESH_TTL ? JSON.parse(JSON.stringify(app)) : app;
|
||||
const app2 = JAMBONES_MYSQL_REFRESH_TTL ? JSON.parse(JSON.stringify(app)) : app;
|
||||
if ('WS' === app.call_hook?.method ||
|
||||
app.call_hook?.url.startsWith('ws://') || app.call_hook?.url.startsWith('wss://')) {
|
||||
app2.requestor = new WsRequestor(logger, account_sid, app.call_hook, accountInfo.account.webhook_secret) ;
|
||||
@@ -285,7 +288,7 @@ module.exports = function(srf, logger) {
|
||||
const {rootSpan, siprec, application:app} = req.locals;
|
||||
let span;
|
||||
try {
|
||||
if (app.tasks && !process.env.JAMBONES_MYSQL_REFRESH_TTL) {
|
||||
if (app.tasks && !JAMBONES_MYSQL_REFRESH_TTL) {
|
||||
app.tasks = normalizeJambones(logger, app.tasks).map((tdata) => makeTask(logger, tdata));
|
||||
if (0 === app.tasks.length) throw new Error('no application provided');
|
||||
return next();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const {CallDirection, CallStatus} = require('../utils/constants');
|
||||
const parseUri = require('drachtio-srf').parseUri;
|
||||
const uuidv4 = require('uuid-random');
|
||||
const {JAMBONES_API_BASE_URL} = require('../config');
|
||||
/**
|
||||
* @classdesc Represents the common information for all calls
|
||||
* that is provided in call status webhooks
|
||||
@@ -146,8 +147,8 @@ class CallInfo {
|
||||
Object.assign(obj, {customerData: this._customerData});
|
||||
}
|
||||
|
||||
if (process.env.JAMBONES_API_BASE_URL) {
|
||||
Object.assign(obj, {apiBaseUrl: process.env.JAMBONES_API_BASE_URL});
|
||||
if (JAMBONES_API_BASE_URL) {
|
||||
Object.assign(obj, {apiBaseUrl: JAMBONES_API_BASE_URL});
|
||||
}
|
||||
if (this.publicIp) {
|
||||
Object.assign(obj, {fsPublicIp: this.publicIp});
|
||||
|
||||
@@ -17,6 +17,10 @@ const { normalizeJambones } = require('@jambonz/verb-specifications');
|
||||
const listTaskNames = require('../utils/summarize-tasks');
|
||||
const HttpRequestor = require('../utils/http-requestor');
|
||||
const WsRequestor = require('../utils/ws-requestor');
|
||||
const {
|
||||
JAMBONES_INJECT_CONTENT,
|
||||
AWS_REGION
|
||||
} = require('../config');
|
||||
const BADPRECONDITIONS = 'preconditions not met';
|
||||
const CALLER_CANCELLED_ERR_MSG = 'Response not sent due to unknown transaction';
|
||||
|
||||
@@ -626,7 +630,7 @@ class CallSession extends Emitter {
|
||||
speech_credential_sid: credential.speech_credential_sid,
|
||||
accessKeyId: credential.access_key_id,
|
||||
secretAccessKey: credential.secret_access_key,
|
||||
region: credential.aws_region || process.env.AWS_REGION
|
||||
region: credential.aws_region || AWS_REGION
|
||||
};
|
||||
}
|
||||
else if ('microsoft' === vendor) {
|
||||
@@ -1199,7 +1203,7 @@ class CallSession extends Emitter {
|
||||
this.logger.info({tasks: listTaskNames(t)}, 'CallSession:_onCommand new task list');
|
||||
this.replaceApplication(t);
|
||||
}
|
||||
else if (process.env.JAMBONES_INJECT_CONTENT) {
|
||||
else if (JAMBONES_INJECT_CONTENT) {
|
||||
this._injectTasks(t);
|
||||
this.logger.info({tasks: listTaskNames(this.tasks)}, 'CallSession:_onCommand - updated task list');
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ const DtmfCollector = require('../utils/dtmf-collector');
|
||||
const dbUtils = require('../utils/db-utils');
|
||||
const debug = require('debug')('jambonz:feature-server');
|
||||
const {parseUri} = require('drachtio-srf');
|
||||
const {ANCHOR_MEDIA_ALWAYS} = require('../config');
|
||||
|
||||
function parseDtmfOptions(logger, dtmfCapture) {
|
||||
let parentDtmfCollector, childDtmfCollector;
|
||||
@@ -135,7 +136,7 @@ class TaskDial extends Task {
|
||||
|
||||
get canReleaseMedia() {
|
||||
const keepAnchor = this.data.anchorMedia ||
|
||||
process.env.ANCHOR_MEDIA_ALWAYS ||
|
||||
ANCHOR_MEDIA_ALWAYS ||
|
||||
this.listenTask ||
|
||||
this.transcribeTask ||
|
||||
this.startAmd;
|
||||
|
||||
@@ -12,7 +12,11 @@ const {
|
||||
NvidiaTranscriptionEvents,
|
||||
JambonzTranscriptionEvents
|
||||
} = require('../utils/constants');
|
||||
|
||||
const {
|
||||
JAMBONES_GATHER_EARLY_HINTS_MATCH,
|
||||
JAMBONZ_GATHER_EARLY_HINTS_MATCH,
|
||||
JAMBONES_GATHER_CLEAR_GLOBAL_HINTS_ON_EMPTY_HINTS,
|
||||
} = require('../config');
|
||||
const makeTask = require('./make_task');
|
||||
const assert = require('assert');
|
||||
|
||||
@@ -71,7 +75,7 @@ class TaskGather extends Task {
|
||||
this.isContinuousAsr = this.asrTimeout > 0;
|
||||
|
||||
if (Array.isArray(this.data.recognizer.hints) &&
|
||||
0 == this.data.recognizer.hints.length && process.env.JAMBONES_GATHER_CLEAR_GLOBAL_HINTS_ON_EMPTY_HINTS) {
|
||||
0 == this.data.recognizer.hints.length && JAMBONES_GATHER_CLEAR_GLOBAL_HINTS_ON_EMPTY_HINTS) {
|
||||
logger.debug('Gather: an empty hints array was supplied, so we will mask global hints');
|
||||
this.maskGlobalSttHints = true;
|
||||
}
|
||||
@@ -162,7 +166,7 @@ class TaskGather extends Task {
|
||||
asrDtmfTerminationDigit: this.asrDtmfTerminationDigit
|
||||
}, 'Gather:exec - enabling continuous ASR since it is turned on for the session');
|
||||
}
|
||||
const {JAMBONZ_GATHER_EARLY_HINTS_MATCH, JAMBONES_GATHER_EARLY_HINTS_MATCH} = process.env;
|
||||
|
||||
if ((JAMBONZ_GATHER_EARLY_HINTS_MATCH || JAMBONES_GATHER_EARLY_HINTS_MATCH) && this.needsStt &&
|
||||
!this.isContinuousAsr &&
|
||||
this.data.recognizer?.hints?.length > 0 && this.data.recognizer?.hints?.length <= 10) {
|
||||
|
||||
@@ -2,7 +2,7 @@ const Task = require('./task');
|
||||
const {TaskName, TaskPreconditions} = require('../utils/constants');
|
||||
const bent = require('bent');
|
||||
const uuidv4 = require('uuid-random');
|
||||
|
||||
const {K8S} = require('../config');
|
||||
class TaskMessage extends Task {
|
||||
constructor(logger, opts) {
|
||||
super(logger, opts);
|
||||
@@ -42,7 +42,7 @@ class TaskMessage extends Task {
|
||||
}
|
||||
if (gw) {
|
||||
this.logger.info({gw, accountSid}, 'Message:exec - using smpp to send message');
|
||||
url = process.env.K8S ? 'http://smpp' : getSmpp();
|
||||
url = K8S ? 'http://smpp' : getSmpp();
|
||||
relativeUrl = '/sms';
|
||||
payload = {
|
||||
...payload,
|
||||
|
||||
@@ -8,7 +8,7 @@ const {
|
||||
AvmdEvents
|
||||
} = require('./constants');
|
||||
const bugname = 'amd_bug';
|
||||
const {VMD_HINTS_FILE} = process.env;
|
||||
const {VMD_HINTS_FILE} = require('../config');
|
||||
let voicemailHints = [];
|
||||
|
||||
const updateHints = async(file, callback) => {
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
const Emitter = require('events');
|
||||
const bent = require('bent');
|
||||
const assert = require('assert');
|
||||
const PORT = process.env.AWS_SNS_PORT || 3010;
|
||||
const {
|
||||
AWS_REGION,
|
||||
AWS_SNS_PORT: PORT,
|
||||
AWS_SNS_TOPIC_ARM,
|
||||
AWS_SNS_PORT_MAX,
|
||||
} = require('../config');
|
||||
const {LifeCycleEvents} = require('./constants');
|
||||
const express = require('express');
|
||||
const app = express();
|
||||
@@ -13,7 +18,7 @@ const {Parser} = require('xml2js');
|
||||
const parser = new Parser();
|
||||
const {validatePayload} = require('verify-aws-sns-signature');
|
||||
|
||||
AWS.config.update({region: process.env.AWS_REGION});
|
||||
AWS.config.update({region: AWS_REGION});
|
||||
|
||||
class SnsNotifier extends Emitter {
|
||||
constructor(logger) {
|
||||
@@ -31,8 +36,8 @@ class SnsNotifier extends Emitter {
|
||||
|
||||
_handleErrors(logger, app, resolve, reject, e) {
|
||||
if (e.code === 'EADDRINUSE' &&
|
||||
process.env.AWS_SNS_PORT_MAX &&
|
||||
e.port < process.env.AWS_SNS_PORT_MAX) {
|
||||
AWS_SNS_PORT_MAX &&
|
||||
e.port < AWS_SNS_PORT_MAX) {
|
||||
|
||||
logger.info(`SNS lifecycle server failed to bind port on ${e.port}, will try next port`);
|
||||
const server = this._doListen(logger, app, ++e.port, resolve);
|
||||
@@ -132,12 +137,12 @@ class SnsNotifier extends Emitter {
|
||||
try {
|
||||
const response = await sns.subscribe({
|
||||
Protocol: 'http',
|
||||
TopicArn: process.env.AWS_SNS_TOPIC_ARM,
|
||||
TopicArn: AWS_SNS_TOPIC_ARM,
|
||||
Endpoint: this.snsEndpoint
|
||||
}).promise();
|
||||
this.logger.info({response}, `response to SNS subscribe to ${process.env.AWS_SNS_TOPIC_ARM}`);
|
||||
this.logger.info({response}, `response to SNS subscribe to ${AWS_SNS_TOPIC_ARM}`);
|
||||
} catch (err) {
|
||||
this.logger.error({err}, `Error subscribing to SNS topic arn ${process.env.AWS_SNS_TOPIC_ARM}`);
|
||||
this.logger.error({err}, `Error subscribing to SNS topic arn ${AWS_SNS_TOPIC_ARM}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,9 +152,9 @@ class SnsNotifier extends Emitter {
|
||||
const response = await sns.unsubscribe({
|
||||
SubscriptionArn: this.subscriptionArn
|
||||
}).promise();
|
||||
this.logger.info({response}, `response to SNS unsubscribe to ${process.env.AWS_SNS_TOPIC_ARM}`);
|
||||
this.logger.info({response}, `response to SNS unsubscribe to ${AWS_SNS_TOPIC_ARM}`);
|
||||
} catch (err) {
|
||||
this.logger.error({err}, `Error unsubscribing to SNS topic arn ${process.env.AWS_SNS_TOPIC_ARM}`);
|
||||
this.logger.error({err}, `Error unsubscribing to SNS topic arn ${AWS_SNS_TOPIC_ARM}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ const assert = require('assert');
|
||||
const Emitter = require('events');
|
||||
const crypto = require('crypto');
|
||||
const timeSeries = require('@jambonz/time-series');
|
||||
const {NODE_ENV, JAMBONES_TIME_SERIES_HOST} = require('../config');
|
||||
let alerter ;
|
||||
|
||||
class BaseRequestor extends Emitter {
|
||||
@@ -22,9 +23,9 @@ class BaseRequestor extends Emitter {
|
||||
|
||||
if (!alerter) {
|
||||
alerter = timeSeries(logger, {
|
||||
host: process.env.JAMBONES_TIME_SERIES_HOST,
|
||||
host: JAMBONES_TIME_SERIES_HOST,
|
||||
commitSize: 50,
|
||||
commitInterval: 'test' === process.env.NODE_ENV ? 7 : 20
|
||||
commitInterval: 'test' === NODE_ENV ? 7 : 20
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
const {execSync} = require('child_process');
|
||||
const {
|
||||
JAMBONES_FREESWITCH,
|
||||
NODE_ENV,
|
||||
JAMBONES_FREESWITCH_MAX_CALL_DURATION_MINS,
|
||||
} = require('../config');
|
||||
const now = Date.now();
|
||||
const fsInventory = process.env.JAMBONES_FREESWITCH
|
||||
const fsInventory = JAMBONES_FREESWITCH
|
||||
.split(',')
|
||||
.map((fs) => {
|
||||
const arr = /^([^:]*):([^:]*):([^:]*)(?::([^:]*))?/.exec(fs);
|
||||
const opts = {address: arr[1], port: arr[2], secret: arr[3]};
|
||||
if (arr.length > 4) opts.advertisedAddress = arr[4];
|
||||
if (process.env.NODE_ENV === 'test') opts.listenAddress = '0.0.0.0';
|
||||
if (NODE_ENV === 'test') opts.listenAddress = '0.0.0.0';
|
||||
return opts;
|
||||
});
|
||||
|
||||
const clearChannels = () => {
|
||||
const {logger} = require('../..');
|
||||
const pwd = fsInventory[0].secret;
|
||||
const maxDurationMins = process.env.JAMBONES_FREESWITCH_MAX_CALL_DURATION_MINS || 180;
|
||||
const maxDurationMins = JAMBONES_FREESWITCH_MAX_CALL_DURATION_MINS;
|
||||
|
||||
const calls = execSync(`/usr/local/freeswitch/bin/fs_cli -p ${pwd} -x "show calls"`, {encoding: 'utf8'})
|
||||
.split('\n')
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
const crypto = require('crypto');
|
||||
const algorithm = process.env.LEGACY_CRYPTO ? 'aes-256-ctr' : 'aes-256-cbc';
|
||||
const {LEGACY_CRYPTO, ENCRYPTION_SECRET, JWT_SECRET} = require('../config');
|
||||
const algorithm = LEGACY_CRYPTO ? 'aes-256-ctr' : 'aes-256-cbc';
|
||||
const iv = crypto.randomBytes(16);
|
||||
const secretKey = crypto.createHash('sha256')
|
||||
.update(process.env.ENCRYPTION_SECRET || process.env.JWT_SECRET)
|
||||
.update(ENCRYPTION_SECRET || JWT_SECRET)
|
||||
.digest('base64')
|
||||
.substring(0, 32);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
const express = require('express');
|
||||
const httpRoutes = require('../http-routes');
|
||||
const PORT = process.env.HTTP_PORT || 3000;
|
||||
const {PORT, HTTP_PORT_MAX} = require('../config');
|
||||
|
||||
const doListen = (logger, app, port, resolve) => {
|
||||
const server = app.listen(port, () => {
|
||||
@@ -13,8 +13,8 @@ const doListen = (logger, app, port, resolve) => {
|
||||
};
|
||||
const handleErrors = (logger, app, resolve, reject, e) => {
|
||||
if (e.code === 'EADDRINUSE' &&
|
||||
process.env.HTTP_PORT_MAX &&
|
||||
e.port < process.env.HTTP_PORT_MAX) {
|
||||
HTTP_PORT_MAX &&
|
||||
e.port < HTTP_PORT_MAX) {
|
||||
|
||||
logger.info(`HTTP server failed to bind port on ${e.port}, will try next port`);
|
||||
const server = doListen(logger, app, ++e.port, resolve);
|
||||
|
||||
@@ -5,7 +5,12 @@ const BaseRequestor = require('./base-requestor');
|
||||
const {HookMsgTypes} = require('./constants.json');
|
||||
const snakeCaseKeys = require('./snakecase-keys');
|
||||
const pools = new Map();
|
||||
const HTTP_TIMEOUT = 10000;
|
||||
const {
|
||||
HTTP_POOL,
|
||||
HTTP_POOLSIZE,
|
||||
HTTP_PIPELINING,
|
||||
HTTP_TIMEOUT,
|
||||
} = require('../config');
|
||||
|
||||
const toBase64 = (str) => Buffer.from(str || '', 'utf8').toString('base64');
|
||||
|
||||
@@ -34,15 +39,15 @@ class HttpRequestor extends BaseRequestor {
|
||||
this._resource = u.resource;
|
||||
this._port = u.port;
|
||||
this._search = u.search;
|
||||
this._usePools = process.env.HTTP_POOL && parseInt(process.env.HTTP_POOL);
|
||||
this._usePools = HTTP_POOL && parseInt(HTTP_POOL);
|
||||
|
||||
if (this._usePools) {
|
||||
if (pools.has(this._baseUrl)) {
|
||||
this.client = pools.get(this._baseUrl);
|
||||
}
|
||||
else {
|
||||
const connections = process.env.HTTP_POOLSIZE ? parseInt(process.env.HTTP_POOLSIZE) : 10;
|
||||
const pipelining = process.env.HTTP_PIPELINING ? parseInt(process.env.HTTP_PIPELINING) : 1;
|
||||
const connections = HTTP_POOLSIZE ? parseInt(HTTP_POOLSIZE) : 10;
|
||||
const pipelining = HTTP_PIPELINING ? parseInt(HTTP_PIPELINING) : 1;
|
||||
const pool = this.client = new Pool(this._baseUrl, {
|
||||
connections,
|
||||
pipelining
|
||||
|
||||
@@ -1,6 +1,21 @@
|
||||
const Mrf = require('drachtio-fsmrf');
|
||||
const ip = require('ip');
|
||||
const PORT = process.env.HTTP_PORT || 3000;
|
||||
const {
|
||||
JAMBONES_MYSQL_HOST,
|
||||
JAMBONES_MYSQL_USER,
|
||||
JAMBONES_MYSQL_PASSWORD,
|
||||
JAMBONES_MYSQL_DATABASE,
|
||||
JAMBONES_MYSQL_CONNECTION_LIMIT,
|
||||
JAMBONES_MYSQL_PORT,
|
||||
JAMBONES_FREESWITCH,
|
||||
JAMBONES_REDIS_HOST,
|
||||
JAMBONES_REDIS_PORT,
|
||||
SMPP_URL,
|
||||
JAMBONES_TIME_SERIES_HOST,
|
||||
JAMBONES_ESL_LISTEN_ADDRESS,
|
||||
PORT,
|
||||
NODE_ENV,
|
||||
} = require('../config');
|
||||
const assert = require('assert');
|
||||
|
||||
function initMS(logger, wrapper, ms) {
|
||||
@@ -42,18 +57,18 @@ function installSrfLocals(srf, logger) {
|
||||
let idxStart = 0;
|
||||
|
||||
(async function() {
|
||||
const fsInventory = process.env.JAMBONES_FREESWITCH
|
||||
const fsInventory = JAMBONES_FREESWITCH
|
||||
.split(',')
|
||||
.map((fs) => {
|
||||
const arr = /^([^:]*):([^:]*):([^:]*)(?::([^:]*))?/.exec(fs);
|
||||
assert.ok(arr, `Invalid syntax JAMBONES_FREESWITCH: ${process.env.JAMBONES_FREESWITCH}`);
|
||||
assert.ok(arr, `Invalid syntax JAMBONES_FREESWITCH: ${JAMBONES_FREESWITCH}`);
|
||||
const opts = {address: arr[1], port: arr[2], secret: arr[3]};
|
||||
if (arr.length > 4) opts.advertisedAddress = arr[4];
|
||||
/* NB: originally for testing only, but for now all jambonz deployments
|
||||
have freeswitch installed locally alongside this app
|
||||
*/
|
||||
if (process.env.NODE_ENV === 'test') opts.listenAddress = '0.0.0.0';
|
||||
else if (process.env.JAMBONES_ESL_LISTEN_ADDRESS) opts.listenAddress = process.env.JAMBONES_ESL_LISTEN_ADDRESS;
|
||||
if (NODE_ENV === 'test') opts.listenAddress = '0.0.0.0';
|
||||
else if (JAMBONES_ESL_LISTEN_ADDRESS) opts.listenAddress = JAMBONES_ESL_LISTEN_ADDRESS;
|
||||
return opts;
|
||||
});
|
||||
logger.info({fsInventory}, 'freeswitch inventory');
|
||||
@@ -125,12 +140,12 @@ function installSrfLocals(srf, logger) {
|
||||
lookupAccountCapacitiesBySid,
|
||||
lookupSmppGateways
|
||||
} = require('@jambonz/db-helpers')({
|
||||
host: process.env.JAMBONES_MYSQL_HOST,
|
||||
user: process.env.JAMBONES_MYSQL_USER,
|
||||
port: process.env.JAMBONES_MYSQL_PORT || 3306,
|
||||
password: process.env.JAMBONES_MYSQL_PASSWORD,
|
||||
database: process.env.JAMBONES_MYSQL_DATABASE,
|
||||
connectionLimit: process.env.JAMBONES_MYSQL_CONNECTION_LIMIT || 10
|
||||
host: JAMBONES_MYSQL_HOST,
|
||||
user: JAMBONES_MYSQL_USER,
|
||||
port: JAMBONES_MYSQL_PORT || 3306,
|
||||
password: JAMBONES_MYSQL_PASSWORD,
|
||||
database: JAMBONES_MYSQL_DATABASE,
|
||||
connectionLimit: JAMBONES_MYSQL_CONNECTION_LIMIT || 10
|
||||
}, logger, tracer);
|
||||
const {
|
||||
client,
|
||||
@@ -153,24 +168,24 @@ function installSrfLocals(srf, logger) {
|
||||
getListPosition,
|
||||
lengthOfList,
|
||||
} = require('@jambonz/realtimedb-helpers')({
|
||||
host: process.env.JAMBONES_REDIS_HOST,
|
||||
port: process.env.JAMBONES_REDIS_PORT || 6379
|
||||
host: JAMBONES_REDIS_HOST,
|
||||
port: JAMBONES_REDIS_PORT || 6379
|
||||
}, logger, tracer);
|
||||
const {
|
||||
synthAudio,
|
||||
getNuanceAccessToken,
|
||||
getIbmAccessToken,
|
||||
} = require('@jambonz/speech-utils')({
|
||||
host: process.env.JAMBONES_REDIS_HOST,
|
||||
port: process.env.JAMBONES_REDIS_PORT || 6379
|
||||
host: JAMBONES_REDIS_HOST,
|
||||
port: JAMBONES_REDIS_PORT || 6379
|
||||
}, logger, tracer);
|
||||
const {
|
||||
writeAlerts,
|
||||
AlertType
|
||||
} = require('@jambonz/time-series')(logger, {
|
||||
host: process.env.JAMBONES_TIME_SERIES_HOST,
|
||||
host: JAMBONES_TIME_SERIES_HOST,
|
||||
commitSize: 50,
|
||||
commitInterval: 'test' === process.env.NODE_ENV ? 7 : 20
|
||||
commitInterval: 'test' === NODE_ENV ? 7 : 20
|
||||
});
|
||||
|
||||
let localIp;
|
||||
@@ -218,7 +233,7 @@ function installSrfLocals(srf, logger) {
|
||||
parentLogger: logger,
|
||||
getSBC,
|
||||
getSmpp: () => {
|
||||
return process.env.SMPP_URL;
|
||||
return SMPP_URL;
|
||||
},
|
||||
lifecycleEmitter,
|
||||
getFreeswitch,
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
const assert = require('assert');
|
||||
const timeSeries = require('@jambonz/time-series');
|
||||
const {
|
||||
NODE_ENV,
|
||||
JAMBONES_TIME_SERIES_HOST
|
||||
} = require('../config');
|
||||
let alerter ;
|
||||
|
||||
function isAbsoluteUrl(u) {
|
||||
@@ -28,9 +32,9 @@ class Requestor {
|
||||
|
||||
if (!alerter) {
|
||||
alerter = timeSeries(logger, {
|
||||
host: process.env.JAMBONES_TIME_SERIES_HOST,
|
||||
host: JAMBONES_TIME_SERIES_HOST,
|
||||
commitSize: 50,
|
||||
commitInterval: 'test' === process.env.NODE_ENV ? 7 : 20
|
||||
commitInterval: 'test' === NODE_ENV ? 7 : 20
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -38,9 +42,9 @@ class Requestor {
|
||||
get Alerter() {
|
||||
if (!alerter) {
|
||||
alerter = timeSeries(this.logger, {
|
||||
host: process.env.JAMBONES_TIME_SERIES_HOST,
|
||||
host: JAMBONES_TIME_SERIES_HOST,
|
||||
commitSize: 50,
|
||||
commitInterval: 'test' === process.env.NODE_ENV ? 7 : 20
|
||||
commitInterval: 'test' === NODE_ENV ? 7 : 20
|
||||
});
|
||||
}
|
||||
return alerter;
|
||||
|
||||
@@ -4,28 +4,38 @@ const {LifeCycleEvents, FS_UUID_SET_NAME} = require('./constants');
|
||||
const Emitter = require('events');
|
||||
const debug = require('debug')('jambonz:feature-server');
|
||||
const noopLogger = {info: () => {}, error: () => {}};
|
||||
const {
|
||||
JAMBONES_SBCS,
|
||||
K8S,
|
||||
K8S_SBC_SIP_SERVICE_NAME,
|
||||
AWS_SNS_TOPIC_ARM,
|
||||
OPTIONS_PING_INTERVAL,
|
||||
AWS_REGION,
|
||||
NODE_ENV,
|
||||
JAMBONES_CLUSTER_ID,
|
||||
} = require('../config');
|
||||
|
||||
module.exports = (logger) => {
|
||||
logger = logger || noopLogger;
|
||||
let idxSbc = 0;
|
||||
let sbcs = [];
|
||||
|
||||
if (process.env.JAMBONES_SBCS) {
|
||||
sbcs = process.env.JAMBONES_SBCS
|
||||
if (JAMBONES_SBCS) {
|
||||
sbcs = JAMBONES_SBCS
|
||||
.split(',')
|
||||
.map((sbc) => sbc.trim());
|
||||
assert.ok(sbcs.length, 'JAMBONES_SBCS env var is empty or misconfigured');
|
||||
logger.info({sbcs}, 'SBC inventory');
|
||||
}
|
||||
else if (process.env.K8S && process.env.K8S_SBC_SIP_SERVICE_NAME) {
|
||||
sbcs = [`${process.env.K8S_SBC_SIP_SERVICE_NAME}:5060`];
|
||||
else if (K8S && K8S_SBC_SIP_SERVICE_NAME) {
|
||||
sbcs = [`${K8S_SBC_SIP_SERVICE_NAME}:5060`];
|
||||
logger.info({sbcs}, 'SBC inventory');
|
||||
}
|
||||
|
||||
// listen for SNS lifecycle changes
|
||||
let lifecycleEmitter = new Emitter();
|
||||
let dryUpCalls = false;
|
||||
if (process.env.AWS_SNS_TOPIC_ARM && process.env.AWS_REGION) {
|
||||
if (AWS_SNS_TOPIC_ARM && AWS_REGION) {
|
||||
|
||||
(async function() {
|
||||
try {
|
||||
@@ -75,13 +85,13 @@ module.exports = (logger) => {
|
||||
}
|
||||
})();
|
||||
}
|
||||
else if (process.env.K8S) {
|
||||
else if (K8S) {
|
||||
lifecycleEmitter.scaleIn = () => process.exit(0);
|
||||
}
|
||||
|
||||
|
||||
async function pingProxies(srf) {
|
||||
if (process.env.NODE_ENV === 'test') return;
|
||||
if (NODE_ENV === 'test') return;
|
||||
|
||||
for (const sbc of sbcs) {
|
||||
try {
|
||||
@@ -102,7 +112,7 @@ module.exports = (logger) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (process.env.K8S) {
|
||||
if (K8S) {
|
||||
setImmediate(() => {
|
||||
logger.info('disabling OPTIONS pings since we are running as a kubernetes service');
|
||||
const {srf} = require('../..');
|
||||
@@ -123,16 +133,16 @@ module.exports = (logger) => {
|
||||
setInterval(() => {
|
||||
const {srf} = require('../..');
|
||||
pingProxies(srf);
|
||||
}, process.env.OPTIONS_PING_INTERVAL || 30000);
|
||||
}, OPTIONS_PING_INTERVAL);
|
||||
|
||||
// initial ping once we are up
|
||||
setTimeout(async() => {
|
||||
|
||||
// if SBCs are auto-scaling, monitor them as they come and go
|
||||
const {srf} = require('../..');
|
||||
if (!process.env.JAMBONES_SBCS) {
|
||||
if (!JAMBONES_SBCS) {
|
||||
const {monitorSet} = srf.locals.dbHelpers;
|
||||
const setName = `${(process.env.JAMBONES_CLUSTER_ID || 'default')}:active-sip`;
|
||||
const setName = `${(JAMBONES_CLUSTER_ID || 'default')}:active-sip`;
|
||||
await monitorSet(setName, 10, (members) => {
|
||||
sbcs = members;
|
||||
logger.info(`sbc-pinger: SBC roster has changed, list of active SBCs is now ${sbcs}`);
|
||||
|
||||
@@ -4,8 +4,12 @@ const short = require('short-uuid');
|
||||
const {HookMsgTypes} = require('./constants.json');
|
||||
const Websocket = require('ws');
|
||||
const snakeCaseKeys = require('./snakecase-keys');
|
||||
const MAX_RECONNECTS = 5;
|
||||
const RESPONSE_TIMEOUT_MS = process.env.JAMBONES_WS_API_MSG_RESPONSE_TIMEOUT || 5000;
|
||||
const {
|
||||
RESPONSE_TIMEOUT_MS,
|
||||
MAX_RECONNECTS,
|
||||
JAMBONES_WS_HANDSHAKE_TIMEOUT_MS,
|
||||
JAMBONES_WS_MAX_PAYLOAD
|
||||
} = require('../config');
|
||||
|
||||
class WsRequestor extends BaseRequestor {
|
||||
constructor(logger, account_sid, hook, secret) {
|
||||
@@ -192,14 +196,14 @@ class WsRequestor extends BaseRequestor {
|
||||
_connect() {
|
||||
assert(!this.ws);
|
||||
return new Promise((resolve, reject) => {
|
||||
const handshakeTimeout = process.env.JAMBONES_WS_HANDSHAKE_TIMEOUT_MS ?
|
||||
parseInt(process.env.JAMBONES_WS_HANDSHAKE_TIMEOUT_MS) :
|
||||
const handshakeTimeout = JAMBONES_WS_HANDSHAKE_TIMEOUT_MS ?
|
||||
parseInt(JAMBONES_WS_HANDSHAKE_TIMEOUT_MS) :
|
||||
1500;
|
||||
let opts = {
|
||||
followRedirects: true,
|
||||
maxRedirects: 2,
|
||||
handshakeTimeout,
|
||||
maxPayload: process.env.JAMBONES_WS_MAX_PAYLOAD ? parseInt(process.env.JAMBONES_WS_MAX_PAYLOAD) : 24 * 1024,
|
||||
maxPayload: JAMBONES_WS_MAX_PAYLOAD ? parseInt(JAMBONES_WS_MAX_PAYLOAD) : 24 * 1024,
|
||||
};
|
||||
if (this.username && this.password) opts = {...opts, auth: `${this.username}:${this.password}`};
|
||||
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
"start": "node app",
|
||||
"test": "NODE_ENV=test JAMBONES_HOSTING=1 HTTP_POOL=1 ENCRYPTION_SECRET=foobar DRACHTIO_HOST=127.0.0.1 DRACHTIO_PORT=9060 DRACHTIO_SECRET=cymru JAMBONES_MYSQL_HOST=127.0.0.1 JAMBONES_MYSQL_PORT=3360 JAMBONES_MYSQL_USER=jambones_test JAMBONES_MYSQL_PASSWORD=jambones_test JAMBONES_MYSQL_DATABASE=jambones_test JAMBONES_REDIS_HOST=127.0.0.1 JAMBONES_REDIS_PORT=16379 JAMBONES_LOGLEVEL=error ENABLE_METRICS=0 HTTP_PORT=3000 JAMBONES_SBCS=172.38.0.10 JAMBONES_FREESWITCH=127.0.0.1:8022:JambonzR0ck$:docker-host JAMBONES_TIME_SERIES_HOST=127.0.0.1 JAMBONES_NETWORK_CIDR=172.38.0.0/16 node test/ ",
|
||||
"coverage": "./node_modules/.bin/nyc --reporter html --report-dir ./coverage npm run test",
|
||||
"jslint": "eslint app.js lib"
|
||||
"jslint": "eslint app.js lib",
|
||||
"jslint:fix": "eslint app.js lib --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jambonz/db-helpers": "^0.7.4",
|
||||
|
||||
@@ -2,6 +2,14 @@ const test = require('tape') ;
|
||||
const exec = require('child_process').exec ;
|
||||
const fs = require('fs');
|
||||
const {encrypt} = require('../lib/utils/encrypt-decrypt');
|
||||
const {
|
||||
GCP_JSON_KEY,
|
||||
AWS_ACCESS_KEY_ID,
|
||||
AWS_SECRET_ACCESS_KEY,
|
||||
AWS_REGION,
|
||||
MICROSOFT_REGION,
|
||||
MICROSOFT_API_KEY,
|
||||
} = require('../lib/config');
|
||||
|
||||
test('creating jambones_test database', (t) => {
|
||||
exec(`mysql -h 127.0.0.1 -u root --protocol=tcp --port=3360 < ${__dirname}/db/create_test_db.sql`, (err, stdout, stderr) => {
|
||||
@@ -19,24 +27,24 @@ test('creating schema', (t) => {
|
||||
t.pass('schema and test data successfully created');
|
||||
|
||||
const sql = [];
|
||||
if (process.env.GCP_JSON_KEY) {
|
||||
const google_credential = encrypt(process.env.GCP_JSON_KEY);
|
||||
if (GCP_JSON_KEY) {
|
||||
const google_credential = encrypt(GCP_JSON_KEY);
|
||||
t.pass('adding google credentials');
|
||||
sql.push(`UPDATE speech_credentials SET credential='${google_credential}' WHERE vendor='google';`);
|
||||
}
|
||||
if (process.env.AWS_ACCESS_KEY_ID && process.env.AWS_SECRET_ACCESS_KEY) {
|
||||
if (AWS_ACCESS_KEY_ID && AWS_SECRET_ACCESS_KEY) {
|
||||
const aws_credential = encrypt(JSON.stringify({
|
||||
access_key_id: process.env.AWS_ACCESS_KEY_ID,
|
||||
secret_access_key: process.env.AWS_SECRET_ACCESS_KEY,
|
||||
aws_region: process.env.AWS_REGION
|
||||
access_key_id: AWS_ACCESS_KEY_ID,
|
||||
secret_access_key: AWS_SECRET_ACCESS_KEY,
|
||||
aws_region: AWS_REGION
|
||||
}));
|
||||
t.pass('adding aws credentials');
|
||||
sql.push(`UPDATE speech_credentials SET credential='${aws_credential}' WHERE vendor='aws';`);
|
||||
}
|
||||
if (process.env.MICROSOFT_REGION && process.env.MICROSOFT_API_KEY) {
|
||||
if (MICROSOFT_REGION && MICROSOFT_API_KEY) {
|
||||
const microsoft_credential = encrypt(JSON.stringify({
|
||||
region: process.env.MICROSOFT_REGION,
|
||||
api_key: process.env.MICROSOFT_API_KEY
|
||||
region: MICROSOFT_REGION,
|
||||
api_key: MICROSOFT_API_KEY
|
||||
}));
|
||||
t.pass('adding microsoft credentials');
|
||||
sql.push(`UPDATE speech_credentials SET credential='${microsoft_credential}' WHERE vendor='microsoft';`);
|
||||
|
||||
@@ -4,6 +4,15 @@ const bent = require('bent');
|
||||
const getJSON = bent('json')
|
||||
const clearModule = require('clear-module');
|
||||
const {provisionCallHook} = require('./utils')
|
||||
const {
|
||||
GCP_JSON_KEY,
|
||||
AWS_ACCESS_KEY_ID,
|
||||
AWS_SECRET_ACCESS_KEY,
|
||||
SONIOX_API_KEY,
|
||||
DEEPGRAM_API_KEY,
|
||||
MICROSOFT_REGION,
|
||||
MICROSOFT_API_KEY,
|
||||
} = require('../lib/config');
|
||||
|
||||
process.on('unhandledRejection', (reason, p) => {
|
||||
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
|
||||
@@ -18,7 +27,7 @@ function connect(connectable) {
|
||||
}
|
||||
|
||||
test('\'gather\' test - google', async(t) => {
|
||||
if (!process.env.GCP_JSON_KEY) {
|
||||
if (!GCP_JSON_KEY) {
|
||||
t.pass('skipping google tests');
|
||||
return t.end();
|
||||
}
|
||||
@@ -58,7 +67,7 @@ test('\'gather\' test - google', async(t) => {
|
||||
});
|
||||
|
||||
test('\'gather\' test - default (google)', async(t) => {
|
||||
if (!process.env.GCP_JSON_KEY) {
|
||||
if (!GCP_JSON_KEY) {
|
||||
t.pass('skipping google tests');
|
||||
return t.end();
|
||||
}
|
||||
@@ -94,7 +103,7 @@ test('\'gather\' test - default (google)', async(t) => {
|
||||
});
|
||||
|
||||
test('\'gather\' test - microsoft', async(t) => {
|
||||
if (!process.env.MICROSOFT_REGION || !process.env.MICROSOFT_API_KEY) {
|
||||
if (!MICROSOFT_REGION || !MICROSOFT_API_KEY) {
|
||||
t.pass('skipping microsoft tests');
|
||||
return t.end();
|
||||
}
|
||||
@@ -134,7 +143,7 @@ test('\'gather\' test - microsoft', async(t) => {
|
||||
});
|
||||
|
||||
test('\'gather\' test - aws', async(t) => {
|
||||
if (!process.env.AWS_ACCESS_KEY_ID || !process.env.AWS_SECRET_ACCESS_KEY) {
|
||||
if (!AWS_ACCESS_KEY_ID || !AWS_SECRET_ACCESS_KEY) {
|
||||
t.pass('skipping aws tests');
|
||||
return t.end();
|
||||
}
|
||||
@@ -174,7 +183,7 @@ test('\'gather\' test - aws', async(t) => {
|
||||
});
|
||||
|
||||
test('\'gather\' test - deepgram', async(t) => {
|
||||
if (!process.env.DEEPGRAM_API_KEY ) {
|
||||
if (!DEEPGRAM_API_KEY ) {
|
||||
t.pass('skipping deepgram tests');
|
||||
return t.end();
|
||||
}
|
||||
@@ -192,7 +201,7 @@ test('\'gather\' test - deepgram', async(t) => {
|
||||
"vendor": "deepgram",
|
||||
"hints": ["customer support", "sales", "human resources", "HR"],
|
||||
"deepgramOptions": {
|
||||
"apiKey": process.env.DEEPGRAM_API_KEY
|
||||
"apiKey": DEEPGRAM_API_KEY
|
||||
}
|
||||
},
|
||||
"timeout": 10,
|
||||
@@ -216,7 +225,7 @@ test('\'gather\' test - deepgram', async(t) => {
|
||||
});
|
||||
|
||||
test('\'gather\' test - soniox', async(t) => {
|
||||
if (!process.env.SONIOX_API_KEY ) {
|
||||
if (!SONIOX_API_KEY ) {
|
||||
t.pass('skipping soniox tests');
|
||||
return t.end();
|
||||
}
|
||||
@@ -234,7 +243,7 @@ test('\'gather\' test - soniox', async(t) => {
|
||||
"vendor": "deepgram",
|
||||
"hints": ["customer support", "sales", "human resources", "HR"],
|
||||
"deepgramOptions": {
|
||||
"apiKey": process.env.SONIOX_API_KEY
|
||||
"apiKey": SONIOX_API_KEY
|
||||
}
|
||||
},
|
||||
"timeout": 10,
|
||||
|
||||
@@ -4,6 +4,15 @@ const bent = require('bent');
|
||||
const getJSON = bent('json')
|
||||
const clearModule = require('clear-module');
|
||||
const {provisionCallHook} = require('./utils')
|
||||
const {
|
||||
GCP_JSON_KEY,
|
||||
AWS_ACCESS_KEY_ID,
|
||||
AWS_SECRET_ACCESS_KEY,
|
||||
MICROSOFT_REGION,
|
||||
MICROSOFT_API_KEY,
|
||||
SONIOX_API_KEY,
|
||||
DEEPGRAM_API_KEY,
|
||||
} = require('../lib/config');
|
||||
|
||||
process.on('unhandledRejection', (reason, p) => {
|
||||
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
|
||||
@@ -18,7 +27,7 @@ function connect(connectable) {
|
||||
}
|
||||
|
||||
test('\'transcribe\' test - google', async(t) => {
|
||||
if (!process.env.GCP_JSON_KEY) {
|
||||
if (!GCP_JSON_KEY) {
|
||||
t.pass('skipping google tests');
|
||||
return t.end();
|
||||
}
|
||||
@@ -55,7 +64,7 @@ test('\'transcribe\' test - google', async(t) => {
|
||||
});
|
||||
|
||||
test('\'transcribe\' test - microsoft', async(t) => {
|
||||
if (!process.env.MICROSOFT_REGION || !process.env.MICROSOFT_API_KEY) {
|
||||
if (!MICROSOFT_REGION || !MICROSOFT_API_KEY) {
|
||||
t.pass('skipping microsoft tests');
|
||||
return t.end();
|
||||
}
|
||||
@@ -92,7 +101,7 @@ test('\'transcribe\' test - microsoft', async(t) => {
|
||||
});
|
||||
|
||||
test('\'transcribe\' test - aws', async(t) => {
|
||||
if (!process.env.AWS_ACCESS_KEY_ID || !process.env.AWS_SECRET_ACCESS_KEY) {
|
||||
if (!AWS_ACCESS_KEY_ID || !AWS_SECRET_ACCESS_KEY) {
|
||||
t.pass('skipping aws tests');
|
||||
return t.end();
|
||||
}
|
||||
@@ -129,7 +138,7 @@ test('\'transcribe\' test - aws', async(t) => {
|
||||
});
|
||||
|
||||
test('\'transcribe\' test - deepgram', async(t) => {
|
||||
if (!process.env.DEEPGRAM_API_KEY ) {
|
||||
if (!DEEPGRAM_API_KEY ) {
|
||||
t.pass('skipping deepgram tests');
|
||||
return t.end();
|
||||
}
|
||||
@@ -146,7 +155,7 @@ test('\'transcribe\' test - deepgram', async(t) => {
|
||||
"vendor": "deepgram",
|
||||
"hints": ["customer support", "sales", "human resources", "HR"],
|
||||
"deepgramOptions": {
|
||||
"apiKey": process.env.DEEPGRAM_API_KEY
|
||||
"apiKey": DEEPGRAM_API_KEY
|
||||
}
|
||||
},
|
||||
"transcriptionHook": "/transcriptionHook"
|
||||
@@ -169,7 +178,7 @@ test('\'transcribe\' test - deepgram', async(t) => {
|
||||
});
|
||||
|
||||
test('\'transcribe\' test - soniox', async(t) => {
|
||||
if (!process.env.SONIOX_API_KEY ) {
|
||||
if (!SONIOX_API_KEY ) {
|
||||
t.pass('skipping soniox tests');
|
||||
return t.end();
|
||||
}
|
||||
@@ -186,7 +195,7 @@ test('\'transcribe\' test - soniox', async(t) => {
|
||||
"vendor": "soniox",
|
||||
"hints": ["customer support", "sales", "human resources", "HR"],
|
||||
"deepgramOptions": {
|
||||
"apiKey": process.env.SONIOX_API_KEY
|
||||
"apiKey": SONIOX_API_KEY
|
||||
}
|
||||
},
|
||||
"transcriptionHook": "/transcriptionHook"
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
const express = require('express');
|
||||
const app = express();
|
||||
const Websocket = require('ws');
|
||||
const listenPort = process.env.HTTP_PORT || 3000;
|
||||
const {PORT} = require('../../lib/config');
|
||||
const listenPort = PORT;
|
||||
let json_mapping = new Map();
|
||||
let hook_mapping = new Map();
|
||||
let ws_packet_count = new Map();
|
||||
|
||||
@@ -2,13 +2,17 @@ const test = require('tape');
|
||||
const { sippUac } = require('./sipp')('test_fs');
|
||||
const clearModule = require('clear-module');
|
||||
const {provisionCallHook} = require('./utils')
|
||||
const {
|
||||
JAMBONES_LOGLEVEL,
|
||||
JAMBONES_TIME_SERIES_HOST
|
||||
} = require('../lib/config');
|
||||
const opts = {
|
||||
timestamp: () => {return `, "time": "${new Date().toISOString()}"`;},
|
||||
level: process.env.JAMBONES_LOGLEVEL || 'info'
|
||||
level: JAMBONES_LOGLEVEL
|
||||
};
|
||||
const logger = require('pino')(opts);
|
||||
const { queryAlerts } = require('@jambonz/time-series')(
|
||||
logger, process.env.JAMBONES_TIME_SERIES_HOST
|
||||
logger, JAMBONES_TIME_SERIES_HOST
|
||||
);
|
||||
|
||||
process.on('unhandledRejection', (reason, p) => {
|
||||
|
||||
@@ -3,7 +3,10 @@ const sinon = require('sinon');
|
||||
const proxyquire = require("proxyquire");
|
||||
proxyquire.noCallThru();
|
||||
const MockWebsocket = require('./ws-mock')
|
||||
const logger = require('pino')({level: process.env.JAMBONES_LOGLEVEL || 'error'});
|
||||
const {
|
||||
JAMBONES_LOGLEVEL,
|
||||
} = require('../lib/config');
|
||||
const logger = require('pino')({level: JAMBONES_LOGLEVEL});
|
||||
|
||||
const BaseRequestor = proxyquire(
|
||||
"../lib/utils/base-requestor",
|
||||
|
||||
16
tracer.js
16
tracer.js
@@ -7,12 +7,14 @@ const { BatchSpanProcessor } = require('@opentelemetry/sdk-trace-base');
|
||||
const { JaegerExporter } = require('@opentelemetry/exporter-jaeger');
|
||||
const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin');
|
||||
const { OTLPTraceExporter } = require ('@opentelemetry/exporter-trace-otlp-http');
|
||||
//const { HttpInstrumentation } = require('@opentelemetry/instrumentation-http');
|
||||
//const { ExpressInstrumentation } = require('@opentelemetry/instrumentation-express');
|
||||
//const { PinoInstrumentation } = require('@opentelemetry/instrumentation-pino');
|
||||
const {
|
||||
JAMBONES_OTEL_ENABLED,
|
||||
OTEL_EXPORTER_JAEGER_AGENT_HOST,
|
||||
OTEL_EXPORTER_ZIPKIN_URL,
|
||||
} = require('./lib/config');
|
||||
|
||||
module.exports = (serviceName) => {
|
||||
if (process.env.JAMBONES_OTEL_ENABLED) {
|
||||
if (JAMBONES_OTEL_ENABLED) {
|
||||
const {version} = require('./package.json');
|
||||
const provider = new NodeTracerProvider({
|
||||
resource: new Resource({
|
||||
@@ -22,11 +24,11 @@ module.exports = (serviceName) => {
|
||||
});
|
||||
|
||||
let exporter;
|
||||
if (process.env.OTEL_EXPORTER_JAEGER_AGENT_HOST || process.env.OTEL_EXPORTER_JAEGER_ENDPOINT) {
|
||||
if (OTEL_EXPORTER_JAEGER_AGENT_HOST || OTEL_EXPORTER_JAEGER_ENDPOINT) {
|
||||
exporter = new JaegerExporter();
|
||||
}
|
||||
else if (process.env.OTEL_EXPORTER_ZIPKIN_URL) {
|
||||
exporter = new ZipkinExporter({url:process.env.OTEL_EXPORTER_ZIPKIN_URL});
|
||||
else if (OTEL_EXPORTER_ZIPKIN_URL) {
|
||||
exporter = new ZipkinExporter({url:OTEL_EXPORTER_ZIPKIN_URL});
|
||||
}
|
||||
else {
|
||||
exporter = new OTLPTraceExporter({
|
||||
|
||||
Reference in New Issue
Block a user