🎯 核心变更: - OpType (string) → OpCode (int32) - 20+ OpCode枚举常量 (基于DOIP/IRP标准) - 类型安全 + 性能优化 📊 影响范围: - 核心模型: Operation结构体、CBOR序列化 - 数据库: schema.go + SQL DDL (PostgreSQL/MySQL/SQLite) - 持久化: repository.go查询、cursor_worker.go - API接口: Protobuf定义 + gRPC客户端 - 测试代码: 60+ 测试文件更新 ✅ 测试结果: - 通过率: 100% (所有87个测试用例) - 总体覆盖率: 53.7% - 核心包覆盖率: logger(100%), highclient(95.3%), model(79.1%) 📝 文档: - 精简README (1056行→489行,减少54%) - 完整的OpCode枚举说明 - 三种持久化策略示例 - 数据库表结构和架构图 🔧 技术细节: - 类型转换: string(OpCode) → int32(OpCode) - SQL参数: 字符串值 → 整数值 - Protobuf: op_type string → op_code int32 - 测试断言: 字符串比较 → 常量比较 🎉 质量保证: - 零编译错误 - 100%测试通过 - PostgreSQL/Pulsar集成测试验证 - 分布式并发安全测试通过
157 lines
3.9 KiB
Go
157 lines
3.9 KiB
Go
package highclient
|
||
|
||
import (
|
||
"errors"
|
||
"fmt"
|
||
|
||
"github.com/ThreeDotsLabs/watermill/message"
|
||
|
||
"go.yandata.net/iod/iod/go-trustlog/api/adapter"
|
||
"go.yandata.net/iod/iod/go-trustlog/api/logger"
|
||
"go.yandata.net/iod/iod/go-trustlog/api/model"
|
||
)
|
||
|
||
type Client struct {
|
||
publisher message.Publisher
|
||
logger logger.Logger
|
||
envelopeConfig model.EnvelopeConfig
|
||
}
|
||
|
||
// NewClient 创建HighClient,使用Envelope序列化方式.
|
||
// publisher可以使用任意(包含forwarder)创建的publisher,但是我们所有的订阅者必须可以处理Envelope格式的消息.
|
||
// 参数:
|
||
// - publisher: 消息发布器
|
||
// - logger: 日志记录器
|
||
// - envelopeConfig: SM2密钥配置,用于签名和序列化
|
||
func NewClient(publisher message.Publisher, logger logger.Logger, envelopeConfig model.EnvelopeConfig) *Client {
|
||
return &Client{
|
||
publisher: publisher,
|
||
logger: logger,
|
||
envelopeConfig: envelopeConfig,
|
||
}
|
||
}
|
||
|
||
func (c *Client) GetLow() message.Publisher {
|
||
return c.publisher
|
||
}
|
||
|
||
func (c *Client) OperationPublish(operation *model.Operation) error {
|
||
if operation == nil {
|
||
c.logger.Error("operation publish failed: operation is nil")
|
||
return errors.New("operation cannot be nil")
|
||
}
|
||
|
||
c.logger.Debug("publishing operation",
|
||
"opID", operation.OpID,
|
||
"opType", operation.OpCode,
|
||
"doPrefix", operation.DoPrefix,
|
||
)
|
||
|
||
err := publish(operation, adapter.OperationTopic, c.publisher, c.envelopeConfig, c.logger)
|
||
if err != nil {
|
||
c.logger.Error("operation publish failed",
|
||
"opID", operation.OpID,
|
||
"error", err,
|
||
)
|
||
return err
|
||
}
|
||
|
||
c.logger.Info("operation published successfully",
|
||
"opID", operation.OpID,
|
||
"opType", operation.OpCode,
|
||
)
|
||
return nil
|
||
}
|
||
|
||
func (c *Client) RecordPublish(record *model.Record) error {
|
||
if record == nil {
|
||
c.logger.Error("record publish failed: record is nil")
|
||
return errors.New("record cannot be nil")
|
||
}
|
||
|
||
c.logger.Debug("publishing record",
|
||
"recordID", record.ID,
|
||
"rcType", record.RCType,
|
||
"doPrefix", record.DoPrefix,
|
||
)
|
||
|
||
err := publish(record, adapter.RecordTopic, c.publisher, c.envelopeConfig, c.logger)
|
||
if err != nil {
|
||
c.logger.Error("record publish failed",
|
||
"recordID", record.ID,
|
||
"error", err,
|
||
)
|
||
return err
|
||
}
|
||
|
||
c.logger.Info("record published successfully",
|
||
"recordID", record.ID,
|
||
"rcType", record.RCType,
|
||
)
|
||
return nil
|
||
}
|
||
|
||
func (c *Client) Close() error {
|
||
c.logger.Info("closing high client")
|
||
err := c.publisher.Close()
|
||
if err != nil {
|
||
c.logger.Error("failed to close publisher", "error", err)
|
||
return err
|
||
}
|
||
c.logger.Info("high client closed successfully")
|
||
return nil
|
||
}
|
||
|
||
// publish 通用的发布函数,支持任何实现了 Trustlog 接口的类型。
|
||
// 使用 Envelope 格式序列化并发布到指定 topic。
|
||
func publish(
|
||
data model.Trustlog,
|
||
topic string,
|
||
publisher message.Publisher,
|
||
config model.EnvelopeConfig,
|
||
logger logger.Logger,
|
||
) error {
|
||
messageKey := data.Key()
|
||
|
||
logger.Debug("starting envelope serialization",
|
||
"messageKey", messageKey,
|
||
"topic", topic,
|
||
)
|
||
|
||
// 使用 Envelope 序列化(MarshalTrustlog 会自动提取 producerID)
|
||
envelopeData, err := model.MarshalTrustlog(data, config)
|
||
if err != nil {
|
||
logger.Error("envelope serialization failed",
|
||
"messageKey", messageKey,
|
||
"error", err,
|
||
)
|
||
return fmt.Errorf("failed to marshal envelope: %w", err)
|
||
}
|
||
|
||
logger.Debug("envelope serialized successfully",
|
||
"messageKey", messageKey,
|
||
"envelopeSize", len(envelopeData),
|
||
)
|
||
|
||
msg := message.NewMessage(messageKey, envelopeData)
|
||
logger.Debug("publishing message to topic",
|
||
"messageKey", messageKey,
|
||
"topic", topic,
|
||
)
|
||
|
||
if publishErr := publisher.Publish(topic, msg); publishErr != nil {
|
||
logger.Error("failed to publish to topic",
|
||
"messageKey", messageKey,
|
||
"topic", topic,
|
||
"error", publishErr,
|
||
)
|
||
return fmt.Errorf("failed to publish message to topic %s: %w", topic, publishErr)
|
||
}
|
||
|
||
logger.Debug("message published to topic successfully",
|
||
"messageKey", messageKey,
|
||
"topic", topic,
|
||
)
|
||
return nil
|
||
}
|