github.com/vicanso/pike@v1.0.1-0.20210630235453-9099e041f6ec/store/redis.go (about)

     1  // MIT License
     2  
     3  // Copyright (c) 2021 Tree Xie
     4  
     5  // Permission is hereby granted, free of charge, to any person obtaining a copy
     6  // of this software and associated documentation files (the "Software"), to deal
     7  // in the Software without restriction, including without limitation the rights
     8  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     9  // copies of the Software, and to permit persons to whom the Software is
    10  // furnished to do so, subject to the following conditions:
    11  
    12  // The above copyright notice and this permission notice shall be included in all
    13  // copies or substantial portions of the Software.
    14  
    15  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    16  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    17  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    18  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    19  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    20  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    21  // SOFTWARE.
    22  
    23  package store
    24  
    25  import (
    26  	"context"
    27  	"fmt"
    28  	"net/url"
    29  	"strconv"
    30  	"strings"
    31  	"time"
    32  
    33  	"github.com/go-redis/redis/v8"
    34  	"github.com/vicanso/pike/log"
    35  	"go.uber.org/zap"
    36  )
    37  
    38  type redisStore struct {
    39  	client redis.UniversalClient
    40  	// timeout 超时设置
    41  	timeout time.Duration
    42  	// prefix key的前缀
    43  	prefix string
    44  }
    45  
    46  type redisLogger struct{}
    47  
    48  func (rl *redisLogger) Printf(ctx context.Context, format string, v ...interface{}) {
    49  	log.Default().Info(fmt.Sprintf(format, v...),
    50  		zap.String("category", "redisLogger"),
    51  	)
    52  }
    53  
    54  func init() {
    55  	redis.SetLogger(&redisLogger{})
    56  }
    57  
    58  func newRedisStore(connectionURI string) (store Store, err error) {
    59  	urlInfo, err := url.Parse(connectionURI)
    60  	if err != nil {
    61  		return
    62  	}
    63  	user := ""
    64  	password := ""
    65  	if urlInfo.User != nil {
    66  		user = urlInfo.User.Username()
    67  		password, _ = urlInfo.User.Password()
    68  	}
    69  	// redis选择的db
    70  	db, _ := strconv.Atoi(urlInfo.Query().Get("db"))
    71  	// 设置的超时,如 3s
    72  	timeout, _ := time.ParseDuration(urlInfo.Query().Get("timeout"))
    73  	// 保存的key的前缀
    74  	prefix := urlInfo.Query().Get("prefix")
    75  
    76  	addrs := strings.Split(urlInfo.Host, ",")
    77  	master := urlInfo.Query().Get("master")
    78  
    79  	client := redis.NewUniversalClient(&redis.UniversalOptions{
    80  		Addrs:            addrs,
    81  		Username:         user,
    82  		Password:         password,
    83  		DB:               db,
    84  		SentinelPassword: password,
    85  		MasterName:       master,
    86  	})
    87  
    88  	// 默认3秒超时
    89  	if timeout == 0 {
    90  		timeout = 3 * time.Second
    91  	}
    92  	store = &redisStore{
    93  		client:  client,
    94  		timeout: timeout,
    95  		prefix:  prefix,
    96  	}
    97  	return
    98  }
    99  
   100  func (rs *redisStore) getKey(key []byte) string {
   101  	return rs.prefix + string(key)
   102  }
   103  
   104  // Get get data from redis
   105  func (rs *redisStore) Get(key []byte) (data []byte, err error) {
   106  	ctx, cancel := context.WithTimeout(context.Background(), rs.timeout)
   107  	defer cancel()
   108  	k := rs.getKey(key)
   109  	cmd := rs.client.Get(ctx, k)
   110  	data, err = cmd.Bytes()
   111  	if err != nil {
   112  		if err == redis.Nil {
   113  			err = ErrNotFound
   114  		}
   115  		return
   116  	}
   117  	return
   118  }
   119  
   120  // Set set data to redis
   121  func (rs *redisStore) Set(key []byte, data []byte, ttl time.Duration) (err error) {
   122  	ctx, cancel := context.WithTimeout(context.Background(), rs.timeout)
   123  	defer cancel()
   124  	k := rs.getKey(key)
   125  	cmd := rs.client.Set(ctx, k, data, ttl)
   126  	return cmd.Err()
   127  }
   128  
   129  // Delete delete date from redis
   130  func (rs *redisStore) Delete(key []byte) (err error) {
   131  	ctx, cancel := context.WithTimeout(context.Background(), rs.timeout)
   132  	defer cancel()
   133  	k := rs.getKey(key)
   134  	cmd := rs.client.Del(ctx, k)
   135  	return cmd.Err()
   136  }
   137  
   138  // Close close redis
   139  func (rs *redisStore) Close() error {
   140  	return rs.client.Close()
   141  }