Files
zfjia 35751b4f00
IT-0 verify / verify (push) Waiting to run
1111
2026-11-11 18:30:31 +08:00

157 lines
10 KiB
SQL
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- =============================================================================
-- AMI 连接与语音链路增量(一公寓一 Asterisk 实例)
-- 依据:公寓端/19 设计文档;公寓端/05 表 5-12(SIP 叫乘链路)、表 5-13(AMI 事件映射);
-- docs/10 表 8-3(AMI 不出本机)、表 8-4(端口 7058)、D5(一进程一 gyid)
-- 口径:
-- 1) 新增 1 张映射表 apt_ast_instance:gyid 唯一 -> 一公寓一实例(UK 兜底)。
-- 这是对「59 张表」基线的显式偏离,已在公寓端/19 §7 登记(新增第 60 张)。
-- 2) AMI 口令**不落库**:只存环境变量引用 ami_secret_ref(红钱:口令不进仓库)。
-- 3) 复用既有 apt_ast_ami_session / apt_call_session / apt_call_event /
-- apt_tts_utterance / apt_recording,仅补列,不新建语音表。
-- 4) 幂等:建表 IF NOT EXISTS,补列走 apt_add_column_if_missing。
-- =============================================================================
SET NAMES utf8mb4;
-- -----------------------------------------------------------------------------
-- 1. 公寓 ↔ Asterisk 实例映射(1:1)
-- -----------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS apt_ast_instance (
id BIGINT NOT NULL AUTO_INCREMENT COMMENT '代理主键',
gyid VARCHAR(32) NOT NULL COMMENT '公寓隔离标识(D5:一进程一 gyid)',
instance_code VARCHAR(64) NOT NULL COMMENT '实例编码,如 AST-REV01-001',
display_name VARCHAR(64) NULL COMMENT '展示名,如 1 号楼机房 Asterisk',
ami_host VARCHAR(128) NOT NULL COMMENT 'AMI 地址;生产固定 127.0.0.1(AMI 不出本机)',
ami_port INT NOT NULL DEFAULT 5038 COMMENT 'AMI 端口;现网配置值 7058',
ami_user VARCHAR(64) NOT NULL COMMENT 'AMI 账号',
ami_secret_ref VARCHAR(128) NOT NULL COMMENT '口令引用(环境变量名),禁止存明文',
tls_enabled TINYINT NOT NULL DEFAULT 0 COMMENT '0 明文 / 1 TLS(TLS 端口另配)',
conference VARCHAR(64) NOT NULL DEFAULT 'Conf-01' COMMENT '会议桥标识(D11 未定前不改)',
dial_context VARCHAR(64) NOT NULL DEFAULT 'from-internal' COMMENT '拨号计划上下文',
dial_prefix VARCHAR(16) NULL COMMENT '外呼前缀(如 9),本地分机为空',
channel_tech VARCHAR(16) NOT NULL DEFAULT 'PJSIP' COMMENT '话机通道技术:PJSIP / SIP',
recording_base_url VARCHAR(256) NULL COMMENT '录音 HTTP 基址(只对内网)',
connect_timeout_ms INT NOT NULL DEFAULT 3000 COMMENT 'TCP 建连超时',
action_timeout_ms INT NOT NULL DEFAULT 5000 COMMENT 'AMI Action 等待 Response 超时',
ping_interval_sec INT NOT NULL DEFAULT 30 COMMENT '心跳间隔(Action: Ping)',
ping_timeout_sec INT NOT NULL DEFAULT 5 COMMENT '单次心跳超时',
reconnect_initial_ms INT NOT NULL DEFAULT 1000 COMMENT '重连初始退避',
reconnect_max_ms INT NOT NULL DEFAULT 60000 COMMENT '重连最大退避(封顶)',
state VARCHAR(20) NOT NULL DEFAULT 'DOWN' COMMENT 'DOWN/CONNECTING/UP/DEGRADED/DISABLED',
last_connected_at DATETIME(3) NULL COMMENT '最近登录成功时刻',
last_ping_at DATETIME(3) NULL COMMENT '最近心跳成功时刻',
last_error VARCHAR(256) NULL COMMENT '最近一次失败原因(脱敏,不含口令)',
enabled TINYINT NOT NULL DEFAULT 1 COMMENT '0 停用(不建连、不叫乘)',
biz_version BIGINT NOT NULL DEFAULT 1 COMMENT '数据库条件更新乐观锁',
deleted TINYINT NOT NULL DEFAULT 0,
create_time DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
update_time DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
UNIQUE KEY uk_astinstance_gyid (gyid),
KEY idx_astinstance_gyid_state (gyid, state, enabled),
CONSTRAINT ck_astinstance_state CHECK (state IN ('DOWN','CONNECTING','UP','DEGRADED','DISABLED')),
CONSTRAINT ck_astinstance_enabled CHECK (enabled IN (0,1))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
COMMENT='公寓-Asterisk 实例映射与 AMI 连接配置(一公寓一实例)';
-- 默认实例:只写占位地址与口令引用,口令由部署环境 APT_AMI_SECRET 注入
INSERT INTO apt_ast_instance
(gyid, instance_code, display_name, ami_host, ami_port, ami_user, ami_secret_ref,
conference, dial_context, state, enabled, create_time, update_time)
SELECT 'APT-REV01-001', 'AST-REV01-001', '本机 Asterisk(AMI 仅本机)',
'127.0.0.1', 5038, 'apt', 'APT_AMI_SECRET',
'Conf-01', 'from-internal', 'DOWN', 1, NOW(3), NOW(3)
WHERE NOT EXISTS (
SELECT 1 FROM apt_ast_instance WHERE gyid = 'APT-REV01-001' AND deleted = 0
);
-- -----------------------------------------------------------------------------
-- 2. AMI 会话补列:心跳与断连原因(表已有 connected_at/disconnected_at/reconnect_count/state)
-- -----------------------------------------------------------------------------
CALL apt_add_column_if_missing('apt_ast_ami_session', 'last_ping_at',
"last_ping_at DATETIME(3) NULL COMMENT '最近心跳成功时刻'");
CALL apt_add_column_if_missing('apt_ast_ami_session', 'last_error',
"last_error VARCHAR(256) NULL COMMENT '本次连接断开的失败原因(脱敏)'");
CALL apt_add_column_if_missing('apt_ast_ami_session', 'close_reason',
"close_reason VARCHAR(64) NULL COMMENT 'CLIENT_CLOSE / IO_ERROR / PING_TIMEOUT / AUTH_FAILED / SHUTDOWN'");
-- -----------------------------------------------------------------------------
-- 3. 通话会话补列:双腿(房间/值班台)与通道映射
-- -----------------------------------------------------------------------------
CALL apt_add_column_if_missing('apt_call_session', 'leg_role',
"leg_role VARCHAR(16) NOT NULL DEFAULT 'ROOM' COMMENT '腿角色:ROOM 房间 / DUTY 值班台 / TTS 播报'");
CALL apt_add_column_if_missing('apt_call_session', 'channel',
"channel VARCHAR(128) NULL COMMENT 'AMI Channel(PJSIP/1001-00000001),事件反查用'");
CALL apt_add_column_if_missing('apt_call_session', 'originate_action_id',
"originate_action_id VARCHAR(64) NULL COMMENT 'Originate ActionID,OriginateResponse 关联用'");
CALL apt_add_column_if_missing('apt_call_session', 'ami_session_id',
"ami_session_id VARCHAR(64) NULL COMMENT '所属 AMI 连接会话(apt_ast_ami_session.ami_session_id)'");
-- -----------------------------------------------------------------------------
-- 4. TTS 播报补列:与会话/序号绑定,避免并发时互相覆盖(docs/10 表 10-13 TTS 槽位风险)
-- -----------------------------------------------------------------------------
CALL apt_add_column_if_missing('apt_tts_utterance', 'session_id',
"session_id VARCHAR(64) NULL COMMENT '关联会话;一次入会一条播报链'");
CALL apt_add_column_if_missing('apt_tts_utterance', 'utterance_seq',
"utterance_seq BIGINT NOT NULL DEFAULT 1 COMMENT '同会话单调递增,禁止共用槽位'");
CALL apt_add_column_if_missing('apt_tts_utterance', 'played_at',
"played_at DATETIME(3) NULL COMMENT '播放完成时刻'");
CALL apt_add_column_if_missing('apt_tts_utterance', 'error_msg',
"error_msg VARCHAR(256) NULL COMMENT '失败原因(不改叫乘结论,只告警)'");
-- 会话按通道反查(事件热点路径)
SET @apt_idx_channel = (SELECT COUNT(*) FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'apt_call_session'
AND INDEX_NAME = 'idx_callsession_gyid_channel');
SET @apt_sql_channel = IF(@apt_idx_channel = 0,
'ALTER TABLE apt_call_session ADD KEY idx_callsession_gyid_channel (gyid, channel)',
'SELECT 1');
PREPARE apt_stmt_channel FROM @apt_sql_channel;
EXECUTE apt_stmt_channel;
DEALLOCATE PREPARE apt_stmt_channel;
SET @apt_idx_action = (SELECT COUNT(*) FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'apt_call_session'
AND INDEX_NAME = 'idx_callsession_gyid_action');
SET @apt_sql_action = IF(@apt_idx_action = 0,
'ALTER TABLE apt_call_session ADD KEY idx_callsession_gyid_action (gyid, originate_action_id)',
'SELECT 1');
PREPARE apt_stmt_action FROM @apt_sql_action;
EXECUTE apt_stmt_action;
DEALLOCATE PREPARE apt_stmt_action;
-- -----------------------------------------------------------------------------
-- 5. 校验
-- -----------------------------------------------------------------------------
SELECT '=== 27. 公寓-实例映射(应 1 行,一公寓一实例)===' AS section;
SELECT gyid, instance_code, ami_host, ami_port, ami_user, ami_secret_ref,
conference, dial_context, state, enabled
FROM apt_ast_instance WHERE deleted = 0 ORDER BY gyid;
SELECT '=== 28. 口令不落明文(应 0:secret_ref 不得是疑似明文口令)===' AS section;
SELECT COUNT(*) AS plaintext_secret_rows
FROM apt_ast_instance
WHERE deleted = 0
AND (ami_secret_ref LIKE '% %' OR ami_secret_ref LIKE '%.%' OR CHAR_LENGTH(ami_secret_ref) > 64);
SELECT '=== 29. AMI 会话补列(应 3)===' AS section;
SELECT COUNT(*) AS ami_session_columns
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'apt_ast_ami_session'
AND COLUMN_NAME IN ('last_ping_at','last_error','close_reason');
SELECT '=== 30. 会话/TTS 补列(应 8:call_session 4 + tts 4)===' AS section;
SELECT COUNT(*) AS call_tts_columns
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND ((TABLE_NAME = 'apt_call_session'
AND COLUMN_NAME IN ('leg_role','channel','originate_action_id','ami_session_id'))
OR (TABLE_NAME = 'apt_tts_utterance'
AND COLUMN_NAME IN ('session_id','utterance_seq','played_at','error_msg')));
SELECT '=== 31. 会话索引(应 2)===' AS section;
SELECT INDEX_NAME, GROUP_CONCAT(COLUMN_NAME ORDER BY SEQ_IN_INDEX) AS cols
FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'apt_call_session'
AND INDEX_NAME IN ('idx_callsession_gyid_channel','idx_callsession_gyid_action')
GROUP BY INDEX_NAME;