Enables outbound PSTN probes via TwiML webhooks with Webex result cards, status polling, and optional store CDR enrichment.
93 lines
2.8 KiB
JavaScript
93 lines
2.8 KiB
JavaScript
// commands/callTest.js
|
||
// /calltest — Twilio voice path testing (store AA entry or direct dial).
|
||
|
||
import {
|
||
getConfigurationMessage,
|
||
getSessionForStatus,
|
||
isCallTestConfigured,
|
||
startDialTest,
|
||
startStoreTest,
|
||
} from '../services/callTest/callTestService.js';
|
||
import { parseCallTestArgs } from '../services/callTest/parseArgs.js';
|
||
import { renderCallTestResultMarkdown } from '../services/renderers/callTestRenderer.js';
|
||
import { extractRequester } from '../utils/requester.js';
|
||
import { logger } from '../utils/logger.js';
|
||
|
||
function usageMarkdown() {
|
||
return (
|
||
'**Usage:** `/calltest <store|store subcommand|dial subcommand>`\n\n' +
|
||
'**Store path** (auto-attendant → DTMF → 60s test):\n' +
|
||
'• `/calltest 782` or `/calltest store 782`\n' +
|
||
'• `/calltest store 782 +12125550100` — override main number\n\n' +
|
||
'**Direct dial** (answer → 60s test, no AA/DTMF):\n' +
|
||
'• `/calltest dial +12125550100`\n' +
|
||
'• `/calltest +12125550100` — shorthand when arg looks like a phone number\n\n' +
|
||
'**Status:**\n' +
|
||
'• `/calltest status <testId>`\n\n' +
|
||
'Each test places a **real outbound call** from the configured Twilio number. ' +
|
||
'Results post to this room when the call completes (~2–3 min).'
|
||
);
|
||
}
|
||
|
||
export async function handleCallTest(bot, trigger) {
|
||
logger('calltest', 'Handler entered');
|
||
|
||
const args = trigger.args || [];
|
||
const query = trigger.query || {};
|
||
const parsed = parseCallTestArgs(
|
||
args.length
|
||
? args
|
||
: [
|
||
query.mode,
|
||
query.store || query.storeNum,
|
||
query.dial || query.number,
|
||
query.testId,
|
||
].filter(Boolean),
|
||
);
|
||
|
||
if (parsed.kind === 'usage') {
|
||
await bot.say('markdown', usageMarkdown());
|
||
return;
|
||
}
|
||
|
||
if (!isCallTestConfigured()) {
|
||
await bot.say('markdown', getConfigurationMessage() || 'Call test is not available.');
|
||
return;
|
||
}
|
||
|
||
const roomId = trigger.roomId || bot?.room?.id || null;
|
||
const requester = extractRequester(trigger);
|
||
|
||
try {
|
||
if (parsed.kind === 'status') {
|
||
const session = getSessionForStatus(parsed.testId);
|
||
if (!session) {
|
||
await bot.say('markdown', `No in-memory session for testId \`${parsed.testId}\` (expired or unknown).`);
|
||
return;
|
||
}
|
||
await bot.say('markdown', renderCallTestResultMarkdown(session));
|
||
return;
|
||
}
|
||
|
||
if (parsed.kind === 'store') {
|
||
await startStoreTest({
|
||
storeNum: parsed.storeNum,
|
||
dialOverride: parsed.dialOverride,
|
||
roomId,
|
||
requester,
|
||
});
|
||
return;
|
||
}
|
||
|
||
if (parsed.kind === 'dial') {
|
||
await startDialTest({
|
||
dialNumber: parsed.dial,
|
||
roomId,
|
||
requester,
|
||
});
|
||
}
|
||
} catch (err) {
|
||
logger('calltest', `Handler error: ${err.message}`, 'error');
|
||
await bot.say('markdown', `❌ **Call test failed**\n\n${err.message}`);
|
||
}
|
||
}
|