bnkamalesh/verifier

View on GitHub
stores/redis.go

Summary

Maintainability
A
2 hrs
Test Coverage
package stores

import (
    "fmt"
    "time"

    "github.com/go-redis/redis"
    "github.com/vmihailenco/msgpack/v4"

    "github.com/bnkamalesh/verifier"
)

// RedisConfig holds all the configuration required for the redis handler
type RedisConfig struct {
    Hosts            []string      `json:"hosts,omitempty"`
    Username         string        `json:"username,omitempty"`
    Password         string        `json:"password,omitempty"`
    DialTimeoutSecs  time.Duration `json:"dialTimeoutSecs,omitempty"`
    ReadTimeoutSecs  time.Duration `json:"readTimeoutSecs,omitempty"`
    WriteTimeoutSecs time.Duration `json:"writeTimeoutSecs,omitempty"`
}

// Redis struct exposes all the store functionalities required for verifier
type Redis struct {
    client redis.UniversalClient
}

// Create creates a new entry of the verification request in the store
func (ris *Redis) Create(ver *verifier.Request) (*verifier.Request, error) {
    key := fmt.Sprintf(
        "%s-%s",
        ver.Type,
        ver.Recipient,
    )

    now := time.Now()
    expiry := ver.SecretExpiry.Sub(now)

    payload, err := msgpack.Marshal(ver)
    if err != nil {
        return nil, err
    }

    resp := ris.client.Set(
        key,
        payload,
        expiry,
    )

    err = resp.Err()
    if err != nil {
        return nil, err
    }

    return ver, nil
}

// ReadLastPending reads the last pending verification request of the commtype + recipient
func (ris *Redis) ReadLastPending(ctype verifier.CommType, recipient string) (*verifier.Request, error) {
    key := fmt.Sprintf(
        "%s-%s",
        ctype,
        recipient,
    )

    resp := ris.client.Get(key)
    err := resp.Err()
    if err != nil {
        return nil, err
    }

    b, err := resp.Bytes()
    if err != nil {
        return nil, err
    }

    ver := &verifier.Request{}
    err = msgpack.Unmarshal(b, ver)
    if err != nil {
        return nil, err
    }

    return ver, nil
}

// Update updates a verification request for the given verification ID & the payload
func (ris *Redis) Update(verID string, ver *verifier.Request) (*verifier.Request, error) {
    key := fmt.Sprintf(
        "%s-%s",
        ver.Type,
        ver.Recipient,
    )
    now := time.Now()
    expiry := ver.SecretExpiry.Sub(now)

    payload, err := msgpack.Marshal(ver)
    if err != nil {
        return nil, err
    }

    resp := ris.client.Set(
        key,
        payload,
        expiry,
    )

    err = resp.Err()
    if err != nil {
        return nil, err
    }

    return nil, nil
}

// NewRedis returns a newly initialized redis store
func NewRedis(cfg *RedisConfig) (*Redis, error) {
    cli := redis.NewUniversalClient(
        &redis.UniversalOptions{
            Addrs:        cfg.Hosts,
            Password:     cfg.Password,
            DialTimeout:  cfg.DialTimeoutSecs,
            ReadTimeout:  cfg.ReadTimeoutSecs,
            WriteTimeout: cfg.WriteTimeoutSecs,
            PoolTimeout:  cfg.WriteTimeoutSecs * 10,
        },
    )

    result := cli.Ping()
    err := result.Err()
    if err != nil {
        return nil, err
    }

    r := &Redis{
        client: cli,
    }
    return r, nil
}