1
0
mirror of https://github.com/mainflux/mainflux.git synced 2025-05-11 19:29:16 +08:00
Darko Draskovic 340e685d70
MF-1180 - Add redis based twins and states cache (#1184)
* Add twins redis cache

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add connectToRedis to twins main and twinCache to twins service

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add tracing to twins cache

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add twins cache mock and test setup for redis cache

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add TestTwinSave to redis twins cache tests

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add remove twin redis cache test

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add channels param to CreateDefinition helper method in mocks

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add IDs test to redis twins cache

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Simplify senml rec array and attribute creation funcs by removing unnecessary params

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Align cache remove twin method with service remove twin method

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add cache funcs to twins save, update and remove

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add def SaveIDs to redis cache and ref to service SaveStates

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add TwinSaveIDs tests for redis cache

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add cache related env vars desc to README.md

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add twinid bson key constant

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add Update method to cache

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Integrate uuid unification related changes

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Use named arguments in interface method declarations

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add env vars to docker-compose file

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Make parameter names in interface methods and implementations consistent

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Wrap vars and consts in var and const blocks

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2020-06-05 11:42:16 +02:00

124 lines
3.3 KiB
Go

// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
package redis
import (
"context"
"fmt"
"github.com/go-redis/redis"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/twins"
)
const (
prefix = "twin"
)
var (
// ErrRedisTwinSave indicates error while saving Twin in redis cache
ErrRedisTwinSave = errors.New("failed to save twin in redis cache")
// ErrRedisTwinUpdate indicates error while saving Twin in redis cache
ErrRedisTwinUpdate = errors.New("failed to update twin in redis cache")
// ErrRedisTwinIDs indicates error while geting Twin IDs from redis cache
ErrRedisTwinIDs = errors.New("failed to get twin id from redis cache")
// ErrRedisTwinRemove indicates error while removing Twin from redis cache
ErrRedisTwinRemove = errors.New("failed to remove twin from redis cache")
)
var _ twins.TwinCache = (*twinCache)(nil)
type twinCache struct {
client *redis.Client
}
// NewTwinCache returns redis twin cache implementation.
func NewTwinCache(client *redis.Client) twins.TwinCache {
return &twinCache{
client: client,
}
}
func (tc *twinCache) Save(_ context.Context, twin twins.Twin) error {
return tc.save(twin)
}
func (tc *twinCache) Update(_ context.Context, twin twins.Twin) error {
if err := tc.remove(twin.ID); err != nil {
return errors.Wrap(ErrRedisTwinUpdate, err)
}
if err := tc.save(twin); err != nil {
return errors.Wrap(ErrRedisTwinUpdate, err)
}
return nil
}
func (tc *twinCache) SaveIDs(_ context.Context, channel, subtopic string, ids []string) error {
for _, id := range ids {
if err := tc.client.SAdd(attrKey(channel, subtopic), id).Err(); err != nil {
return errors.Wrap(ErrRedisTwinSave, err)
}
if err := tc.client.SAdd(twinKey(id), attrKey(channel, subtopic)).Err(); err != nil {
return errors.Wrap(ErrRedisTwinSave, err)
}
}
return nil
}
func (tc *twinCache) IDs(_ context.Context, channel, subtopic string) ([]string, error) {
ids, err := tc.client.SMembers(attrKey(channel, subtopic)).Result()
if err != nil {
return nil, errors.Wrap(ErrRedisTwinIDs, err)
}
return ids, nil
}
func (tc *twinCache) Remove(_ context.Context, twinID string) error {
return tc.remove(twinID)
}
func (tc *twinCache) save(twin twins.Twin) error {
if len(twin.Definitions) < 1 {
return nil
}
attributes := twin.Definitions[len(twin.Definitions)-1].Attributes
for _, attr := range attributes {
if err := tc.client.SAdd(attrKey(attr.Channel, attr.Subtopic), twin.ID).Err(); err != nil {
return errors.Wrap(ErrRedisTwinSave, err)
}
if err := tc.client.SAdd(twinKey(twin.ID), attrKey(attr.Channel, attr.Subtopic)).Err(); err != nil {
return errors.Wrap(ErrRedisTwinSave, err)
}
}
return nil
}
func (tc *twinCache) remove(twinID string) error {
twinKey := twinKey(twinID)
attrKeys, err := tc.client.SMembers(twinKey).Result()
if err != nil {
return errors.Wrap(ErrRedisTwinRemove, err)
}
if err := tc.client.Del(twinKey).Err(); err != nil {
return errors.Wrap(ErrRedisTwinRemove, err)
}
for _, attrKey := range attrKeys {
if err := tc.client.SRem(attrKey, twinID).Err(); err != nil {
return errors.Wrap(ErrRedisTwinRemove, err)
}
}
return nil
}
func twinKey(twinID string) string {
return fmt.Sprintf("%s:%s", prefix, twinID)
}
func attrKey(channel, subtopic string) string {
return fmt.Sprintf("%s:%s-%s", prefix, channel, subtopic)
}