mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-08 17:03:39 +00:00
281 lines
8.9 KiB
Go
281 lines
8.9 KiB
Go
// The following code is a slightly modified version of code taken from the Paho MQTT library.
|
|
// It is here until TinyGo can compile the "net" package from the standard library, at which time
|
|
// it can be removed.
|
|
|
|
/*
|
|
* 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
|
|
*/
|
|
|
|
// Portions copyright © 2018 TIBCO Software Inc.
|
|
|
|
package mqtt
|
|
|
|
import (
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/eclipse/paho.mqtt.golang/packets"
|
|
"tinygo.org/x/drivers/net"
|
|
)
|
|
|
|
const (
|
|
disconnected uint32 = iota
|
|
connecting
|
|
reconnecting
|
|
connected
|
|
)
|
|
|
|
// Client is the interface definition for a Client as used by this
|
|
// library, the interface is primarily to allow mocking tests.
|
|
//
|
|
// It is an MQTT v3.1.1 client for communicating
|
|
// with an MQTT server using non-blocking methods that allow work
|
|
// to be done in the background.
|
|
// An application may connect to an MQTT server using:
|
|
// A plain TCP socket
|
|
// A secure SSL/TLS socket
|
|
// A websocket
|
|
// To enable ensured message delivery at Quality of Service (QoS) levels
|
|
// described in the MQTT spec, a message persistence mechanism must be
|
|
// used. This is done by providing a type which implements the Store
|
|
// interface. For convenience, FileStore and MemoryStore are provided
|
|
// implementations that should be sufficient for most use cases. More
|
|
// information can be found in their respective documentation.
|
|
// Numerous connection options may be specified by configuring a
|
|
// and then supplying a ClientOptions type.
|
|
type Client interface {
|
|
// IsConnected returns a bool signifying whether
|
|
// the client is connected or not.
|
|
IsConnected() bool
|
|
// IsConnectionOpen return a bool signifying wether the client has an active
|
|
// connection to mqtt broker, i.e not in disconnected or reconnect mode
|
|
IsConnectionOpen() bool
|
|
// Connect will create a connection to the message broker, by default
|
|
// it will attempt to connect at v3.1.1 and auto retry at v3.1 if that
|
|
// fails
|
|
Connect() Token
|
|
// Disconnect will end the connection with the server, but not before waiting
|
|
// the specified number of milliseconds to wait for existing work to be
|
|
// completed.
|
|
Disconnect(quiesce uint)
|
|
// Publish will publish a message with the specified QoS and content
|
|
// to the specified topic.
|
|
// Returns a token to track delivery of the message to the broker
|
|
Publish(topic string, qos byte, retained bool, payload interface{}) Token
|
|
// Subscribe starts a new subscription. Provide a MessageHandler to be executed when
|
|
// a message is published on the topic provided, or nil for the default handler
|
|
Subscribe(topic string, qos byte, callback MessageHandler) Token
|
|
// SubscribeMultiple starts a new subscription for multiple topics. Provide a MessageHandler to
|
|
// be executed when a message is published on one of the topics provided, or nil for the
|
|
// default handler
|
|
SubscribeMultiple(filters map[string]byte, callback MessageHandler) Token
|
|
// Unsubscribe will end the subscription from each of the topics provided.
|
|
// Messages published to those topics from other clients will no longer be
|
|
// received.
|
|
Unsubscribe(topics ...string) Token
|
|
// AddRoute allows you to add a handler for messages on a specific topic
|
|
// without making a subscription. For example having a different handler
|
|
// for parts of a wildcard subscription
|
|
AddRoute(topic string, callback MessageHandler)
|
|
// OptionsReader returns a ClientOptionsReader which is a copy of the clientoptions
|
|
// in use by the client.
|
|
OptionsReader() ClientOptionsReader
|
|
}
|
|
|
|
// Token defines the interface for the tokens used to indicate when
|
|
// actions have completed.
|
|
type Token interface {
|
|
Wait() bool
|
|
WaitTimeout(time.Duration) bool
|
|
Error() error
|
|
}
|
|
|
|
// MessageHandler is a callback type which can be set to be
|
|
// executed upon the arrival of messages published to topics
|
|
// to which the client is subscribed.
|
|
type MessageHandler func(Client, Message)
|
|
|
|
// Message defines the externals that a message implementation must support
|
|
// these are received messages that are passed to the callbacks, not internal
|
|
// messages
|
|
type Message interface {
|
|
Duplicate() bool
|
|
Qos() byte
|
|
Retained() bool
|
|
Topic() string
|
|
MessageID() uint16
|
|
Payload() []byte
|
|
Ack()
|
|
}
|
|
|
|
type message struct {
|
|
duplicate bool
|
|
qos byte
|
|
retained bool
|
|
topic string
|
|
messageID uint16
|
|
payload []byte
|
|
ack func()
|
|
}
|
|
|
|
func (m *message) Duplicate() bool {
|
|
return m.duplicate
|
|
}
|
|
|
|
func (m *message) Qos() byte {
|
|
return m.qos
|
|
}
|
|
|
|
func (m *message) Retained() bool {
|
|
return m.retained
|
|
}
|
|
|
|
func (m *message) Topic() string {
|
|
return m.topic
|
|
}
|
|
|
|
func (m *message) MessageID() uint16 {
|
|
return m.messageID
|
|
}
|
|
|
|
func (m *message) Payload() []byte {
|
|
return m.payload
|
|
}
|
|
|
|
func (m *message) Ack() {
|
|
return
|
|
}
|
|
|
|
func messageFromPublish(p *packets.PublishPacket, ack func()) Message {
|
|
return &message{
|
|
duplicate: p.Dup,
|
|
qos: p.Qos,
|
|
retained: p.Retain,
|
|
topic: p.TopicName,
|
|
messageID: p.MessageID,
|
|
payload: p.Payload,
|
|
ack: ack,
|
|
}
|
|
}
|
|
|
|
// ClientOptionsReader provides an interface for reading ClientOptions after the client has been initialized.
|
|
type ClientOptionsReader struct {
|
|
options *ClientOptions
|
|
}
|
|
|
|
// ClientOptions contains configurable options for an MQTT Client.
|
|
type ClientOptions struct {
|
|
Adaptor net.DeviceDriver
|
|
|
|
//Servers []*url.URL
|
|
Servers string
|
|
ClientID string
|
|
Username string
|
|
Password string
|
|
//CredentialsProvider CredentialsProvider
|
|
CleanSession bool
|
|
Order bool
|
|
WillEnabled bool
|
|
WillTopic string
|
|
WillPayload []byte
|
|
WillQos byte
|
|
WillRetained bool
|
|
ProtocolVersion uint
|
|
protocolVersionExplicit bool
|
|
//TLSConfig *tls.Config
|
|
KeepAlive int64
|
|
PingTimeout time.Duration
|
|
ConnectTimeout time.Duration
|
|
MaxReconnectInterval time.Duration
|
|
AutoReconnect bool
|
|
//Store Store
|
|
//DefaultPublishHandler MessageHandler
|
|
//OnConnect OnConnectHandler
|
|
//OnConnectionLost ConnectionLostHandler
|
|
WriteTimeout time.Duration
|
|
MessageChannelDepth uint
|
|
ResumeSubs bool
|
|
//HTTPHeaders http.Header
|
|
}
|
|
|
|
// NewClientOptions returns a new ClientOptions struct.
|
|
func NewClientOptions() *ClientOptions {
|
|
return &ClientOptions{Adaptor: net.ActiveDevice, ProtocolVersion: 4}
|
|
}
|
|
|
|
// AddBroker adds a broker URI to the list of brokers to be used. The format should be
|
|
// scheme://host:port
|
|
// Where "scheme" is one of "tcp", "ssl", or "ws", "host" is the ip-address (or hostname)
|
|
// and "port" is the port on which the broker is accepting connections.
|
|
//
|
|
// Default values for hostname is "127.0.0.1", for schema is "tcp://".
|
|
//
|
|
// An example broker URI would look like: tcp://foobar.com:1883
|
|
func (o *ClientOptions) AddBroker(server string) *ClientOptions {
|
|
if len(server) > 0 && server[0] == ':' {
|
|
server = "127.0.0.1" + server
|
|
}
|
|
if !strings.Contains(server, "://") {
|
|
server = "tcp://" + server
|
|
}
|
|
|
|
o.Servers = server
|
|
return o
|
|
}
|
|
|
|
// SetClientID will set the client id to be used by this client when
|
|
// connecting to the MQTT broker. According to the MQTT v3.1 specification,
|
|
// a client id mus be no longer than 23 characters.
|
|
func (o *ClientOptions) SetClientID(id string) *ClientOptions {
|
|
o.ClientID = id
|
|
return o
|
|
}
|
|
|
|
// SetUsername will set the username to be used by this client when connecting
|
|
// to the MQTT broker. Note: without the use of SSL/TLS, this information will
|
|
// be sent in plaintext accross the wire.
|
|
func (o *ClientOptions) SetUsername(u string) *ClientOptions {
|
|
o.Username = u
|
|
return o
|
|
}
|
|
|
|
// SetPassword will set the password to be used by this client when connecting
|
|
// to the MQTT broker. Note: without the use of SSL/TLS, this information will
|
|
// be sent in plaintext accross the wire.
|
|
func (o *ClientOptions) SetPassword(p string) *ClientOptions {
|
|
o.Password = p
|
|
return o
|
|
}
|
|
|
|
// SetWill accepts a string will message to be set. When the client connects,
|
|
// it will give this will message to the broker, which will then publish the
|
|
// provided payload (the will) to any clients that are subscribed to the provided
|
|
// topic.
|
|
func (o *ClientOptions) SetWill(topic string, payload string, qos byte, retained bool) *ClientOptions {
|
|
o.SetBinaryWill(topic, []byte(payload), qos, retained)
|
|
return o
|
|
}
|
|
|
|
// SetBinaryWill accepts a []byte will message to be set. When the client connects,
|
|
// it will give this will message to the broker, which will then publish the
|
|
// provided payload (the will) to any clients that are subscribed to the provided
|
|
// topic.
|
|
func (o *ClientOptions) SetBinaryWill(topic string, payload []byte, qos byte, retained bool) *ClientOptions {
|
|
o.WillEnabled = true
|
|
o.WillTopic = topic
|
|
o.WillPayload = payload
|
|
o.WillQos = qos
|
|
o.WillRetained = retained
|
|
return o
|
|
}
|