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

207 lines
5.3 KiB
Go
Raw Normal View History

MF-415 - Merge mProxy support (#1045) * NOISSUE - Add mProxy support (#1017) * Add mproxy Signed-off-by: Drasko DRASKOVIC <drasko.draskovic@gmail.com> * Fix docker and add EMQ compose Signed-off-by: Drasko DRASKOVIC <drasko.draskovic@gmail.com> * Fix EMQX name Signed-off-by: Drasko DRASKOVIC <drasko.draskovic@gmail.com> * Add nats, auth and es Signed-off-by: Drasko DRASKOVIC <drasko.draskovic@gmail.com> * Removed unucessary vendoring Signed-off-by: Drasko Draskovic <drasko.draskovic@gmail.com> * Update vendoring Signed-off-by: Drasko Draskovic <drasko.draskovic@gmail.com> * Fix mproxy interface implementation Signed-off-by: Drasko Draskovic <drasko.draskovic@gmail.com> NOISSUE - Aligned Event interface method signatures with new spec (#1025) * Aligned Event interface method signatures with new spec Signed-off-by: Nikola Marcetic <n.marcetic86@gmail.com> * Updated deps Signed-off-by: Nikola Marcetic <n.marcetic86@gmail.com> NOISSUE - Update mproxy dependency (#1038) Signed-off-by: Nikola Marcetic <n.marcetic86@gmail.com> Update Vendor with new mProxy (#1043) Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> Twins merge conflict reverted Signed-off-by: Nikola Marcetic <n.marcetic86@gmail.com> Twins merge conflict reverted Signed-off-by: Nikola Marcetic <n.marcetic86@gmail.com> Twins fixed nats import Signed-off-by: Nikola Marcetic <n.marcetic86@gmail.com> Update deps Signed-off-by: Nikola Marcetic <n.marcetic86@gmail.com> * Resolved GolangCI remarks Signed-off-by: Nikola Marcetic <n.marcetic86@gmail.com> Resolved GolangCI remarks Signed-off-by: Nikola Marcetic <n.marcetic86@gmail.com> Resolved GolangCI remarks Signed-off-by: Nikola Marcetic <n.marcetic86@gmail.com> * Fixed Event interface Unsubscribe() typo Signed-off-by: Nikola Marcetic <n.marcetic86@gmail.com> * Update vendors Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Upgrade CI script Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> Co-authored-by: Drasko DRASKOVIC <drasko.draskovic@gmail.com> Co-authored-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>
2020-02-26 17:14:16 +01:00
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
package mproxy
import (
"context"
"errors"
"fmt"
"net/url"
"regexp"
"strings"
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/mqtt/mproxy/redis"
"github.com/mainflux/mproxy/pkg/events"
opentracing "github.com/opentracing/opentracing-go"
)
var (
_ events.Event = (*Event)(nil)
channelRegExp = regexp.MustCompile(`^\/?channels\/([\w\-]+)\/messages(\/[^?]*)?(\?.*)?$`)
ctRegExp = regexp.MustCompile(`^(\/.*)?\/ct\/([^\/]+)$`)
errMalformedTopic = errors.New("malformed topic")
errMalformedData = errors.New("malformed request data")
errMalformedSubtopic = errors.New("malformed subtopic")
)
// Event implements events.Event interface
type Event struct {
tc mainflux.ThingsServiceClient
mp mainflux.MessagePublisher
tracer opentracing.Tracer
logger logger.Logger
es redis.EventStore
}
// New creates new Event entity
func New(tc mainflux.ThingsServiceClient, mp mainflux.MessagePublisher, es redis.EventStore,
logger logger.Logger, tracer opentracing.Tracer) *Event {
return &Event{
tc: tc,
mp: mp,
es: es,
tracer: tracer,
logger: logger,
}
}
// AuthRegister is called on device connection,
// prior forwarding to the MQTT broker
func (e *Event) AuthRegister(username, clientID *string, password *[]byte) error {
e.logger.Info(fmt.Sprintf("AuthRegister() - clientID: %s, username: %s",
*clientID, *username))
t := &mainflux.Token{
Value: string(*password),
}
thid, err := e.tc.Identify(context.TODO(), t)
if err != nil {
return err
}
if thid.Value != *username {
return err
}
return nil
}
func (e *Event) authAccess(username string, topic string) error {
// Topics are in the format:
// channels/<channel_id>/messages/<subtopic>/.../ct/<content_type>
if !channelRegExp.Match([]byte(topic)) {
e.logger.Info(fmt.Sprintf("Malformed topic %s", topic))
return errMalformedTopic
}
channelParts := channelRegExp.FindStringSubmatch(topic)
if len(channelParts) < 1 {
return errMalformedData
}
chanID := channelParts[1]
ar := &mainflux.AccessByIDReq{
ThingID: username,
ChanID: chanID,
}
_, err := e.tc.CanAccessByID(context.TODO(), ar)
if err != nil {
return err
}
return nil
}
// AuthPublish is called on device publish,
// prior forwarding to the MQTT broker
func (e *Event) AuthPublish(username, clientID string, topic *string, payload *[]byte) error {
e.logger.Info(fmt.Sprintf("AuthPublish() - clientID: %s, topic: %s", clientID, *topic))
return e.authAccess(username, *topic)
}
// AuthSubscribe is called on device publish,
// prior forwarding to the MQTT broker
func (e *Event) AuthSubscribe(username, clientID string, topics *[]string) error {
e.logger.Info(fmt.Sprintf("AuthSubscribe() - clientID: %s, topics: %s", clientID, strings.Join(*topics, ",")))
for _, v := range *topics {
if err := e.authAccess(username, v); err != nil {
return err
}
}
return nil
}
// Register - after client sucesfully connected
func (e *Event) Register(clientID string) {
e.logger.Info(fmt.Sprintf("Register() - clientID: %s", clientID))
}
func parseSubtopic(subtopic string) (string, error) {
if subtopic == "" {
return subtopic, nil
}
subtopic, err := url.QueryUnescape(subtopic)
if err != nil {
return "", errMalformedSubtopic
}
subtopic = strings.Replace(subtopic, "/", ".", -1)
elems := strings.Split(subtopic, ".")
filteredElems := []string{}
for _, elem := range elems {
if elem == "" {
continue
}
if len(elem) > 1 && (strings.Contains(elem, "*") || strings.Contains(elem, ">")) {
return "", errMalformedSubtopic
}
filteredElems = append(filteredElems, elem)
}
subtopic = strings.Join(filteredElems, ".")
return subtopic, nil
}
// Publish - after client sucesfully published
func (e *Event) Publish(clientID, topic string, payload []byte) {
e.logger.Info(fmt.Sprintf("Publish() - clientID: %s, topic: %s", clientID, topic))
// Topics are in the format:
// channels/<channel_id>/messages/<subtopic>/.../ct/<content_type>
channelParts := channelRegExp.FindStringSubmatch(topic)
if len(channelParts) < 1 {
e.logger.Info(fmt.Sprintf("Error in mqtt publish %s", errMalformedData))
return
}
chanID := channelParts[1]
subtopic := channelParts[2]
ct := ""
if stParts := ctRegExp.FindStringSubmatch(subtopic); len(stParts) > 1 {
ct = stParts[2]
subtopic = stParts[1]
}
subtopic, err := parseSubtopic(subtopic)
if err != nil {
e.logger.Info(fmt.Sprintf("Error in mqtt publish %s", err))
return
}
msg := mainflux.Message{
Protocol: "mqtt",
ContentType: ct,
Channel: chanID,
Subtopic: subtopic,
Payload: payload,
}
if err := e.mp.Publish(context.TODO(), "", msg); err != nil {
e.logger.Info(fmt.Sprintf("Error in mqtt publish %s", err))
return
}
}
// Subscribe - after client sucesfully subscribed
func (e *Event) Subscribe(clientID string, topics []string) {
e.logger.Info(fmt.Sprintf("Subscribe() - clientID: %s, topics: %s", clientID, strings.Join(topics, ",")))
}
// Unubscribe - after client unsubscribed
func (e *Event) Unsubscribe(clientID string, topics []string) {
e.logger.Info(fmt.Sprintf("Unubscribe() - clientID: %s, topics: %s", clientID, strings.Join(topics, ",")))
}