From e5d32e6b4c40c8c87f89c716faaf9256ae2d0459 Mon Sep 17 00:00:00 2001 From: hectorzhao Date: Tue, 1 Sep 2026 10:20:54 +0800 Subject: [PATCH] fix: emit talk start after dialog route matching --- infra/server-b/caller-analytics/deploy.sh | 2 +- scripts/instrument-caller-analytics.mjs | 25 +++++++++++++++++------ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/infra/server-b/caller-analytics/deploy.sh b/infra/server-b/caller-analytics/deploy.sh index 44920b8..58a78cd 100644 --- a/infra/server-b/caller-analytics/deploy.sh +++ b/infra/server-b/caller-analytics/deploy.sh @@ -67,7 +67,7 @@ tar -xzf "$archive" -C "$new" printf '%s\n' "$commit" > "$new/.deployed-commit" printf '%s\n' "$old" > "$new/.delta-base-release" source_cfg="$backup/opensips.cfg" -if grep -q 'CRA_INSTRUMENTATION_VERSION=2' "$source_cfg"; then +if grep -q 'CRA_INSTRUMENTATION_VERSION=3' "$source_cfg"; then cp "$source_cfg" "$new/opensips-candidate.cfg" else /usr/bin/node "$new/scripts/instrument-caller-analytics.mjs" "$source_cfg" "$new/opensips-candidate.cfg" diff --git a/scripts/instrument-caller-analytics.mjs b/scripts/instrument-caller-analytics.mjs index 41d29c9..7a46a95 100644 --- a/scripts/instrument-caller-analytics.mjs +++ b/scripts/instrument-caller-analytics.mjs @@ -3,17 +3,30 @@ import { readFileSync, writeFileSync } from 'node:fs'; const [source, output] = process.argv.slice(2); if (!source || !output) throw new Error('Usage: node instrument-caller-analytics.mjs source.cfg output.cfg'); let cfg = readFileSync(source, 'utf8').replaceAll('\r\n', '\n').replace(/^\uFEFF/, ''); -if (cfg.includes('CRA_INSTRUMENTATION_VERSION=2')) throw new Error('Already instrumented at version 2'); +if (cfg.includes('CRA_INSTRUMENTATION_VERSION=3')) throw new Error('Already instrumented at version 3'); function insert(marker, extra, after = false) { if (cfg.split(marker).length !== 2) throw new Error(`Unsupported routing layout: ${marker}`); cfg = cfg.replace(marker, after ? marker + extra : extra + marker); } -const versionMarker = '# CRA_INSTRUMENTATION_VERSION=2\n'; +const versionMarker = '# CRA_INSTRUMENTATION_VERSION=3\n'; const registerStats = () => insert('modparam("statistics", "variable", "s28_cdr_xadd_error_total/no_reset")', '\nmodparam("statistics", "variable", "cra_event_total/no_reset")', true); const ackHook = ` if (is_method("ACK")) {\n $var(cra_kind)="TALK_START"; $var(cra_code)=200; $var(cra_source)="dialog-acked"; route(CRA_EMIT_DLG);\n }\n`; +const testPeerAckHook = ` if (loose_route()) {\n $var(cra_kind)="TALK_START"; $var(cra_code)=200; $var(cra_source)="dialog-acked"; route(CRA_EMIT_DLG);\n }\n`; +const placeAckHooks = () => { + insert(' if (loose_route()) {\n', ackHook, true); + insert(' if (is_method("ACK") && $si == "100.93.185.30") {\n', testPeerAckHook, true); +}; +if (cfg.includes('CRA_INSTRUMENTATION_VERSION=2')) { + if (!cfg.includes(ackHook)) throw new Error('Version 2 ACK hook not found'); + cfg = cfg.replace('# CRA_INSTRUMENTATION_VERSION=2\n', '').replace(ackHook, ''); + placeAckHooks(); + writeFileSync(output, versionMarker + cfg, 'utf8'); + console.log('Analytics observation hooks upgraded to version 3 ACK matching; OpenSIPS config validation is required before activation.'); + process.exit(0); +} if (cfg.includes('CRA1|')) { registerStats(); - insert(' if (has_totag()) {\n', ackHook, true); + placeAckHooks(); cfg = cfg .replace('$var(cra_kind)="END"; $var(cra_code)=$var(s28_reply_code); $var(cra_source)="platform-final"; route(CRA_EMIT_AVP);', '$var(cra_kind)="END"; $var(cra_code)=$var(s28_reply_code); $var(cra_source)="platform-final"; route(CRA_EMIT_AVP);\n $var(cra_kind)="CLOSE"; $var(cra_source)="platform-closed"; route(CRA_EMIT_AVP);') .replace('$var(cra_kind)="END"; $var(cra_code)=200; $var(cra_source)="verified-dialog-final"; route(CRA_EMIT_DLG);', '$var(cra_kind)="END"; $var(cra_code)=200; $var(cra_source)="verified-dialog-final"; route(CRA_EMIT_DLG);\n $var(cra_kind)="CLOSE"; $var(cra_source)="dialog-closed"; route(CRA_EMIT_DLG);') @@ -21,11 +34,11 @@ if (cfg.includes('CRA1|')) { .replace('$var(cra_kind)="END"; $var(cra_code)=$T_reply_code; $var(cra_source)="verified-dialog-final"; route(CRA_EMIT_DLG);', '$var(cra_kind)="END"; $var(cra_code)=$T_reply_code; $var(cra_source)="verified-dialog-final"; route(CRA_EMIT_DLG);\n $var(cra_kind)="CLOSE"; $var(cra_source)="attempts-exhausted"; route(CRA_EMIT_DLG);') .replaceAll('xlog("L_NOTICE", "CRA1|', 'update_stat("cra_event_total", 1);\n xlog("L_NOTICE", "CRA1|'); writeFileSync(output, versionMarker + cfg, 'utf8'); - console.log('Analytics observation hooks upgraded to version 2; OpenSIPS config validation is required before activation.'); + console.log('Analytics observation hooks upgraded to version 3; OpenSIPS config validation is required before activation.'); process.exit(0); } registerStats(); -insert(' if (has_totag()) {\n', ackHook, true); +placeAckHooks(); const metadata = { uid: '$ci + "~" + $ft + "~" + $TS', callid: '$ci', customer: '$var(s28_customer_id)', gateway: '$var(s28_gateway_id)', vendor: '$var(s28_vendor_id)', vendorGateway: '$var(s28_vendor_gateway_id)', @@ -60,4 +73,4 @@ failure_route[CRA_FAILURE] { } `; writeFileSync(output, versionMarker + cfg, 'utf8'); -console.log('Analytics observation hooks generated; OpenSIPS config validation is required before activation.'); +console.log('Analytics observation hooks generated at version 3; OpenSIPS config validation is required before activation.');