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

* update WS service to mproxy Signed-off-by: SammyOina <sammyoina@gmail.com> * Fix brokerstracing initialization in main.go The commit fixes the initialization of the brokerstracing package in the main.go file. The target server configuration is now correctly passed to the NewPubSub function, ensuring that the correct host and port are used for the PubSub service. This resolves an issue where the wrong server configuration was being used, leading to incorrect behavior. Signed-off-by: SammyOina <sammyoina@gmail.com> * Fix goroutine issue in main.go The commit fixes a goroutine issue in the main.go file. Previously, the `hs.Start()` function was not being executed in a goroutine, which caused the program to block. This commit wraps the `hs.Start()` function call in a goroutine to ensure it runs concurrently. This resolves the issue and allows the program to continue execution without blocking. Signed-off-by: SammyOina <sammyoina@gmail.com> * update to current mproxy Signed-off-by: SammyOina <sammyoina@gmail.com> * update dependencies Signed-off-by: SammyOina <sammyoina@gmail.com> * Fix targetWSHost value in proxyWS function The targetWSHost value in the proxyWS function was empty. This commit fixes the issue by setting the targetWSHost value to "localhost". Additionally, the target variable in the proxyWS function is updated to include the "ws://" protocol prefix. Signed-off-by: SammyOina <sammyoina@gmail.com> * update deps Signed-off-by: SammyOina <sammyoina@gmail.com> * remove authorize from unsubscribe Signed-off-by: SammyOina <sammyoina@gmail.com> --------- Signed-off-by: SammyOina <sammyoina@gmail.com>
126 lines
2.8 KiB
Go
126 lines
2.8 KiB
Go
// Copyright (c) Mainflux
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package api
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/go-zoo/bone"
|
|
"github.com/mainflux/mainflux/pkg/errors"
|
|
"github.com/mainflux/mainflux/ws"
|
|
)
|
|
|
|
var channelPartRegExp = regexp.MustCompile(`^/channels/([\w\-]+)/messages(/[^?]*)?(\?.*)?$`)
|
|
|
|
func handshake(ctx context.Context, svc ws.Service) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
req, err := decodeRequest(r)
|
|
if err != nil {
|
|
encodeError(w, err)
|
|
return
|
|
}
|
|
conn, err := upgrader.Upgrade(w, r, nil)
|
|
if err != nil {
|
|
logger.Warn(fmt.Sprintf("Failed to upgrade connection to websocket: %s", err.Error()))
|
|
return
|
|
}
|
|
req.conn = conn
|
|
client := ws.NewClient(conn)
|
|
|
|
if err := svc.Subscribe(ctx, req.thingKey, req.chanID, req.subtopic, client); err != nil {
|
|
req.conn.Close()
|
|
return
|
|
}
|
|
|
|
logger.Debug(fmt.Sprintf("Successfully upgraded communication to WS on channel %s", req.chanID))
|
|
}
|
|
}
|
|
|
|
func decodeRequest(r *http.Request) (connReq, error) {
|
|
authKey := r.Header.Get("Authorization")
|
|
if authKey == "" {
|
|
authKeys := bone.GetQuery(r, "authorization")
|
|
if len(authKeys) == 0 {
|
|
logger.Debug("Missing authorization key.")
|
|
return connReq{}, errUnauthorizedAccess
|
|
}
|
|
authKey = authKeys[0]
|
|
}
|
|
|
|
chanID := bone.GetValue(r, "chanID")
|
|
|
|
req := connReq{
|
|
thingKey: authKey,
|
|
chanID: chanID,
|
|
}
|
|
|
|
channelParts := channelPartRegExp.FindStringSubmatch(r.RequestURI)
|
|
if len(channelParts) < 2 {
|
|
logger.Warn("Empty channel id or malformed url")
|
|
return connReq{}, errors.ErrMalformedEntity
|
|
}
|
|
|
|
subtopic, err := parseSubTopic(channelParts[2])
|
|
if err != nil {
|
|
return connReq{}, err
|
|
}
|
|
|
|
req.subtopic = subtopic
|
|
|
|
return req, nil
|
|
}
|
|
|
|
func parseSubTopic(subtopic string) (string, error) {
|
|
if subtopic == "" {
|
|
return subtopic, nil
|
|
}
|
|
|
|
subtopic, err := url.QueryUnescape(subtopic)
|
|
if err != nil {
|
|
return "", errMalformedSubtopic
|
|
}
|
|
|
|
subtopic = strings.ReplaceAll(subtopic, "/", ".")
|
|
|
|
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
|
|
}
|
|
|
|
func encodeError(w http.ResponseWriter, err error) {
|
|
var statusCode int
|
|
|
|
switch err {
|
|
case ws.ErrEmptyID, ws.ErrEmptyTopic:
|
|
statusCode = http.StatusBadRequest
|
|
case errUnauthorizedAccess:
|
|
statusCode = http.StatusForbidden
|
|
case errMalformedSubtopic, errors.ErrMalformedEntity:
|
|
statusCode = http.StatusBadRequest
|
|
default:
|
|
statusCode = http.StatusNotFound
|
|
}
|
|
logger.Warn(fmt.Sprintf("Failed to authorize: %s", err.Error()))
|
|
w.WriteHeader(statusCode)
|
|
}
|