Files
go-trustlog/api/highclient/client.go
ryan fb182adef4 feat: OpType重构为OpCode (int32) - 完整实现
🎯 核心变更:
- 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集成测试验证
- 分布式并发安全测试通过
2025-12-26 13:47:55 +08:00

157 lines
3.9 KiB
Go
Raw 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.
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
}