1
0
mirror of https://github.com/mainflux/mainflux.git synced 2025-05-01 13:48:56 +08:00
Mainflux.mainflux/ws/adapter.go
Manuel Imperiale fff492bd50
NOISSUE - Create broker package for NATS (#1080)
* NOISSUEE - Create broker package for NATS

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Create funcs to return NATS connection

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* mv os.exit to main

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix Reviews

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix tests and typos

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix CI

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix reviews

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Unify Publisher and Subscriber interfaces

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Rename Nats interface

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* typo

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Mv message.pb.go, messsage.proto and topics.go to broker directory

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix go.mod

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Use mainflux broker for writers and twins services

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix go.mod

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix twins tests

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix make proto

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix message.proto

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix golangcibot

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* regenerate message.pb.go

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix comment

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix comment

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix make proto

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Add NATS errors

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>
2020-04-01 21:22:13 +02:00

141 lines
3.3 KiB
Go

// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
// Package ws contains the domain concept definitions needed to support
// Mainflux ws adapter service functionality.
package ws
import (
"context"
"errors"
"fmt"
"sync"
"github.com/gogo/protobuf/proto"
"github.com/mainflux/mainflux/broker"
"github.com/mainflux/mainflux/logger"
"github.com/nats-io/nats.go"
)
var (
// ErrFailedMessagePublish indicates that message publishing failed.
ErrFailedMessagePublish = errors.New("failed to publish message")
// ErrFailedSubscription indicates that client couldn't subscribe to specified channel.
ErrFailedSubscription = errors.New("failed to subscribe to a channel")
// ErrFailedConnection indicates that service couldn't connect to message broker.
ErrFailedConnection = errors.New("failed to connect to message broker")
)
// Service specifies web socket service API.
type Service interface {
// Publish Messssage
Publish(context.Context, string, broker.Message) error
// Subscribes to channel with specified id.
Subscribe(string, string, *Channel) error
}
// Channel is used for receiving and sending messages.
type Channel struct {
Messages chan broker.Message
Closed chan bool
closed bool
mutex sync.Mutex
}
// NewChannel instantiates empty channel.
func NewChannel() *Channel {
return &Channel{
Messages: make(chan broker.Message),
Closed: make(chan bool),
closed: false,
mutex: sync.Mutex{},
}
}
// Send method send message over Messages channel.
func (channel *Channel) Send(msg broker.Message) {
channel.mutex.Lock()
defer channel.mutex.Unlock()
if !channel.closed {
channel.Messages <- msg
}
}
// Close channel and stop message transfer.
func (channel *Channel) Close() {
channel.mutex.Lock()
defer channel.mutex.Unlock()
channel.closed = true
channel.Closed <- true
close(channel.Messages)
close(channel.Closed)
}
var _ Service = (*adapterService)(nil)
type adapterService struct {
broker broker.Nats
log logger.Logger
}
// New instantiates the WS adapter implementation.
func New(broker broker.Nats, log logger.Logger) Service {
return &adapterService{
broker: broker,
log: log,
}
}
func (as *adapterService) Publish(ctx context.Context, token string, msg broker.Message) error {
if err := as.broker.Publish(ctx, token, msg); err != nil {
switch err {
case nats.ErrConnectionClosed, nats.ErrInvalidConnection:
return ErrFailedConnection
default:
return ErrFailedMessagePublish
}
}
return nil
}
func (as *adapterService) Subscribe(chanID, subtopic string, channel *Channel) error {
subject := chanID
if subtopic != "" {
subject = fmt.Sprintf("%s.%s", chanID, subtopic)
}
sub, err := as.broker.Subscribe(subject, func(msg *nats.Msg) {
if msg == nil {
as.log.Warn("Received nil message")
return
}
m := broker.Message{}
if err := proto.Unmarshal(msg.Data, &m); err != nil {
as.log.Warn(fmt.Sprintf("Failed to deserialize received message: %s", err.Error()))
return
}
as.log.Debug(fmt.Sprintf("Successfully received message from NATS from channel %s", m.GetChannel()))
// Sends message to messages channel
channel.Send(m)
})
// Check if subscription should be closed
go func() {
<-channel.Closed
if err := sub.Unsubscribe(); err != nil {
as.log.Error(fmt.Sprintf("Failed to unsubscribe from %s.%s", chanID, subtopic))
}
}()
return err
}