Basic support of XEP-0045 to send messages to MUC
This commit is contained in:
parent
6ee09c3994
commit
2215e428a5
12
README.md
12
README.md
|
@ -36,7 +36,9 @@ This example of configuration file shows:
|
|||
- when it is working, it has the status `Monitoring Prometheus...`
|
||||
- it doesn't use a TLS socket due to the `no_tls` flag. Actually it will use STARTTLS due to the server configuration
|
||||
- it doesn't check the TLS certificates thanks to `tls_insecure` (for some reason, it doesn't work on my Prosody install, but as I'm connecting to localhost, it doesn't matter)
|
||||
- each time it receives an alert, it sends a notification to 2 XMPP accounts `on-duty-1@example.com` and `on-duty-2@example.com`.
|
||||
- each time it receives an alert, it sends a notification to
|
||||
- 2 XMPP accounts `on-duty-1@example.com` and `on-duty-2@example.com`
|
||||
- 1 MUC `monitoring-room-id@conference.example.com` using the nick `monitoring-bot`
|
||||
|
||||
```json
|
||||
{
|
||||
|
@ -54,6 +56,12 @@ This example of configuration file shows:
|
|||
"send_notif": [
|
||||
"on-duty-1@example.com",
|
||||
"on-duty-2@example.com"
|
||||
],
|
||||
"send_muc": [
|
||||
{
|
||||
"room": "monitoring-room-id@conference.example.com",
|
||||
"nick": "monitoring-bot"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -82,6 +90,6 @@ This program uses HTTP with 3 different paths:
|
|||
|
||||
- `/alert` is used by Prometheus' Alertmanager to send alerts
|
||||
- `/send` is mainly used for debugging or if one just want to send simple message from another program. To send a message:
|
||||
- `curl -H 'Content-Type: text/plain' -X POST <my_ip:port>/send -d 'my message'`
|
||||
- `curl -H 'Content-Type: text/plain' -X POST <my_ip:port>/send -d 'my message'`
|
||||
- `curl -H 'Content-Type: text/html' -X POST <my_ip:port>/send -d '<p style="color:green;font-weight:bold;">Green text</p>'` if the client supports the deprecated XEP-0071
|
||||
- `/metrics` to be scrapped by Prometheus. It exposes some basic metrics
|
||||
|
|
30
config.go
30
config.go
|
@ -4,6 +4,7 @@ import (
|
|||
"encoding/json"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
|
@ -20,13 +21,21 @@ type Config struct {
|
|||
|
||||
// ConfigXMPP is the configuration for XMPP connection
|
||||
type ConfigXMPP struct {
|
||||
OverrideServer string `json:"override_server"`
|
||||
User string `json:"user"`
|
||||
Password string `json:"password"`
|
||||
SendNotif []string `json:"send_notif"`
|
||||
Status string `json:"status"`
|
||||
NoTLS bool `json:"no_tls"`
|
||||
TLSInsecure bool `json:"tls_insecure"`
|
||||
OverrideServer string `json:"override_server"`
|
||||
User string `json:"user"`
|
||||
Password string `json:"password"`
|
||||
SendNotif []string `json:"send_notif"`
|
||||
SendMUC []*ConfigMUC `json:"send_muc"`
|
||||
Status string `json:"status"`
|
||||
NoTLS bool `json:"no_tls"`
|
||||
TLSInsecure bool `json:"tls_insecure"`
|
||||
}
|
||||
|
||||
// ConfigMUC is the list of MUC to join (xep-0045)
|
||||
type ConfigMUC struct {
|
||||
Room string `json:"room"`
|
||||
Nick string `json:"nick"`
|
||||
Password *string `json:"password"`
|
||||
}
|
||||
|
||||
// NewConfig reads the JSON file filename and generates a configuration
|
||||
|
@ -47,6 +56,13 @@ func NewConfig(filename string) *Config {
|
|||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
// default nick
|
||||
for _, configMUC := range config.XMPP.SendMUC {
|
||||
if configMUC.Nick == "" {
|
||||
configMUC.Nick = strings.Split(config.XMPP.User, "@")[0]
|
||||
}
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ var (
|
|||
Namespace: promNamespace,
|
||||
Name: "messages_sent_total",
|
||||
Help: "Number of messages sent.",
|
||||
}, []string{"recipient", "format"})
|
||||
}, []string{"recipient", "recipient_type", "format"})
|
||||
promMessagesReceivedMetric = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: promNamespace,
|
||||
Name: "messages_received_total",
|
||||
|
|
66
xmpp.go
66
xmpp.go
|
@ -27,6 +27,7 @@ type xmpp struct {
|
|||
channel chan xmppMessage
|
||||
status string
|
||||
sendNotif []string
|
||||
sendMUC []string
|
||||
}
|
||||
|
||||
type xmppMessage struct {
|
||||
|
@ -35,6 +36,35 @@ type xmppMessage struct {
|
|||
format Format
|
||||
}
|
||||
|
||||
type xmppChatType int
|
||||
|
||||
const (
|
||||
xmppChatType_Chat xmppChatType = iota
|
||||
xmppChatType_GroupChat
|
||||
)
|
||||
|
||||
func (x xmppChatType) String() string {
|
||||
switch x {
|
||||
case xmppChatType_GroupChat:
|
||||
return "groupchat"
|
||||
case xmppChatType_Chat:
|
||||
return "chat"
|
||||
default:
|
||||
return "chat"
|
||||
}
|
||||
}
|
||||
|
||||
func xmppChatTypeFrom(s string) (xmppChatType, error) {
|
||||
switch s {
|
||||
case xmppChatType_Chat.String():
|
||||
return xmppChatType_Chat, nil
|
||||
case xmppChatType_GroupChat.String():
|
||||
return xmppChatType_GroupChat, nil
|
||||
default:
|
||||
return xmppChatType_Chat, fmt.Errorf("unhandled chat type: %s", s)
|
||||
}
|
||||
}
|
||||
|
||||
// NewXMPP create an XMPP connection. Use Close() to end it
|
||||
func NewXMPP(config *Config) SendCloser {
|
||||
if config.XMPP.OverrideServer != "" {
|
||||
|
@ -69,7 +99,22 @@ func NewXMPP(config *Config) SendCloser {
|
|||
status: config.XMPP.Status,
|
||||
sendNotif: config.XMPP.SendNotif,
|
||||
}
|
||||
|
||||
for _, muc := range config.XMPP.SendMUC {
|
||||
var err error
|
||||
result.sendMUC = append(result.sendMUC, muc.Room)
|
||||
if muc.Password != nil {
|
||||
_, err = client.JoinProtectedMUC(muc.Room, muc.Nick, *muc.Password, libxmpp.NoHistory, 0, nil)
|
||||
} else {
|
||||
_, err = client.JoinMUC(muc.Room, muc.Nick, libxmpp.NoHistory, 0, nil)
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatalf("Could not connect to MUC: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
prometheus.MustRegister(result)
|
||||
|
||||
go result.runSender()
|
||||
go result.runReceiver()
|
||||
if config.StartupMessage != "" {
|
||||
|
@ -112,10 +157,13 @@ func (x *xmpp) sendTo(to, message string) error {
|
|||
func (x *xmpp) runSender() {
|
||||
for payload := range x.channel {
|
||||
if payload.to != nil {
|
||||
x.sendToImmediate(*payload.to, payload.message, payload.format)
|
||||
x.sendToImmediate(xmppChatType_Chat, *payload.to, payload.message, payload.format)
|
||||
} else {
|
||||
for _, sendNotif := range x.sendNotif {
|
||||
x.sendToImmediate(sendNotif, payload.message, payload.format)
|
||||
x.sendToImmediate(xmppChatType_Chat, sendNotif, payload.message, payload.format)
|
||||
}
|
||||
for _, room := range x.sendMUC {
|
||||
x.sendToImmediate(xmppChatType_GroupChat, room, payload.message, payload.format)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -134,7 +182,10 @@ func (x *xmpp) runReceiver() {
|
|||
x.debug("Stanza: %v\n", stanza)
|
||||
switch v := stanza.(type) {
|
||||
case libxmpp.Chat:
|
||||
x.handleChat(&v)
|
||||
chatType, err := xmppChatTypeFrom(v.Type)
|
||||
if err == nil && chatType == xmppChatType_Chat {
|
||||
x.handleChat(&v)
|
||||
}
|
||||
case libxmpp.Presence:
|
||||
x.handlePresence(&v)
|
||||
}
|
||||
|
@ -160,7 +211,6 @@ func (x *xmpp) handleChat(chat *libxmpp.Chat) {
|
|||
|
||||
func (x *xmpp) handlePresence(presence *libxmpp.Presence) {
|
||||
switch presence.Type {
|
||||
case "":
|
||||
case "unavailable":
|
||||
// something puts us as unavailable
|
||||
if presence.From == x.client.JID() {
|
||||
|
@ -174,6 +224,8 @@ func (x *xmpp) handlePresence(presence *libxmpp.Presence) {
|
|||
x.client.RevokeSubscription(presence.From)
|
||||
x.debug("Revoked subscription to %s\n", presence.From)
|
||||
}
|
||||
case "error":
|
||||
fmt.Printf("Error from %s", presence.From)
|
||||
default:
|
||||
x.debug("Unhandled presence: %v\n", presence)
|
||||
}
|
||||
|
@ -199,11 +251,11 @@ func (x *xmpp) handleCommand(from, command string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (x *xmpp) sendToImmediate(to, message string, format Format) {
|
||||
promMessagesSentMetric.WithLabelValues(to, format.String()).Inc()
|
||||
func (x *xmpp) sendToImmediate(chatType xmppChatType, to, message string, format Format) {
|
||||
promMessagesSentMetric.WithLabelValues(to, chatType.String(), format.String()).Inc()
|
||||
_, err := x.sendChat(libxmpp.Chat{
|
||||
Remote: to,
|
||||
Type: "chat",
|
||||
Type: chatType.String(),
|
||||
Text: message,
|
||||
}, format)
|
||||
if err != nil {
|
||||
|
|
Loading…
Reference in New Issue