157 lines
10 KiB
SQL
157 lines
10 KiB
SQL
-- =============================================================================
|
||
-- 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;
|