add mqtt listenner

This commit is contained in:
Loïc 2023-02-03 13:00:35 +01:00
parent 2624897efe
commit db518b5c19
4 changed files with 133 additions and 0 deletions

93
server/mqtt.go Normal file
View file

@ -0,0 +1,93 @@
package server
import (
"fmt"
"bytes"
mqtt "github.com/eclipse/paho.mqtt.golang"
"heckel.io/ntfy/log"
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
)
type mqttBackend struct {
config *Config
handler func(http.ResponseWriter, *http.Request)
client mqtt.Client
}
type mqttMessage struct {
Topic string `json:"topic"`
Title string `json:"title"`
Message string `json:"message"`
Priority string `json:"priority"`
Tags string `json:"tags"`
Actions string `json:"actions"`
}
func newMqttBackend(conf *Config, handler func(http.ResponseWriter, *http.Request)) *mqttBackend {
return &mqttBackend{
config: conf,
handler: handler,
}
}
func (b *mqttBackend) Connect() () {
opts := mqtt.NewClientOptions()
opts.AddBroker(fmt.Sprintf("tcp://%s:%d", b.config.MqttServer, b.config.MqttPort))
opts.SetClientID("ntfy")
opts.SetUsername(b.config.MqttUsername)
opts.SetPassword(b.config.MqttPassword)
log.Info("[mqtt] Connect to mqtt server %s:%d", b.config.MqttServer, b.config.MqttPort)
client := mqtt.NewClient(opts)
if token := client.Connect(); token.Wait() && token.Error() != nil {
log.Debug("[mqtt] Can not connect")
return
}
b.client = client
return
}
func (b *mqttBackend) Subscribe() () {
b.client.Subscribe(b.config.MqttTopic+"/message", 0, func(client mqtt.Client, msg mqtt.Message) {
log.Debug("[mqtt] Received message [%s] %s ", msg.Topic(), string(msg.Payload()))
var m mqttMessage
if err := json.NewDecoder(bytes.NewReader(msg.Payload())).Decode(&m); err != nil {
log.Info("[mqtt] not a valide json")
return
}
if !topicRegex.MatchString(m.Topic) {
log.Info("[mqtt] not a valide topic")
return
}
if m.Message == "" {
m.Message = emptyMessageBody
}
url := fmt.Sprintf("%s/%s", b.config.BaseURL, m.Topic)
req, err := http.NewRequest("POST", url, strings.NewReader(m.Message))
req.RequestURI = "/" + m.Topic
req.RemoteAddr = "127.0.0.1"
if err != nil {
return
}
if m.Title != "" {
req.Header.Set("Title", m.Title)
}
if m.Priority != "" {
req.Header.Set("Priority",m.Priority)
}
if m.Tags != "" {
req.Header.Set("Tags",m.Tags)
}
if m.Actions != "" {
req.Header.Set("Actions",m.Actions)
}
rr := httptest.NewRecorder()
b.handler(rr, req)
if rr.Code != http.StatusOK {
return
}
})
log.Info("[mqtt] Subscribed to topic %s/message", b.config.MqttTopic)
}

View file

@ -41,6 +41,7 @@ type Server struct {
unixListener net.Listener
smtpServer *smtp.Server
smtpServerBackend *smtpBackend
mqttServerBackend *mqttBackend
smtpSender mailer
topics map[string]*topic
visitors map[netip.Addr]*visitor
@ -228,6 +229,11 @@ func (s *Server) Run() error {
errChan <- s.runSMTPServer()
}()
}
if s.config.MqttServer != "" {
go func() {
s.runMqttServer()
}()
}
s.mu.Unlock()
go s.runManager()
go s.runDelayedSender()
@ -1221,6 +1227,13 @@ func (s *Server) runSMTPServer() error {
return s.smtpServer.ListenAndServe()
}
func (s *Server) runMqttServer() {
s.mqttServerBackend = newMqttBackend(s.config, s.handle)
s.mqttServerBackend.Connect()
s.mqttServerBackend.Subscribe()
return
}
func (s *Server) runManager() {
for {
select {

View file

@ -203,6 +203,18 @@
# visitor-attachment-total-size-limit: "100M"
# visitor-attachment-daily-bandwidth-limit: "500M"
# MQTT configuration, if mqtt-server is empty no connexion to MQTT server :
# - mqtt-server if it's empty no connexion to Mqtt server
# - mqtt-port mqtt server port, by defaut it's 1883
# - mqtt-username if it's empty no authentification
# - mqtt-password can not be empty if username is not empty
# - mqtt-topic defaut topic to listen, message need to be send in json format on mqtt-topic/message, by defaut it's ntfy/message
# mqtt-server: ""
# mqtt-port: 1883
# mqtt-username: ""
# mqtt-password: ""
# mqtt-topic: "ntfy"
# Log level, can be TRACE, DEBUG, INFO, WARN or ERROR
# This option can be hot-reloaded by calling "kill -HUP $pid" or "systemctl reload ntfy".
#