2025-12-23 18:59:43 +08:00
|
|
|
|
package persistence
|
|
|
|
|
|
|
|
|
|
|
|
// TrustlogStatus 存证状态枚举
|
|
|
|
|
|
type TrustlogStatus string
|
|
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
|
// StatusNotTrustlogged 未存证
|
|
|
|
|
|
StatusNotTrustlogged TrustlogStatus = "NOT_TRUSTLOGGED"
|
|
|
|
|
|
// StatusTrustlogged 已存证
|
|
|
|
|
|
StatusTrustlogged TrustlogStatus = "TRUSTLOGGED"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// RetryStatus 重试状态枚举
|
|
|
|
|
|
type RetryStatus string
|
|
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
|
// RetryStatusPending 待重试
|
|
|
|
|
|
RetryStatusPending RetryStatus = "PENDING"
|
|
|
|
|
|
// RetryStatusRetrying 重试中
|
|
|
|
|
|
RetryStatusRetrying RetryStatus = "RETRYING"
|
|
|
|
|
|
// RetryStatusDeadLetter 死信(超过最大重试次数)
|
|
|
|
|
|
RetryStatusDeadLetter RetryStatus = "DEAD_LETTER"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// SQL DDL 语句 - 使用通用 SQL 标准,避免方言
|
|
|
|
|
|
|
|
|
|
|
|
// OperationTableDDL 操作记录表的 DDL(通用 SQL)
|
|
|
|
|
|
const OperationTableDDL = `
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS operation (
|
|
|
|
|
|
op_id VARCHAR(32) NOT NULL PRIMARY KEY,
|
|
|
|
|
|
op_actor VARCHAR(64),
|
|
|
|
|
|
doid VARCHAR(512),
|
|
|
|
|
|
producer_id VARCHAR(32),
|
|
|
|
|
|
request_body_hash VARCHAR(128),
|
|
|
|
|
|
response_body_hash VARCHAR(128),
|
|
|
|
|
|
sign VARCHAR(512),
|
|
|
|
|
|
op_source VARCHAR(10),
|
2025-12-26 13:47:55 +08:00
|
|
|
|
op_code INTEGER,
|
2025-12-23 18:59:43 +08:00
|
|
|
|
do_prefix VARCHAR(128),
|
|
|
|
|
|
do_repository VARCHAR(64),
|
|
|
|
|
|
client_ip VARCHAR(32),
|
|
|
|
|
|
server_ip VARCHAR(32),
|
|
|
|
|
|
trustlog_status VARCHAR(32),
|
|
|
|
|
|
timestamp TIMESTAMP,
|
|
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_operation_timestamp ON operation(timestamp);
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_operation_status ON operation(trustlog_status);
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_operation_doid ON operation(doid);
|
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
|
|
// CursorTableDDL 游标表的 DDL(用于跟踪已处理的操作)
|
|
|
|
|
|
const CursorTableDDL = `
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS trustlog_cursor (
|
|
|
|
|
|
cursor_key VARCHAR(64) NOT NULL PRIMARY KEY,
|
|
|
|
|
|
cursor_value VARCHAR(128) NOT NULL,
|
|
|
|
|
|
last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_cursor_updated_at ON trustlog_cursor(last_updated_at);
|
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
|
|
// RetryTableDDL 重试表的 DDL
|
|
|
|
|
|
const RetryTableDDL = `
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS trustlog_retry (
|
|
|
|
|
|
op_id VARCHAR(32) NOT NULL PRIMARY KEY,
|
|
|
|
|
|
retry_count INTEGER DEFAULT 0,
|
|
|
|
|
|
retry_status VARCHAR(32) DEFAULT 'PENDING',
|
|
|
|
|
|
last_retry_at TIMESTAMP,
|
|
|
|
|
|
next_retry_at TIMESTAMP,
|
|
|
|
|
|
error_message TEXT,
|
|
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_retry_status ON trustlog_retry(retry_status);
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_retry_next_retry_at ON trustlog_retry(next_retry_at);
|
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
|
|
// GetDialectDDL 根据数据库类型返回适配的 DDL
|
|
|
|
|
|
// 这个函数处理不同数据库的差异,但尽量使用通用 SQL
|
|
|
|
|
|
func GetDialectDDL(driverName string) (string, string, string, error) {
|
|
|
|
|
|
switch driverName {
|
|
|
|
|
|
case "postgres":
|
|
|
|
|
|
return getPostgresDDL(), getCursorDDLPostgres(), getRetryDDLPostgres(), nil
|
|
|
|
|
|
case "mysql":
|
|
|
|
|
|
return getMySQLDDL(), getCursorDDLMySQL(), getRetryDDLMySQL(), nil
|
|
|
|
|
|
case "sqlite3", "sqlite":
|
|
|
|
|
|
return getSQLiteDDL(), getCursorDDLSQLite(), getRetryDDLSQLite(), nil
|
|
|
|
|
|
default:
|
|
|
|
|
|
// 默认使用通用 SQL
|
|
|
|
|
|
return OperationTableDDL, CursorTableDDL, RetryTableDDL, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// PostgreSQL 特定 DDL
|
|
|
|
|
|
func getPostgresDDL() string {
|
|
|
|
|
|
return `
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS operation (
|
|
|
|
|
|
op_id VARCHAR(32) NOT NULL PRIMARY KEY,
|
|
|
|
|
|
op_actor VARCHAR(64),
|
|
|
|
|
|
doid VARCHAR(512),
|
|
|
|
|
|
producer_id VARCHAR(32),
|
|
|
|
|
|
request_body_hash VARCHAR(128),
|
|
|
|
|
|
response_body_hash VARCHAR(128),
|
|
|
|
|
|
sign VARCHAR(512),
|
|
|
|
|
|
op_source VARCHAR(10),
|
2025-12-26 13:47:55 +08:00
|
|
|
|
op_code INTEGER,
|
2025-12-23 18:59:43 +08:00
|
|
|
|
do_prefix VARCHAR(128),
|
|
|
|
|
|
do_repository VARCHAR(64),
|
|
|
|
|
|
client_ip VARCHAR(32),
|
|
|
|
|
|
server_ip VARCHAR(32),
|
|
|
|
|
|
trustlog_status VARCHAR(32),
|
|
|
|
|
|
timestamp TIMESTAMP,
|
|
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_operation_timestamp ON operation(timestamp);
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_operation_status ON operation(trustlog_status);
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_operation_doid ON operation(doid);
|
|
|
|
|
|
`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func getCursorDDLPostgres() string {
|
|
|
|
|
|
return `
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS trustlog_cursor (
|
|
|
|
|
|
cursor_key VARCHAR(64) NOT NULL PRIMARY KEY,
|
|
|
|
|
|
cursor_value VARCHAR(128) NOT NULL,
|
|
|
|
|
|
last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_cursor_updated_at ON trustlog_cursor(last_updated_at);
|
|
|
|
|
|
`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func getRetryDDLPostgres() string {
|
|
|
|
|
|
return `
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS trustlog_retry (
|
|
|
|
|
|
op_id VARCHAR(32) NOT NULL PRIMARY KEY,
|
|
|
|
|
|
retry_count INTEGER DEFAULT 0,
|
|
|
|
|
|
retry_status VARCHAR(32) DEFAULT 'PENDING',
|
|
|
|
|
|
last_retry_at TIMESTAMP,
|
|
|
|
|
|
next_retry_at TIMESTAMP,
|
|
|
|
|
|
error_message TEXT,
|
|
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_retry_status ON trustlog_retry(retry_status);
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_retry_next_retry_at ON trustlog_retry(next_retry_at);
|
|
|
|
|
|
`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// MySQL 特定 DDL
|
|
|
|
|
|
func getMySQLDDL() string {
|
|
|
|
|
|
return `
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS operation (
|
|
|
|
|
|
op_id VARCHAR(32) NOT NULL PRIMARY KEY,
|
|
|
|
|
|
op_actor VARCHAR(64),
|
|
|
|
|
|
doid VARCHAR(512),
|
|
|
|
|
|
producer_id VARCHAR(32),
|
|
|
|
|
|
request_body_hash VARCHAR(128),
|
|
|
|
|
|
response_body_hash VARCHAR(128),
|
|
|
|
|
|
sign VARCHAR(512),
|
|
|
|
|
|
op_source VARCHAR(10),
|
2025-12-26 13:47:55 +08:00
|
|
|
|
op_code INT,
|
2025-12-23 18:59:43 +08:00
|
|
|
|
do_prefix VARCHAR(128),
|
|
|
|
|
|
do_repository VARCHAR(64),
|
|
|
|
|
|
client_ip VARCHAR(32),
|
|
|
|
|
|
server_ip VARCHAR(32),
|
|
|
|
|
|
trustlog_status VARCHAR(32),
|
|
|
|
|
|
timestamp DATETIME,
|
|
|
|
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
|
INDEX idx_operation_timestamp (timestamp),
|
|
|
|
|
|
INDEX idx_operation_status (trustlog_status),
|
|
|
|
|
|
INDEX idx_operation_doid (doid(255))
|
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
|
|
`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func getCursorDDLMySQL() string {
|
|
|
|
|
|
return `
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS trustlog_cursor (
|
|
|
|
|
|
cursor_key VARCHAR(64) NOT NULL PRIMARY KEY,
|
|
|
|
|
|
cursor_value VARCHAR(128) NOT NULL,
|
|
|
|
|
|
last_updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
|
|
|
|
INDEX idx_cursor_updated_at (last_updated_at)
|
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
|
|
`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func getRetryDDLMySQL() string {
|
|
|
|
|
|
return `
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS trustlog_retry (
|
|
|
|
|
|
op_id VARCHAR(32) NOT NULL PRIMARY KEY,
|
|
|
|
|
|
retry_count INT DEFAULT 0,
|
|
|
|
|
|
retry_status VARCHAR(32) DEFAULT 'PENDING',
|
|
|
|
|
|
last_retry_at DATETIME,
|
|
|
|
|
|
next_retry_at DATETIME,
|
|
|
|
|
|
error_message TEXT,
|
|
|
|
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
|
|
|
|
INDEX idx_retry_status (retry_status),
|
|
|
|
|
|
INDEX idx_retry_next_retry_at (next_retry_at)
|
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
|
|
`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// SQLite 特定 DDL
|
|
|
|
|
|
func getSQLiteDDL() string {
|
|
|
|
|
|
return `
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS operation (
|
|
|
|
|
|
op_id TEXT NOT NULL PRIMARY KEY,
|
|
|
|
|
|
op_actor TEXT,
|
|
|
|
|
|
doid TEXT,
|
|
|
|
|
|
producer_id TEXT,
|
|
|
|
|
|
request_body_hash TEXT,
|
|
|
|
|
|
response_body_hash TEXT,
|
|
|
|
|
|
sign TEXT,
|
|
|
|
|
|
op_source TEXT,
|
2025-12-26 13:47:55 +08:00
|
|
|
|
op_code INTEGER,
|
2025-12-23 18:59:43 +08:00
|
|
|
|
do_prefix TEXT,
|
|
|
|
|
|
do_repository TEXT,
|
|
|
|
|
|
client_ip TEXT,
|
|
|
|
|
|
server_ip TEXT,
|
|
|
|
|
|
trustlog_status TEXT,
|
|
|
|
|
|
timestamp DATETIME,
|
|
|
|
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_operation_timestamp ON operation(timestamp);
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_operation_status ON operation(trustlog_status);
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_operation_doid ON operation(doid);
|
|
|
|
|
|
`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func getCursorDDLSQLite() string {
|
|
|
|
|
|
return `
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS trustlog_cursor (
|
|
|
|
|
|
cursor_key TEXT NOT NULL PRIMARY KEY,
|
|
|
|
|
|
cursor_value TEXT NOT NULL,
|
|
|
|
|
|
last_updated_at TEXT DEFAULT (datetime('now'))
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_cursor_updated_at ON trustlog_cursor(last_updated_at);
|
|
|
|
|
|
`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func getRetryDDLSQLite() string {
|
|
|
|
|
|
return `
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS trustlog_retry (
|
|
|
|
|
|
op_id TEXT NOT NULL PRIMARY KEY,
|
|
|
|
|
|
retry_count INTEGER DEFAULT 0,
|
|
|
|
|
|
retry_status TEXT DEFAULT 'PENDING',
|
|
|
|
|
|
last_retry_at DATETIME,
|
|
|
|
|
|
next_retry_at DATETIME,
|
|
|
|
|
|
error_message TEXT,
|
|
|
|
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_retry_status ON trustlog_retry(retry_status);
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_retry_next_retry_at ON trustlog_retry(next_retry_at);
|
|
|
|
|
|
`
|
|
|
|
|
|
}
|