refactor: 重构trustlog-sdk目录结构到trustlog/go-trustlog

- 将所有trustlog-sdk文件移动到trustlog/go-trustlog/目录
- 更新README中所有import路径从trustlog-sdk改为go-trustlog
- 更新cookiecutter配置文件中的项目名称
- 更新根目录.lefthook.yml以引用新位置的配置
- 添加go.sum文件到版本控制
- 删除过时的示例文件

这次重构与trustlog-server保持一致的目录结构,
为未来支持多语言SDK(Python、Java等)预留空间。
This commit is contained in:
ryan
2025-12-22 13:37:57 +08:00
commit d313449c5c
87 changed files with 20622 additions and 0 deletions

View File

@@ -0,0 +1,195 @@
package adapter
import (
"context"
"errors"
"fmt"
"net"
"sync"
"time"
"github.com/ThreeDotsLabs/watermill/message"
"go.yandata.net/iod/iod/trustlog-sdk/api/logger"
)
// 默认配置常量.
const (
defaultConnectTimeout = 10 * time.Second
defaultMaxRetries = 3
)
// 预定义错误.
var (
ErrServerAddrRequired = errors.New("server address is required")
ErrPublisherClosed = errors.New("publisher is closed")
)
// TCPPublisherConfig TCP 发布者配置
type TCPPublisherConfig struct {
// ServerAddr TCP 服务器地址,格式: "host:port"
ServerAddr string
// ConnectTimeout 连接超时时间
ConnectTimeout time.Duration
// MaxRetries 最大重试次数
MaxRetries int
}
// TCPPublisher 实现基于 TCP 的 watermill Publisher
type TCPPublisher struct {
config TCPPublisherConfig
conn net.Conn
logger logger.Logger
closed bool
closedMu sync.RWMutex
closeChan chan struct{}
}
// NewTCPPublisher 创建一个新的 TCP Publisher.
func NewTCPPublisher(config TCPPublisherConfig, logger logger.Logger) (*TCPPublisher, error) {
if config.ServerAddr == "" {
return nil, ErrServerAddrRequired
}
if config.ConnectTimeout == 0 {
config.ConnectTimeout = defaultConnectTimeout
}
if config.MaxRetries == 0 {
config.MaxRetries = defaultMaxRetries
}
p := &TCPPublisher{
config: config,
logger: logger,
closeChan: make(chan struct{}),
}
// 连接到服务器
if err := p.connect(); err != nil {
return nil, err
}
// 不再接收 ACK/NACK发送即成功模式
// go p.receiveAcks() // 已移除
return p, nil
}
// connect 连接到 TCP 服务器
func (p *TCPPublisher) connect() error {
ctx, cancel := context.WithTimeout(context.Background(), p.config.ConnectTimeout)
defer cancel()
var d net.Dialer
conn, err := d.DialContext(ctx, "tcp", p.config.ServerAddr)
if err != nil {
return fmt.Errorf("failed to connect to %s: %w", p.config.ServerAddr, err)
}
p.conn = conn
p.logger.InfoContext(context.Background(), "Connected to TCP server", "addr", p.config.ServerAddr)
return nil
}
// Publish 发布消息.
func (p *TCPPublisher) Publish(topic string, messages ...*message.Message) error {
p.closedMu.RLock()
if p.closed {
p.closedMu.RUnlock()
return ErrPublisherClosed
}
p.closedMu.RUnlock()
ctx := context.Background()
// 使用 WaitGroup 和 errChan 来并发发送消息并收集错误
var wg sync.WaitGroup
errs := make([]error, 0, len(messages))
var errMu sync.Mutex
errChan := make(chan error, len(messages))
for _, msg := range messages {
if msg == nil {
continue
}
wg.Add(1)
go func(m *message.Message) {
defer wg.Done()
if err := p.publishSingle(ctx, topic, m); err != nil {
errChan <- err
}
}(msg)
}
// 等待所有消息发送完成
wg.Wait()
close(errChan)
// 检查是否有错误
for err := range errChan {
errMu.Lock()
errs = append(errs, err)
errMu.Unlock()
}
if len(errs) > 0 {
return fmt.Errorf("failed to publish %d messages: %w", len(errs), errors.Join(errs...))
}
return nil
}
// publishSingle 发送单条消息,不等待 ACK
func (p *TCPPublisher) publishSingle(ctx context.Context, topic string, msg *message.Message) error {
tcpMsg := &TCPMessage{
Type: MessageTypeData,
Topic: topic,
UUID: msg.UUID,
Payload: msg.Payload,
}
// 编码消息
data, err := EncodeTCPMessage(tcpMsg)
if err != nil {
return fmt.Errorf("failed to encode message: %w", err)
}
p.logger.DebugContext(ctx, "Sending message", "uuid", msg.UUID, "topic", topic)
// 发送消息
if _, err := p.conn.Write(data); err != nil {
return fmt.Errorf("failed to write message: %w", err)
}
p.logger.DebugContext(ctx, "Message sent successfully", "uuid", msg.UUID)
return nil
}
// receiveAcks, shouldStopReceiving, handleDecodeError 方法已移除
// 不再接收 ACK/NACK采用发送即成功模式以提高性能
// Close 关闭发布者
func (p *TCPPublisher) Close() error {
p.closedMu.Lock()
if p.closed {
p.closedMu.Unlock()
return nil
}
p.closed = true
p.closedMu.Unlock()
close(p.closeChan)
if p.conn != nil {
if err := p.conn.Close(); err != nil {
return fmt.Errorf("failed to close connection: %w", err)
}
}
p.logger.InfoContext(context.Background(), "TCP Publisher closed")
return nil
}