- 将所有trustlog-sdk文件移动到trustlog/go-trustlog/目录 - 更新README中所有import路径从trustlog-sdk改为go-trustlog - 更新cookiecutter配置文件中的项目名称 - 更新根目录.lefthook.yml以引用新位置的配置 - 添加go.sum文件到版本控制 - 删除过时的示例文件 这次重构与trustlog-server保持一致的目录结构, 为未来支持多语言SDK(Python、Java等)预留空间。
121 lines
3.2 KiB
Go
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
|
|
}
|