redis.go 1.95 KB
Newer Older
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
package redis

import (
	"errors"
	"fmt"
	"sync"
	"time"

	"github.com/fzzy/radix/redis"

	datastore "github.com/jbenet/go-datastore"
	query "github.com/jbenet/go-datastore/query"
)

var _ datastore.Datastore = &Datastore{}
var _ datastore.ThreadSafeDatastore = &Datastore{}

var ErrInvalidType = errors.New("redis datastore: invalid type error. this datastore only supports []byte values")

func NewExpiringDatastore(client *redis.Client, ttl time.Duration) (datastore.ThreadSafeDatastore, error) {
	return &Datastore{
		client: client,
		ttl:    ttl,
	}, nil
}

func NewDatastore(client *redis.Client) (datastore.ThreadSafeDatastore, error) {
	return &Datastore{
		client: client,
	}, nil
}

type Datastore struct {
	mu     sync.Mutex
	client *redis.Client
	ttl    time.Duration
}

func (ds *Datastore) Put(key datastore.Key, value interface{}) error {
	ds.mu.Lock()
	defer ds.mu.Unlock()

	data, ok := value.([]byte)
	if !ok {
		return ErrInvalidType
	}

	ds.client.Append("SET", key.String(), data)
	if ds.ttl != 0 {
		ds.client.Append("EXPIRE", key.String(), ds.ttl.Seconds())
	}
	if err := ds.client.GetReply().Err; err != nil {
		return fmt.Errorf("failed to put value: %s", err)
	}
	if ds.ttl != 0 {
		if err := ds.client.GetReply().Err; err != nil {
			return fmt.Errorf("failed to set expiration: %s", err)
		}
	}
	return nil
}

func (ds *Datastore) Get(key datastore.Key) (value interface{}, err error) {
	ds.mu.Lock()
	defer ds.mu.Unlock()
	return ds.client.Cmd("GET", key.String()).Bytes()
}

func (ds *Datastore) Has(key datastore.Key) (exists bool, err error) {
	ds.mu.Lock()
	defer ds.mu.Unlock()
	return ds.client.Cmd("EXISTS", key.String()).Bool()
}

func (ds *Datastore) Delete(key datastore.Key) (err error) {
	ds.mu.Lock()
	defer ds.mu.Unlock()
	return ds.client.Cmd("DEL", key.String()).Err
}

func (ds *Datastore) Query(q query.Query) (query.Results, error) {
	return nil, errors.New("TODO implement query for redis datastore?")
}

func (ds *Datastore) IsThreadSafe() {}