This implementation is similar to AMQP notifications: * Notifications are published on a single topic as a JSON feed * Topic is configurable, as is the QoS. Uses the paho.mqtt.golang library for the mqtt connection, and supports connections over tcp and websockets, with optional secure tls support. * Additionally the minio server configuration has been bumped up so mqtt configuration can be added. * Configuration migration code is added with tests. MQTT is an ISO standard M2M/IoT messaging protocol and was originally designed for applications for limited bandwidth networks. Today it's use is growing in the IoT space.
127 lines
3.4 KiB
Go
127 lines
3.4 KiB
Go
/*
|
|
* Copyright (c) 2013 IBM Corp.
|
|
*
|
|
* All rights reserved. This program and the accompanying materials
|
|
* are made available under the terms of the Eclipse Public License v1.0
|
|
* which accompanies this distribution, and is available at
|
|
* http://www.eclipse.org/legal/epl-v10.html
|
|
*
|
|
* Contributors:
|
|
* Seth Hoenig
|
|
* Allan Stockdill-Mander
|
|
* Mike Robertson
|
|
*/
|
|
|
|
package mqtt
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
|
|
"github.com/eclipse/paho.mqtt.golang/packets"
|
|
)
|
|
|
|
const (
|
|
inboundPrefix = "i."
|
|
outboundPrefix = "o."
|
|
)
|
|
|
|
// Store is an interface which can be used to provide implementations
|
|
// for message persistence.
|
|
// Because we may have to store distinct messages with the same
|
|
// message ID, we need a unique key for each message. This is
|
|
// possible by prepending "i." or "o." to each message id
|
|
type Store interface {
|
|
Open()
|
|
Put(key string, message packets.ControlPacket)
|
|
Get(key string) packets.ControlPacket
|
|
All() []string
|
|
Del(key string)
|
|
Close()
|
|
Reset()
|
|
}
|
|
|
|
// A key MUST have the form "X.[messageid]"
|
|
// where X is 'i' or 'o'
|
|
func mIDFromKey(key string) uint16 {
|
|
s := key[2:]
|
|
i, err := strconv.Atoi(s)
|
|
chkerr(err)
|
|
return uint16(i)
|
|
}
|
|
|
|
// Return a string of the form "i.[id]"
|
|
func inboundKeyFromMID(id uint16) string {
|
|
return fmt.Sprintf("%s%d", inboundPrefix, id)
|
|
}
|
|
|
|
// Return a string of the form "o.[id]"
|
|
func outboundKeyFromMID(id uint16) string {
|
|
return fmt.Sprintf("%s%d", outboundPrefix, id)
|
|
}
|
|
|
|
// govern which outgoing messages are persisted
|
|
func persistOutbound(s Store, m packets.ControlPacket) {
|
|
switch m.Details().Qos {
|
|
case 0:
|
|
switch m.(type) {
|
|
case *packets.PubackPacket, *packets.PubcompPacket:
|
|
// Sending puback. delete matching publish
|
|
// from ibound
|
|
s.Del(inboundKeyFromMID(m.Details().MessageID))
|
|
}
|
|
case 1:
|
|
switch m.(type) {
|
|
case *packets.PublishPacket, *packets.PubrelPacket, *packets.SubscribePacket, *packets.UnsubscribePacket:
|
|
// Sending publish. store in obound
|
|
// until puback received
|
|
s.Put(outboundKeyFromMID(m.Details().MessageID), m)
|
|
default:
|
|
ERROR.Println(STR, "Asked to persist an invalid message type")
|
|
}
|
|
case 2:
|
|
switch m.(type) {
|
|
case *packets.PublishPacket:
|
|
// Sending publish. store in obound
|
|
// until pubrel received
|
|
s.Put(outboundKeyFromMID(m.Details().MessageID), m)
|
|
default:
|
|
ERROR.Println(STR, "Asked to persist an invalid message type")
|
|
}
|
|
}
|
|
}
|
|
|
|
// govern which incoming messages are persisted
|
|
func persistInbound(s Store, m packets.ControlPacket) {
|
|
switch m.Details().Qos {
|
|
case 0:
|
|
switch m.(type) {
|
|
case *packets.PubackPacket, *packets.SubackPacket, *packets.UnsubackPacket, *packets.PubcompPacket:
|
|
// Received a puback. delete matching publish
|
|
// from obound
|
|
s.Del(outboundKeyFromMID(m.Details().MessageID))
|
|
case *packets.PublishPacket, *packets.PubrecPacket, *packets.PingrespPacket, *packets.ConnackPacket:
|
|
default:
|
|
ERROR.Println(STR, "Asked to persist an invalid messages type")
|
|
}
|
|
case 1:
|
|
switch m.(type) {
|
|
case *packets.PublishPacket, *packets.PubrelPacket:
|
|
// Received a publish. store it in ibound
|
|
// until puback sent
|
|
s.Put(inboundKeyFromMID(m.Details().MessageID), m)
|
|
default:
|
|
ERROR.Println(STR, "Asked to persist an invalid messages type")
|
|
}
|
|
case 2:
|
|
switch m.(type) {
|
|
case *packets.PublishPacket:
|
|
// Received a publish. store it in ibound
|
|
// until pubrel received
|
|
s.Put(inboundKeyFromMID(m.Details().MessageID), m)
|
|
default:
|
|
ERROR.Println(STR, "Asked to persist an invalid messages type")
|
|
}
|
|
}
|
|
}
|