feat: support yutong mqtt tls config
This commit is contained in:
@@ -2,9 +2,13 @@ package gateway
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -17,16 +21,23 @@ import (
|
||||
)
|
||||
|
||||
type MQTTClientConfig struct {
|
||||
EndpointName string
|
||||
Broker string
|
||||
ClientID string
|
||||
Username string
|
||||
Password string
|
||||
Topics []string
|
||||
QoS byte
|
||||
Sink eventbus.Sink
|
||||
Resolver identity.Resolver
|
||||
Logger *slog.Logger
|
||||
EndpointName string
|
||||
Broker string
|
||||
ClientID string
|
||||
Username string
|
||||
Password string
|
||||
Topics []string
|
||||
QoS byte
|
||||
CleanSession bool
|
||||
KeepAlive time.Duration
|
||||
ConnectTimeout time.Duration
|
||||
TLSCACertPath string
|
||||
TLSClientCertPath string
|
||||
TLSClientKeyPath string
|
||||
TLSHostnameVerification bool
|
||||
Sink eventbus.Sink
|
||||
Resolver identity.Resolver
|
||||
Logger *slog.Logger
|
||||
}
|
||||
|
||||
type MQTTClient struct {
|
||||
@@ -60,17 +71,45 @@ func NewMQTTClient(cfg MQTTClientConfig) (*MQTTClient, error) {
|
||||
}
|
||||
|
||||
func (c *MQTTClient) Start(ctx context.Context) error {
|
||||
opts, err := c.buildOptions(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.client = mqtt.NewClient(opts)
|
||||
token := c.client.Connect()
|
||||
if token.Wait() && token.Error() != nil {
|
||||
return token.Error()
|
||||
}
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
if c.client != nil && c.client.IsConnected() {
|
||||
c.client.Disconnect(250)
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *MQTTClient) buildOptions(ctx context.Context) (*mqtt.ClientOptions, error) {
|
||||
keepAlive := c.cfg.KeepAlive
|
||||
if keepAlive <= 0 {
|
||||
keepAlive = 20 * time.Second
|
||||
}
|
||||
connectTimeout := c.cfg.ConnectTimeout
|
||||
if connectTimeout <= 0 {
|
||||
connectTimeout = 10 * time.Second
|
||||
}
|
||||
opts := mqtt.NewClientOptions().
|
||||
AddBroker(c.cfg.Broker).
|
||||
SetClientID(c.cfg.ClientID).
|
||||
SetUsername(c.cfg.Username).
|
||||
SetPassword(c.cfg.Password).
|
||||
SetCleanSession(false).
|
||||
SetCleanSession(c.cfg.CleanSession).
|
||||
SetAutoReconnect(true).
|
||||
SetConnectRetry(true).
|
||||
SetConnectRetryInterval(5 * time.Second).
|
||||
SetKeepAlive(20 * time.Second).
|
||||
SetConnectTimeout(10 * time.Second)
|
||||
SetKeepAlive(keepAlive).
|
||||
SetConnectTimeout(connectTimeout)
|
||||
|
||||
opts.SetDefaultPublishHandler(func(_ mqtt.Client, message mqtt.Message) {
|
||||
c.handleMessage(ctx, message.Topic(), message.Payload())
|
||||
@@ -89,18 +128,49 @@ func (c *MQTTClient) Start(ctx context.Context) error {
|
||||
c.cfg.Logger.Warn("mqtt connection lost", "broker", c.cfg.Broker, "error", err)
|
||||
}
|
||||
|
||||
c.client = mqtt.NewClient(opts)
|
||||
token := c.client.Connect()
|
||||
if token.Wait() && token.Error() != nil {
|
||||
return token.Error()
|
||||
tlsConfig, err := c.buildTLSConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
if c.client != nil && c.client.IsConnected() {
|
||||
c.client.Disconnect(250)
|
||||
if tlsConfig != nil {
|
||||
opts.SetTLSConfig(tlsConfig)
|
||||
}
|
||||
return opts, nil
|
||||
}
|
||||
|
||||
func (c *MQTTClient) buildTLSConfig() (*tls.Config, error) {
|
||||
caPath := strings.TrimSpace(c.cfg.TLSCACertPath)
|
||||
certPath := strings.TrimSpace(c.cfg.TLSClientCertPath)
|
||||
keyPath := strings.TrimSpace(c.cfg.TLSClientKeyPath)
|
||||
if caPath == "" && certPath == "" && keyPath == "" {
|
||||
return nil, nil
|
||||
}
|
||||
config := &tls.Config{
|
||||
MinVersion: tls.VersionTLS12,
|
||||
InsecureSkipVerify: !c.cfg.TLSHostnameVerification,
|
||||
}
|
||||
if caPath != "" {
|
||||
caPEM, err := os.ReadFile(caPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read mqtt ca certificate: %w", err)
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
roots := x509.NewCertPool()
|
||||
if !roots.AppendCertsFromPEM(caPEM) {
|
||||
return nil, fmt.Errorf("parse mqtt ca certificate %s", caPath)
|
||||
}
|
||||
config.RootCAs = roots
|
||||
}
|
||||
if certPath != "" || keyPath != "" {
|
||||
if certPath == "" || keyPath == "" {
|
||||
return nil, errors.New("mqtt client certificate and key must be configured together")
|
||||
}
|
||||
cert, err := tls.LoadX509KeyPair(certPath, keyPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load mqtt client certificate: %w", err)
|
||||
}
|
||||
config.Certificates = []tls.Certificate{cert}
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func (c *MQTTClient) handleMessage(ctx context.Context, topic string, payload []byte) {
|
||||
|
||||
Reference in New Issue
Block a user