mirror of
https://github.com/mainflux/mainflux.git
synced 2025-04-24 13:48:49 +08:00
146 lines
3.1 KiB
Go
146 lines
3.1 KiB
Go
![]() |
// Copyright (c) Mainflux
|
||
|
// SPDX-License-Identifier: Apache-2.0
|
||
|
|
||
|
package nats
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"encoding/json"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"time"
|
||
|
|
||
|
mflog "github.com/mainflux/mainflux/logger"
|
||
|
"github.com/mainflux/mainflux/pkg/events"
|
||
|
"github.com/mainflux/mainflux/pkg/messaging"
|
||
|
broker "github.com/mainflux/mainflux/pkg/messaging/nats"
|
||
|
"github.com/nats-io/nats.go"
|
||
|
"github.com/nats-io/nats.go/jetstream"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
maxReconnects = -1
|
||
|
)
|
||
|
|
||
|
var _ events.Subscriber = (*subEventStore)(nil)
|
||
|
|
||
|
var (
|
||
|
eventsPrefix = "events"
|
||
|
|
||
|
jsStreamConfig = jetstream.StreamConfig{
|
||
|
Name: "events",
|
||
|
Description: "Mainflux stream for sending and receiving messages in between Mainflux events",
|
||
|
Subjects: []string{"events.>"},
|
||
|
Retention: jetstream.LimitsPolicy,
|
||
|
MaxMsgsPerSubject: 1e9,
|
||
|
MaxAge: time.Hour * 24,
|
||
|
MaxMsgSize: 1024 * 1024,
|
||
|
Discard: jetstream.DiscardOld,
|
||
|
Storage: jetstream.FileStorage,
|
||
|
}
|
||
|
|
||
|
// ErrEmptyStream is returned when stream name is empty.
|
||
|
ErrEmptyStream = errors.New("stream name cannot be empty")
|
||
|
|
||
|
// ErrEmptyConsumer is returned when consumer name is empty.
|
||
|
ErrEmptyConsumer = errors.New("consumer name cannot be empty")
|
||
|
)
|
||
|
|
||
|
type subEventStore struct {
|
||
|
conn *nats.Conn
|
||
|
pubsub messaging.PubSub
|
||
|
stream string
|
||
|
consumer string
|
||
|
logger mflog.Logger
|
||
|
}
|
||
|
|
||
|
func NewSubscriber(ctx context.Context, url, stream, consumer string, logger mflog.Logger) (events.Subscriber, error) {
|
||
|
if stream == "" {
|
||
|
return nil, ErrEmptyStream
|
||
|
}
|
||
|
|
||
|
if consumer == "" {
|
||
|
return nil, ErrEmptyConsumer
|
||
|
}
|
||
|
|
||
|
conn, err := nats.Connect(url, nats.MaxReconnects(maxReconnects))
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
js, err := jetstream.New(conn)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
jsStream, err := js.CreateStream(ctx, jsStreamConfig)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
pubsub, err := broker.NewPubSub(ctx, url, logger, broker.Stream(jsStream))
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return &subEventStore{
|
||
|
conn: conn,
|
||
|
pubsub: pubsub,
|
||
|
stream: stream,
|
||
|
consumer: consumer,
|
||
|
logger: logger,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
func (es *subEventStore) Subscribe(ctx context.Context, handler events.EventHandler) error {
|
||
|
subCfg := messaging.SubscriberConfig{
|
||
|
ID: es.consumer,
|
||
|
Topic: eventsPrefix + "." + es.stream,
|
||
|
Handler: &eventHandler{
|
||
|
handler: handler,
|
||
|
ctx: ctx,
|
||
|
logger: es.logger,
|
||
|
},
|
||
|
DeliveryPolicy: messaging.DeliverNewPolicy,
|
||
|
}
|
||
|
|
||
|
return es.pubsub.Subscribe(ctx, subCfg)
|
||
|
}
|
||
|
|
||
|
func (es *subEventStore) Close() error {
|
||
|
es.conn.Close()
|
||
|
return es.pubsub.Close()
|
||
|
}
|
||
|
|
||
|
type event struct {
|
||
|
Data map[string]interface{}
|
||
|
}
|
||
|
|
||
|
func (re event) Encode() (map[string]interface{}, error) {
|
||
|
return re.Data, nil
|
||
|
}
|
||
|
|
||
|
type eventHandler struct {
|
||
|
handler events.EventHandler
|
||
|
ctx context.Context
|
||
|
logger mflog.Logger
|
||
|
}
|
||
|
|
||
|
func (eh *eventHandler) Handle(msg *messaging.Message) error {
|
||
|
event := event{
|
||
|
Data: make(map[string]interface{}),
|
||
|
}
|
||
|
|
||
|
if err := json.Unmarshal(msg.GetPayload(), &event.Data); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if err := eh.handler.Handle(eh.ctx, event); err != nil {
|
||
|
eh.logger.Warn(fmt.Sprintf("failed to handle redis event: %s", err))
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (eh *eventHandler) Cancel() error {
|
||
|
return nil
|
||
|
}
|