Files
go-trustlog/api/adapter/publisher.go
ryan d313449c5c 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等)预留空间。
2025-12-22 13:37:57 +08:00

121 lines
3.2 KiB
Go

package adapter
import (
"context"
"errors"
"github.com/ThreeDotsLabs/watermill/message"
"github.com/apache/pulsar-client-go/pulsar"
"go.yandata.net/iod/iod/trustlog-sdk/api/logger"
logger2 "go.yandata.net/iod/iod/trustlog-sdk/internal/logger"
)
const (
OperationTopic = "persistent://public/default/operation"
RecordTopic = "persistent://public/default/record"
)
// PublisherConfig is the configuration to create a publisher.
type PublisherConfig struct {
// URL is the Pulsar URL.
URL string
// TLSTrustCertsFilePath is the path to the CA certificate file for verifying the server certificate.
// If empty, TLS verification will be disabled.
TLSTrustCertsFilePath string
// TLSCertificateFilePath is the path to the client certificate file for mTLS authentication.
// If empty, mTLS authentication will be disabled.
TLSCertificateFilePath string
// TLSKeyFilePath is the path to the client private key file for mTLS authentication.
// If empty, mTLS authentication will be disabled.
TLSKeyFilePath string
// TLSAllowInsecureConnection allows insecure TLS connections (not recommended for production).
TLSAllowInsecureConnection bool
}
// Publisher provides the pulsar implementation for watermill publish operations.
type Publisher struct {
conn pulsar.Client
logger logger.Logger
pubs map[string]pulsar.Producer
}
// NewPublisher creates a new Publisher.
func NewPublisher(config PublisherConfig, adapter logger.Logger) (*Publisher, error) {
clientOptions := pulsar.ClientOptions{
URL: config.URL,
Logger: logger2.NewPulsarLoggerAdapter(adapter),
}
// Configure TLS/mTLS
if err := configureTLSForClient(&clientOptions, config, adapter); err != nil {
return nil, errors.Join(err, errors.New("failed to configure TLS"))
}
conn, err := pulsar.NewClient(clientOptions)
if err != nil {
return nil, errors.Join(err, errors.New("cannot connect to pulsar"))
}
return NewPublisherWithPulsarClient(conn, adapter)
}
// NewPublisherWithPulsarClient creates a new Publisher with the provided pulsar connection.
func NewPublisherWithPulsarClient(conn pulsar.Client, logger logger.Logger) (*Publisher, error) {
return &Publisher{
conn: conn,
pubs: make(map[string]pulsar.Producer),
logger: logger,
}, nil
}
// Publish publishes message to Pulsar.
//
// Publish will not return until an ack has been received from Pulsar.
// When one of messages delivery fails - function is interrupted.
func (p *Publisher) Publish(topic string, messages ...*message.Message) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
producer, found := p.pubs[topic]
if !found {
pr, err := p.conn.CreateProducer(pulsar.ProducerOptions{Topic: topic})
if err != nil {
return err
}
producer = pr
p.pubs[topic] = producer
}
for _, msg := range messages {
// 跳过 nil 消息
if msg == nil {
continue
}
p.logger.DebugContext(ctx, "Sending message", "key", msg.UUID, "topic", topic)
_, err := producer.Send(ctx, &pulsar.ProducerMessage{
Key: msg.UUID,
Payload: msg.Payload,
})
if err != nil {
return err
}
}
return nil
}
// Close closes the publisher and the underlying connection.
func (p *Publisher) Close() error {
for _, pub := range p.pubs {
pub.Close()
}
p.conn.Close()
return nil
}