1
0
mirror of https://github.com/mainflux/mainflux.git synced 2025-04-26 13:48:53 +08:00

Update mqtt adapter imports (#1081)

* Fixed mqtt adapter imports

Signed-off-by: Nikola Marcetic <n.marcetic86@gmail.com>

* PR remakrs resolved

Signed-off-by: Nikola Marcetic <n.marcetic86@gmail.com>
This commit is contained in:
Nikola Marčetić 2020-03-24 11:07:41 +01:00 committed by GitHub
parent 19503742a6
commit 6ffa916ed2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 362 additions and 151 deletions

2
.env
View File

@ -81,7 +81,7 @@ MF_MQTT_ADAPTER_LOG_LEVEL=debug
MF_MQTT_ADAPTER_PORT=1883
MF_MQTT_BROKER_PORT=1883
MF_MQTT_ADAPTER_WS_PORT=8080
MF_MQTT_BROKER_WS_PORT=8881
MF_MQTT_BROKER_WS_PORT=8080
MF_MQTT_ADAPTER_ES_DB=0
MF_MQTT_ADAPTER_ES_PASS=

View File

@ -5,6 +5,7 @@ import (
"io"
"io/ioutil"
"log"
"net/http"
"os"
"os/signal"
"strconv"
@ -19,6 +20,7 @@ import (
mr "github.com/mainflux/mainflux/mqtt/redis"
thingsapi "github.com/mainflux/mainflux/things/api/auth/grpc"
mp "github.com/mainflux/mproxy/pkg/mqtt"
ws "github.com/mainflux/mproxy/pkg/websocket"
broker "github.com/nats-io/nats.go"
opentracing "github.com/opentracing/opentracing-go"
jconfig "github.com/uber/jaeger-client-go/config"
@ -27,36 +29,57 @@ import (
)
const (
// MQTT
defMQTTHost = "0.0.0.0"
defMQTTPort = "1883"
defMQTTTargetHost = "0.0.0.0"
defMQTTTargetPort = "1884"
defMQTTTargetPort = "1883"
envMQTTHost = "MF_MQTT_ADAPTER_MQTT_HOST"
envMQTTPort = "MF_MQTT_ADAPTER_MQTT_PORT"
envMQTTTargetHost = "MF_MQTT_ADAPTER_MQTT_TARGET_HOST"
envMQTTTargetPort = "MF_MQTT_ADAPTER_MQTT_TARGET_PORT"
defLogLevel = "error"
envLogLevel = "MF_MQTT_ADAPTER_LOG_LEVEL"
defThingsURL = "localhost:8181"
defThingsTimeout = "1" // in seconds
envThingsURL = "MF_THINGS_URL"
envThingsTimeout = "MF_MQTT_ADAPTER_THINGS_TIMEOUT"
defNatsURL = broker.DefaultURL
envNatsURL = "MF_NATS_URL"
defJaegerURL = ""
envJaegerURL = "MF_JAEGER_URL"
defClientTLS = "false"
defCACerts = ""
envClientTLS = "MF_MQTT_ADAPTER_CLIENT_TLS"
envCACerts = "MF_MQTT_ADAPTER_CA_CERTS"
envInstance = "MF_MQTT_ADAPTER_INSTANCE"
defInstance = ""
envESURL = "MF_MQTT_ADAPTER_ES_URL"
envESPass = "MF_MQTT_ADAPTER_ES_PASS"
envESDB = "MF_MQTT_ADAPTER_ES_DB"
defESURL = "localhost:6379"
defESPass = ""
defESDB = "0"
// HTTP
defHTTPHost = "0.0.0.0"
defHTTPPort = "8080"
defHTTPScheme = "ws"
defHTTPTargetHost = "localhost"
defHTTPTargetPort = "8080"
defHTTPTargetPath = "/mqtt"
envHTTPHost = "MF_MQTT_ADAPTER_WS_HOST"
envHTTPPort = "MF_MQTT_ADAPTER_WS_PORT"
envHTTPScheme = "MF_MQTT_ADAPTER_WS_SCHEMA"
envHTTPTargetHost = "MF_MQTT_ADAPTER_WS_TARGET_HOST"
envHTTPTargetPort = "MF_MQTT_ADAPTER_WS_TARGET_PORT"
envHTTPTargetPath = "MF_MQTT_ADAPTER_WS_TARGET_PATH"
// Logging
defLogLevel = "error"
envLogLevel = "MF_MQTT_ADAPTER_LOG_LEVEL"
// Things
defThingsURL = "localhost:8181"
defThingsTimeout = "1" // in seconds
envThingsURL = "MF_THINGS_URL"
envThingsTimeout = "MF_MQTT_ADAPTER_THINGS_TIMEOUT"
// Nats
defNatsURL = broker.DefaultURL
envNatsURL = "MF_NATS_URL"
// Jaeger
defJaegerURL = ""
envJaegerURL = "MF_JAEGER_URL"
// TLS
defClientTLS = "false"
defCACerts = ""
envClientTLS = "MF_MQTT_ADAPTER_CLIENT_TLS"
envCACerts = "MF_MQTT_ADAPTER_CA_CERTS"
// Instance
envInstance = "MF_MQTT_ADAPTER_INSTANCE"
defInstance = ""
// ES
envESURL = "MF_MQTT_ADAPTER_ES_URL"
envESPass = "MF_MQTT_ADAPTER_ES_PASS"
envESDB = "MF_MQTT_ADAPTER_ES_DB"
defESURL = "localhost:6379"
defESPass = ""
defESDB = "0"
)
type config struct {
@ -64,6 +87,12 @@ type config struct {
mqttPort string
mqttTargetHost string
mqttTargetPort string
httpHost string
httpPort string
httpScheme string
httpTargetHost string
httpTargetPort string
httpTargetPath string
jaegerURL string
logLevel string
thingsURL string
@ -115,9 +144,12 @@ func main() {
errs := make(chan error, 2)
logger.Info(fmt.Sprintf("Starting MQTT proxy on port %s ", cfg.mqttPort))
logger.Info(fmt.Sprintf("Starting MQTT proxy on port %s", cfg.mqttPort))
go proxyMQTT(cfg, logger, evt, errs)
logger.Info(fmt.Sprintf("Starting MQTT over WS proxy on port %s", cfg.httpPort))
go proxyWS(cfg, logger, evt, errs)
go func() {
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGINT)
@ -144,6 +176,12 @@ func loadConfig() config {
mqttPort: mainflux.Env(envMQTTPort, defMQTTPort),
mqttTargetHost: mainflux.Env(envMQTTTargetHost, defMQTTTargetHost),
mqttTargetPort: mainflux.Env(envMQTTTargetPort, defMQTTTargetPort),
httpHost: mainflux.Env(envHTTPHost, defHTTPHost),
httpPort: mainflux.Env(envHTTPPort, defHTTPPort),
httpScheme: mainflux.Env(envHTTPScheme, defHTTPScheme),
httpTargetHost: mainflux.Env(envHTTPTargetHost, defHTTPTargetHost),
httpTargetPort: mainflux.Env(envHTTPTargetPort, defHTTPTargetPort),
httpTargetPath: mainflux.Env(envHTTPTargetPath, defHTTPTargetPath),
jaegerURL: mainflux.Env(envJaegerURL, defJaegerURL),
thingsTimeout: time.Duration(timeout) * time.Second,
thingsURL: mainflux.Env(envThingsURL, defThingsURL),
@ -221,7 +259,17 @@ func connectToRedis(redisURL, redisPass, redisDB string, logger logger.Logger) *
}
func proxyMQTT(cfg config, logger logger.Logger, evt *mqtt.Event, errs chan error) {
mp := mp.New(cfg.mqttHost, cfg.mqttPort, cfg.mqttTargetHost, cfg.mqttTargetPort, evt, logger)
address := fmt.Sprintf("%s:%s", cfg.mqttHost, cfg.mqttPort)
target := fmt.Sprintf("%s:%s", cfg.mqttTargetHost, cfg.mqttTargetPort)
mp := mp.New(address, target, evt, logger)
errs <- mp.Proxy()
}
func proxyWS(cfg config, logger logger.Logger, evt *mqtt.Event, errs chan error) {
target := fmt.Sprintf("%s:%s", cfg.httpTargetHost, cfg.httpTargetPort)
wp := ws.New(target, cfg.httpTargetPath, cfg.httpScheme, evt, logger)
http.Handle("/mqtt", wp.Handler())
p := fmt.Sprintf(":%s", cfg.httpPort)
errs <- http.ListenAndServe(p, nil)
}

View File

@ -208,7 +208,7 @@ services:
restart: on-failure
environment:
DOCKER_VERNEMQ_ALLOW_ANONYMOUS: "on"
DOCKER_VERNEMQ_LOG__CONSOLE__LEVEL: info
DOCKER_VERNEMQ_LOG__CONSOLE__LEVEL: debug
ports:
- 18831:${MF_MQTT_BROKER_PORT}
- 8881:${MF_MQTT_BROKER_WS_PORT}
@ -236,6 +236,8 @@ services:
MF_JAEGER_URL: ${MF_JAEGER_URL}
MF_MQTT_ADAPTER_MQTT_TARGET_HOST: vernemq
MF_MQTT_ADAPTER_MQTT_TARGET_PORT: ${MF_MQTT_BROKER_PORT}
MF_MQTT_ADAPTER_WS_TARGET_HOST: vernemq
MF_MQTT_ADAPTER_WS_TARGET_PORT: ${MF_MQTT_BROKER_WS_PORT}
ports:
- 18832:${MF_MQTT_ADAPTER_PORT}
- 8882:${MF_MQTT_ADAPTER_WS_PORT}

13
go.mod
View File

@ -4,8 +4,6 @@ go 1.11
require (
github.com/BurntSushi/toml v0.3.1
github.com/bitly/go-hostpool v0.1.0 // indirect
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/docker/docker v1.13.1
github.com/dustin/go-coap v0.0.0-20170214053734-ddcc80675fa4
@ -14,21 +12,18 @@ require (
github.com/go-kit/kit v0.9.0
github.com/go-redis/redis v6.15.0+incompatible
github.com/go-zoo/bone v1.3.0
github.com/gobuffalo/packr v1.30.1 // indirect
github.com/gocql/gocql v0.0.0-20181106112037-68ae1e384be4
github.com/gofrs/uuid v3.2.0+incompatible
github.com/gogo/protobuf v1.3.1
github.com/golang/protobuf v1.3.3
github.com/gopcua/opcua v0.1.6
github.com/gorilla/websocket v1.4.1
github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect
github.com/hokaccha/go-prettyjson v0.0.0-20180920040306-f579f869bbfe
github.com/influxdata/influxdb v1.6.4
github.com/jmoiron/sqlx v1.2.1-0.20190319043955-cdf62fdf55f6
github.com/lib/pq v1.0.0
github.com/mainflux/mproxy v0.1.3
github.com/mainflux/mproxy v0.1.5
github.com/mainflux/senml v1.0.1
github.com/nats-io/nats-server/v2 v2.1.4 // indirect
github.com/nats-io/nats.go v1.9.1
github.com/opentracing/opentracing-go v1.1.0
github.com/prometheus/client_golang v0.9.3
@ -37,17 +32,11 @@ require (
github.com/spf13/cobra v0.0.5
github.com/spf13/viper v1.5.0
github.com/stretchr/testify v1.5.1
github.com/tidwall/pretty v1.0.0 // indirect
github.com/uber/jaeger-client-go v2.22.1+incompatible
github.com/ziutek/mymysql v1.5.4 // indirect
go.mongodb.org/mongo-driver v1.1.3
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae // indirect
golang.org/x/text v0.3.2 // indirect
gonum.org/v1/gonum v0.0.0-20190808205415-ced62fe5104b
google.golang.org/genproto v0.0.0-20200225123651-fc8f55426688 // indirect
google.golang.org/grpc v1.27.1
gopkg.in/ory/dockertest.v3 v3.3.5
gotest.tools v2.2.0+incompatible // indirect
)

7
go.sum
View File

@ -113,6 +113,7 @@ github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8l
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopcua/opcua v0.1.6 h1:B9SVRKQGzcWcwP2QPYN93Uku32+3wL+v5cgzBxE6V5I=
github.com/gopcua/opcua v0.1.6/go.mod h1:INwnDoRxmNWAt7+tzqxuGqQkSF2c1C69VAL0c2q6AcY=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
@ -163,8 +164,13 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mainflux/mainflux v0.0.0-20191223163044-f42f2095bab4/go.mod h1:K3ghSIpAqwv5F/t30LO57+11S7tE97ur2Z6wWEHa2CA=
github.com/mainflux/mainflux v0.0.0-20200314190902-c91fe0d45353/go.mod h1:yijZGLNkcDOPJfPhRMwuu5ZFcNHqDHzWurN4q1rOT/Q=
github.com/mainflux/mproxy v0.1.3 h1:/JNnxgo/03wSpbwQH2+WE1AzgMWaSKogTVXblh18x5s=
github.com/mainflux/mproxy v0.1.3/go.mod h1:/BdaBfgye1GNCD+eat4ipFamy9IEVRH5nhZS0yEShVg=
github.com/mainflux/mproxy v0.1.4 h1:g7LhJgA+BXlgaZeyLj505aD5DCsrix79TEiLWuHJZd4=
github.com/mainflux/mproxy v0.1.4/go.mod h1:MBLtv/RvhT8QsmXz4g3GxkRaP8PqlVqBWeqvw9QmO8k=
github.com/mainflux/mproxy v0.1.5 h1:a0zKiUyuTDld2TwCuhrOFtUvotcvSfwJMuh/JcrqC6I=
github.com/mainflux/mproxy v0.1.5/go.mod h1:MBLtv/RvhT8QsmXz4g3GxkRaP8PqlVqBWeqvw9QmO8k=
github.com/mainflux/senml v1.0.0 h1:oLS5aBhvdHjgQ8kfq3jX7yD+DaquhvpyvIWNsPil3X0=
github.com/mainflux/senml v1.0.0/go.mod h1:g9i8pj4WMs29KkUpXivbe/PP0qJd1kt3b1CF77S8A3s=
github.com/mainflux/senml v1.0.1 h1:qWKIGeUe7YEygM3xZcJ9Lbq+DHuT8V23dz1hgAYkYEY=
@ -390,6 +396,7 @@ google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO50
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200225123651-fc8f55426688 h1:1+0Z5cgv1eDXJD9z2tdQF9PSSQnJXwism490hJydMRI=
google.golang.org/genproto v0.0.0-20200225123651-fc8f55426688/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=

View File

@ -14,11 +14,11 @@ import (
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/mqtt/redis"
"github.com/mainflux/mproxy/pkg/mqtt"
"github.com/mainflux/mproxy/pkg/session"
opentracing "github.com/opentracing/opentracing-go"
)
var _ mqtt.Event = (*Event)(nil)
var _ session.Event = (*Event)(nil)
var (
channelRegExp = regexp.MustCompile(`^\/?channels\/([\w\-]+)\/messages(\/[^?]*)?(\?.*)?$`)
@ -56,11 +56,11 @@ func New(tc mainflux.ThingsServiceClient, pubs []mainflux.MessagePublisher, es r
// AuthConnect is called on device connection,
// prior forwarding to the MQTT broker
func (e *Event) AuthConnect(c *mqtt.Client) error {
func (e *Event) AuthConnect(c *session.Client) error {
if c == nil {
return errInvalidConnect
}
e.logger.Info(fmt.Sprintf("AuthConenct - client ID: %s, username: %s", c.ID, c.Username))
e.logger.Info(fmt.Sprintf("AuthConnect - client ID: %s, username: %s", c.ID, c.Username))
t := &mainflux.Token{
Value: string(c.Password),
@ -84,7 +84,7 @@ func (e *Event) AuthConnect(c *mqtt.Client) error {
// AuthPublish is called on device publish,
// prior forwarding to the MQTT broker
func (e *Event) AuthPublish(c *mqtt.Client, topic *string, payload *[]byte) error {
func (e *Event) AuthPublish(c *session.Client, topic *string, payload *[]byte) error {
if c == nil {
return errNilClient
}
@ -97,7 +97,7 @@ func (e *Event) AuthPublish(c *mqtt.Client, topic *string, payload *[]byte) erro
// AuthSubscribe is called on device publish,
// prior forwarding to the MQTT broker
func (e *Event) AuthSubscribe(c *mqtt.Client, topics *[]string) error {
func (e *Event) AuthSubscribe(c *session.Client, topics *[]string) error {
if c == nil {
return errNilClient
}
@ -117,7 +117,7 @@ func (e *Event) AuthSubscribe(c *mqtt.Client, topics *[]string) error {
}
// Connect - after client sucesfully connected
func (e *Event) Connect(c *mqtt.Client) {
func (e *Event) Connect(c *session.Client) {
if c == nil {
e.logger.Error("Nil client connect")
return
@ -126,7 +126,7 @@ func (e *Event) Connect(c *mqtt.Client) {
}
// Publish - after client sucesfully published
func (e *Event) Publish(c *mqtt.Client, topic *string, payload *[]byte) {
func (e *Event) Publish(c *session.Client, topic *string, payload *[]byte) {
if c == nil {
e.logger.Error("Nil client publish")
return
@ -175,7 +175,7 @@ func (e *Event) Publish(c *mqtt.Client, topic *string, payload *[]byte) {
}
// Subscribe - after client sucesfully subscribed
func (e *Event) Subscribe(c *mqtt.Client, topics *[]string) {
func (e *Event) Subscribe(c *session.Client, topics *[]string) {
if c == nil {
e.logger.Error("Nil client subscribe")
return
@ -184,7 +184,7 @@ func (e *Event) Subscribe(c *mqtt.Client, topics *[]string) {
}
// Unsubscribe - after client unsubscribed
func (e *Event) Unsubscribe(c *mqtt.Client, topics *[]string) {
func (e *Event) Unsubscribe(c *session.Client, topics *[]string) {
if c == nil {
e.logger.Error("Nil client unsubscribe")
return
@ -193,7 +193,7 @@ func (e *Event) Unsubscribe(c *mqtt.Client, topics *[]string) {
}
// Disconnect - connection with broker or client lost
func (e *Event) Disconnect(c *mqtt.Client) {
func (e *Event) Disconnect(c *session.Client) {
if c == nil {
e.logger.Error("Nil client disconnect")
return

71
vendor/github.com/mainflux/mproxy/pkg/mqtt/mqtt.go generated vendored Normal file
View File

@ -0,0 +1,71 @@
package mqtt
import (
"io"
"net"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mproxy/pkg/session"
)
// Proxy is main MQTT proxy struct
type Proxy struct {
address string
target string
event session.Event
logger logger.Logger
}
func New(address, target string, event session.Event, logger logger.Logger) *Proxy {
return &Proxy{
address: address,
target: target,
event: event,
logger: logger,
}
}
func (p Proxy) accept(l net.Listener) {
for {
conn, err := l.Accept()
if err != nil {
p.logger.Warn("Accept error " + err.Error())
continue
}
p.logger.Info("Accepted new client")
go p.handleConnection(conn)
}
}
func (p Proxy) handleConnection(inbound net.Conn) {
defer inbound.Close()
outbound, err := net.Dial("tcp", p.target)
if err != nil {
p.logger.Error("Cannot connect to remote broker " + p.target)
return
}
defer outbound.Close()
c := session.New(inbound, outbound, p.event, p.logger)
if err := c.Stream(); err != io.EOF {
p.logger.Warn("Broken connection for client: " + c.Client.ID + " with error: " + err.Error())
}
}
// Proxy of the server, this will block.
func (p Proxy) Proxy() error {
l, err := net.Listen("tcp", p.address)
if err != nil {
return err
}
defer l.Close()
// Acceptor loop
p.accept(l)
p.logger.Info("Server Exiting...")
return nil
}

View File

@ -1,75 +0,0 @@
package mqtt
import (
"fmt"
"io"
"net"
"github.com/mainflux/mainflux/logger"
)
// Proxy is main MQTT proxy struct
type Proxy struct {
host string
port string
target string
event Event
logger logger.Logger
}
// New will setup a new Proxy struct after parsing the options
func New(host, port, targetHost, targetPort string, event Event, logger logger.Logger) *Proxy {
return &Proxy{
host: host,
port: port,
target: fmt.Sprintf("%s:%s", targetHost, targetPort),
event: event,
logger: logger,
}
}
func (p *Proxy) accept(l net.Listener) {
for {
conn, err := l.Accept()
if err != nil {
p.logger.Warn("Accept error " + err.Error())
continue
}
p.logger.Info("Accepted new client")
go p.handleConnection(conn)
}
}
func (p *Proxy) handleConnection(inbound net.Conn) {
defer inbound.Close()
outbound, err := net.Dial("tcp", p.target)
if err != nil {
p.logger.Error("Cannot connect to remote broker " + p.target)
return
}
defer outbound.Close()
s := newSession(inbound, outbound, p.event, p.logger)
if err := s.stream(); err != io.EOF {
p.logger.Warn("Exited session for client " + s.client.ID + " with error: " + err.Error())
}
s.logger.Info("Session for client " + s.client.ID + " closed: " + s.outbound.LocalAddr().String())
}
// Proxy of the server, this will block.
func (p *Proxy) Proxy() error {
addr := fmt.Sprintf("%s:%s", p.host, p.port)
l, err := net.Listen("tcp", addr)
if err != nil {
return err
}
defer l.Close()
// Acceptor loop
p.accept(l)
p.logger.Info("Server Exiting...")
return nil
}

View File

@ -1,4 +1,4 @@
package mqtt
package session
// Client stores MQTT client data.
type Client struct {

View File

@ -1,4 +1,4 @@
package mqtt
package session
// Event is an interface for mProxy hooks
type Event interface {

View File

@ -1,4 +1,4 @@
package mqtt
package session
import (
"net"
@ -14,16 +14,16 @@ const (
type direction int
type session struct {
type Session struct {
logger logger.Logger
inbound net.Conn
outbound net.Conn
event Event
client Client
Client Client
}
func newSession(inbound, outbound net.Conn, event Event, logger logger.Logger) *session {
return &session{
func New(inbound, outbound net.Conn, event Event, logger logger.Logger) *Session {
return &Session{
logger: logger,
inbound: inbound,
outbound: outbound,
@ -31,20 +31,20 @@ func newSession(inbound, outbound net.Conn, event Event, logger logger.Logger) *
}
}
func (s *session) stream() error {
func (s Session) Stream() error {
// In parallel read from client, send to broker
// and read from broker, send to client
errs := make(chan error, 2)
go s.streamUnidir(up, s.inbound, s.outbound, errs)
go s.streamUnidir(down, s.outbound, s.inbound, errs)
go s.stream(up, s.inbound, s.outbound, errs)
go s.stream(down, s.outbound, s.inbound, errs)
err := <-errs
s.event.Disconnect(&s.client)
s.event.Disconnect(&s.Client)
return err
}
func (s *session) streamUnidir(dir direction, r, w net.Conn, errs chan error) {
func (s Session) stream(dir direction, r, w net.Conn, errs chan error) {
for {
// Read from one connection
pkt, err := packets.ReadPacket(r)
@ -72,42 +72,42 @@ func (s *session) streamUnidir(dir direction, r, w net.Conn, errs chan error) {
}
}
func (s *session) authorize(pkt packets.ControlPacket) error {
func (s *Session) authorize(pkt packets.ControlPacket) error {
switch p := pkt.(type) {
case *packets.ConnectPacket:
s.client = Client{
s.Client = Client{
ID: p.ClientIdentifier,
Username: p.Username,
Password: p.Password,
}
if err := s.event.AuthConnect(&s.client); err != nil {
if err := s.event.AuthConnect(&s.Client); err != nil {
return err
}
// Copy back to the packet in case values are changed by Event handler.
// This is specific to CONN, as only that package type has credentials.
p.ClientIdentifier = s.client.ID
p.Username = s.client.Username
p.Password = s.client.Password
p.ClientIdentifier = s.Client.ID
p.Username = s.Client.Username
p.Password = s.Client.Password
return nil
case *packets.PublishPacket:
return s.event.AuthPublish(&s.client, &p.TopicName, &p.Payload)
return s.event.AuthPublish(&s.Client, &p.TopicName, &p.Payload)
case *packets.SubscribePacket:
return s.event.AuthSubscribe(&s.client, &p.Topics)
return s.event.AuthSubscribe(&s.Client, &p.Topics)
default:
return nil
}
}
func (s *session) notify(pkt packets.ControlPacket) {
func (s Session) notify(pkt packets.ControlPacket) {
switch p := pkt.(type) {
case *packets.ConnectPacket:
s.event.Connect(&s.client)
s.event.Connect(&s.Client)
case *packets.PublishPacket:
s.event.Publish(&s.client, &p.TopicName, &p.Payload)
s.event.Publish(&s.Client, &p.TopicName, &p.Payload)
case *packets.SubscribePacket:
s.event.Subscribe(&s.client, &p.Topics)
s.event.Subscribe(&s.Client, &p.Topics)
case *packets.UnsubscribePacket:
s.event.Unsubscribe(&s.client, &p.Topics)
s.event.Unsubscribe(&s.Client, &p.Topics)
default:
return
}

View File

@ -0,0 +1,78 @@
package websocket
import (
"io"
"net"
"sync"
"time"
"github.com/gorilla/websocket"
)
// wsWrapper is a websocket wrapper so it satisfies the net.Conn interface.
type wsWrapper struct {
*websocket.Conn
r io.Reader
rio sync.Mutex
wio sync.Mutex
}
func newConn(ws *websocket.Conn) net.Conn {
wrapper := &wsWrapper{
Conn: ws,
}
return wrapper
}
// SetDeadline sets both the read and write deadlines
func (c *wsWrapper) SetDeadline(t time.Time) error {
if err := c.SetReadDeadline(t); err != nil {
return err
}
err := c.SetWriteDeadline(t)
return err
}
// Write writes data to the websocket
func (c *wsWrapper) Write(p []byte) (int, error) {
c.wio.Lock()
defer c.wio.Unlock()
err := c.WriteMessage(websocket.BinaryMessage, p)
if err != nil {
return 0, err
}
return len(p), nil
}
// Read reads the current websocket frame
func (c *wsWrapper) Read(p []byte) (int, error) {
c.rio.Lock()
defer c.rio.Unlock()
for {
if c.r == nil {
// Advance to next message.
var err error
_, c.r, err = c.NextReader()
if err != nil {
return 0, err
}
}
n, err := c.r.Read(p)
if err == io.EOF {
// At end of message.
c.r = nil
if n > 0 {
return n, nil
}
// No data read, continue to next message.
continue
}
return n, err
}
}
func (c *wsWrapper) Close() error {
return c.Conn.Close()
}

View File

@ -0,0 +1,89 @@
package websocket
import (
"net/http"
"net/url"
"time"
"github.com/gorilla/websocket"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mproxy/pkg/session"
)
// New - creates new HTTP proxy
type Proxy struct {
target string
path string
scheme string
event session.Event
logger logger.Logger
}
func New(target, path, scheme string, event session.Event, logger logger.Logger) *Proxy {
return &Proxy{
target: target,
path: path,
scheme: scheme,
event: event,
logger: logger,
}
}
var upgrader = websocket.Upgrader{
// Timeout for WS upgrade request handshake
HandshakeTimeout: 10 * time.Second,
// Paho JS client expecting header Sec-WebSocket-Protocol:mqtt in Upgrade response during handshake.
Subprotocols: []string{"mqtt"},
// Allow CORS
CheckOrigin: func(r *http.Request) bool {
return true
},
}
// Handle - proxies HTTP traffic
func (p Proxy) Handler() http.Handler {
return p.handle()
}
func (p Proxy) handle() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
cconn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
p.logger.Error("Error upgrading connection " + err.Error())
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
go p.pass(cconn)
})
}
func (p Proxy) pass(in *websocket.Conn) {
defer in.Close()
url := url.URL{
Scheme: p.scheme,
Host: p.target,
Path: p.path,
}
srv, _, err := websocket.DefaultDialer.Dial(url.String(), nil)
if err != nil {
p.logger.Error("Unable to connect to broker, reason: " + err.Error())
return
}
errc := make(chan error, 1)
c := newConn(in)
s := newConn(srv)
defer s.Close()
defer c.Close()
session := session.New(c, s, p.event, p.logger)
err = session.Stream()
errc <- err
p.logger.Warn("Broken connection for client: " + session.Client.ID + " with error: " + err.Error())
}

4
vendor/modules.txt vendored
View File

@ -122,8 +122,10 @@ github.com/lib/pq
github.com/lib/pq/oid
# github.com/magiconair/properties v1.8.1
github.com/magiconair/properties
# github.com/mainflux/mproxy v0.1.3
# github.com/mainflux/mproxy v0.1.5
github.com/mainflux/mproxy/pkg/mqtt
github.com/mainflux/mproxy/pkg/session
github.com/mainflux/mproxy/pkg/websocket
# github.com/mainflux/senml v1.0.1
github.com/mainflux/senml
# github.com/mattn/go-colorable v0.0.9