第六阶段开发。
This commit is contained in:
1 parent
35751b4f00
commit
bacdd15f3a
93 files changed
+10190
-22
No files matched your search
@@ -0,0 +1,132 @@
|
||||
-- =============================================================================
|
||||
-- SIP 分机 / AOR / Contact 与房间的统一管理(承接 03_domain_03_voice.sql)
|
||||
-- 口径:
|
||||
-- 1) apt_sip_endpoint = 分机(PJSIP endpoint),一房一分机,extension 不可改号;
|
||||
-- 2) apt_sip_aor = 分机对应的 AOR(1:1,max_contacts=1 与文件一致);
|
||||
-- 3) apt_sip_contact = AOR 下的 contact(话机 IP 绑定事实,含历史);
|
||||
-- 4) apt_sip_binding = 房间 ↔ 分机的生效区间(历史可追溯,ACTIVE 唯一);
|
||||
-- 5) 同一 gyid 下「一个 IP 只能有一个 ACTIVE contact」= 同一 IP 不得重复绑定;
|
||||
-- 用生成列 + 唯一索引在库层兜底,服务层再做一次可读的冲突前置校验。
|
||||
-- 幂等:建表 IF NOT EXISTS,补列/补索引走 information_schema 判断 + 动态 SQL。
|
||||
-- =============================================================================
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 1. endpoint 补列:话机 IP(与 contact 一致)与来源
|
||||
-- -----------------------------------------------------------------------------
|
||||
CALL apt_add_column_if_missing('apt_sip_endpoint', 'ip_address',
|
||||
"ip_address VARCHAR(64) NULL COMMENT '话机 IP(与 ACTIVE contact 的 ip_address 一致,解绑后清空)'");
|
||||
CALL apt_add_column_if_missing('apt_sip_endpoint', 'source',
|
||||
"source VARCHAR(20) NOT NULL DEFAULT 'ROOM' COMMENT 'ROOM=随房间自动创建 / MANUAL=手工登记'");
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 2. AOR 表(与 endpoint 1:1)
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS apt_sip_aor (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
gyid VARCHAR(32) NOT NULL,
|
||||
aor_id VARCHAR(64) NOT NULL COMMENT 'AOR 标识,如 AOR-<endpointId 后缀>',
|
||||
endpoint_id VARCHAR(64) NOT NULL COMMENT '所属分机(1:1)',
|
||||
max_contacts INT NOT NULL DEFAULT 1 COMMENT 'Asterisk max_contacts',
|
||||
remove_existing TINYINT NOT NULL DEFAULT 1 COMMENT 'Asterisk remove_existing:新注册顶掉旧 contact',
|
||||
default_expiration INT NOT NULL DEFAULT 3600 COMMENT 'contact 默认过期秒数',
|
||||
qualify_frequency INT NOT NULL DEFAULT 30 COMMENT 'OPTIONS 探测间隔秒',
|
||||
sync_state VARCHAR(20) NOT NULL DEFAULT 'PENDING' COMMENT '仅 PENDING/SYNCED/FAILED/DRIFT',
|
||||
config_version BIGINT NOT NULL DEFAULT 1,
|
||||
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_aor_gyid_id (gyid, aor_id),
|
||||
UNIQUE KEY uk_aor_gyid_endpoint (gyid, endpoint_id),
|
||||
KEY idx_aor_gyid_sync (gyid, sync_state),
|
||||
CONSTRAINT ck_aor_sync CHECK (sync_state IN ('PENDING','SYNCED','FAILED','DRIFT'))
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
|
||||
COMMENT='SIP AOR(与 endpoint 1:1,先库后 Asterisk)';
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 3. Contact 表(话机 IP 绑定事实)
|
||||
-- active_ip 生成列:仅 ACTIVE 且未删除时取值,配合唯一索引实现
|
||||
-- 「同 gyid 下一个 IP 只能有一个 ACTIVE contact」。
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS apt_sip_contact (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
gyid VARCHAR(32) NOT NULL,
|
||||
contact_id VARCHAR(64) NOT NULL,
|
||||
aor_id VARCHAR(64) NOT NULL,
|
||||
endpoint_id VARCHAR(64) NOT NULL,
|
||||
uri VARCHAR(255) NOT NULL COMMENT 'sip:<extension>@<ip>:<port>',
|
||||
ip_address VARCHAR(64) NOT NULL,
|
||||
port INT NOT NULL DEFAULT 5060,
|
||||
transport VARCHAR(8) NOT NULL DEFAULT 'udp',
|
||||
user_agent VARCHAR(128) NULL,
|
||||
source VARCHAR(20) NOT NULL DEFAULT 'STATIC' COMMENT 'STATIC=手工绑定 / DYNAMIC=注册上报',
|
||||
state VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' COMMENT 'ACTIVE/RELEASED/EXPIRED',
|
||||
last_seen_at DATETIME(3) NULL,
|
||||
released_at DATETIME(3) NULL,
|
||||
release_remark VARCHAR(128) NULL,
|
||||
active_ip VARCHAR(64) GENERATED ALWAYS AS
|
||||
(CASE WHEN state = 'ACTIVE' AND deleted = 0 THEN ip_address END) STORED,
|
||||
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_contact_gyid_id (gyid, contact_id),
|
||||
UNIQUE KEY uk_contact_gyid_active_ip (gyid, active_ip),
|
||||
KEY idx_contact_gyid_endpoint (gyid, endpoint_id, state),
|
||||
KEY idx_contact_gyid_aor (gyid, aor_id, state),
|
||||
CONSTRAINT ck_contact_state CHECK (state IN ('ACTIVE','RELEASED','EXPIRED'))
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
|
||||
COMMENT='SIP contact(话机 IP 绑定事实,保留历史;同 IP 唯一 ACTIVE)';
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 4. binding 兜底:一个 endpoint 同时只能有一条 ACTIVE 绑定
|
||||
-- -----------------------------------------------------------------------------
|
||||
SET @apt_binding_col = (SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'apt_sip_binding'
|
||||
AND COLUMN_NAME = 'active_endpoint');
|
||||
SET @apt_sql_binding_col = IF(@apt_binding_col = 0,
|
||||
'ALTER TABLE apt_sip_binding ADD COLUMN active_endpoint VARCHAR(64) GENERATED ALWAYS AS (CASE WHEN state = ''ACTIVE'' AND deleted = 0 THEN endpoint_id END) STORED',
|
||||
'SELECT 1');
|
||||
PREPARE stmt_binding_col FROM @apt_sql_binding_col;
|
||||
EXECUTE stmt_binding_col;
|
||||
DEALLOCATE PREPARE stmt_binding_col;
|
||||
|
||||
SET @apt_binding_idx = (SELECT COUNT(*) FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'apt_sip_binding'
|
||||
AND INDEX_NAME = 'uk_binding_gyid_active_ep');
|
||||
SET @apt_sql_binding_idx = IF(@apt_binding_idx = 0,
|
||||
'ALTER TABLE apt_sip_binding ADD UNIQUE KEY uk_binding_gyid_active_ep (gyid, active_endpoint)',
|
||||
'SELECT 1');
|
||||
PREPARE stmt_binding_idx FROM @apt_sql_binding_idx;
|
||||
EXECUTE stmt_binding_idx;
|
||||
DEALLOCATE PREPARE stmt_binding_idx;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 5. 校验
|
||||
-- -----------------------------------------------------------------------------
|
||||
SELECT '=== 32. SIP 表就绪(应 4:endpoint/binding/aor/contact)===' AS section;
|
||||
SELECT COUNT(*) AS sip_tables
|
||||
FROM information_schema.TABLES
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME IN ('apt_sip_endpoint','apt_sip_binding','apt_sip_aor','apt_sip_contact');
|
||||
|
||||
SELECT '=== 33. endpoint 补列(应 2)===' AS section;
|
||||
SELECT COUNT(*) AS endpoint_columns
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'apt_sip_endpoint'
|
||||
AND COLUMN_NAME IN ('ip_address','source');
|
||||
|
||||
SELECT '=== 34. 同 IP 唯一 ACTIVE 的库层兜底(应 1)===' 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_sip_contact'
|
||||
AND INDEX_NAME = 'uk_contact_gyid_active_ip'
|
||||
GROUP BY INDEX_NAME;
|
||||
|
||||
SELECT '=== 35. 一 endpoint 仅一条 ACTIVE 绑定(应 1)===' 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_sip_binding'
|
||||
AND INDEX_NAME = 'uk_binding_gyid_active_ep'
|
||||
GROUP BY INDEX_NAME;
|
||||
Reference in new issue
Block a user