github.com/dschalla/mattermost-server@v4.8.1-rc1+incompatible/store/redis_supplier.go (about) 1 // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package store 5 6 import ( 7 "bytes" 8 "context" 9 "encoding/gob" 10 11 "time" 12 13 l4g "github.com/alecthomas/log4go" 14 "github.com/go-redis/redis" 15 "github.com/mattermost/mattermost-server/model" 16 ) 17 18 const REDIS_EXPIRY_TIME = 30 * time.Minute 19 20 type RedisSupplier struct { 21 next LayeredStoreSupplier 22 client *redis.Client 23 } 24 25 func GetBytes(key interface{}) ([]byte, error) { 26 var buf bytes.Buffer 27 enc := gob.NewEncoder(&buf) 28 err := enc.Encode(key) 29 if err != nil { 30 return nil, err 31 } 32 return buf.Bytes(), nil 33 } 34 35 func DecodeBytes(input []byte, thing interface{}) error { 36 dec := gob.NewDecoder(bytes.NewReader(input)) 37 return dec.Decode(thing) 38 } 39 40 func NewRedisSupplier() *RedisSupplier { 41 supplier := &RedisSupplier{} 42 43 supplier.client = redis.NewClient(&redis.Options{ 44 Addr: "localhost:6379", 45 Password: "", 46 DB: 0, 47 }) 48 49 if _, err := supplier.client.Ping().Result(); err != nil { 50 l4g.Error("Unable to ping redis server: " + err.Error()) 51 return nil 52 } 53 54 return supplier 55 } 56 57 func (s *RedisSupplier) save(key string, value interface{}, expiry time.Duration) error { 58 if bytes, err := GetBytes(value); err != nil { 59 return err 60 } else { 61 if err := s.client.Set(key, bytes, expiry).Err(); err != nil { 62 return err 63 } 64 } 65 return nil 66 } 67 68 func (s *RedisSupplier) load(key string, writeTo interface{}) (bool, error) { 69 if data, err := s.client.Get(key).Bytes(); err != nil { 70 if err == redis.Nil { 71 return false, nil 72 } else { 73 return false, err 74 } 75 } else { 76 if err := DecodeBytes(data, writeTo); err != nil { 77 return false, err 78 } 79 } 80 return true, nil 81 } 82 83 func (s *RedisSupplier) SetChainNext(next LayeredStoreSupplier) { 84 s.next = next 85 } 86 87 func (s *RedisSupplier) Next() LayeredStoreSupplier { 88 return s.next 89 } 90 91 func (s *RedisSupplier) ReactionSave(ctx context.Context, reaction *model.Reaction, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { 92 if err := s.client.Del("reactions:" + reaction.PostId).Err(); err != nil { 93 l4g.Error("Redis failed to remove key reactions:" + reaction.PostId + " Error: " + err.Error()) 94 } 95 return s.Next().ReactionSave(ctx, reaction, hints...) 96 } 97 98 func (s *RedisSupplier) ReactionDelete(ctx context.Context, reaction *model.Reaction, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { 99 if err := s.client.Del("reactions:" + reaction.PostId).Err(); err != nil { 100 l4g.Error("Redis failed to remove key reactions:" + reaction.PostId + " Error: " + err.Error()) 101 } 102 return s.Next().ReactionDelete(ctx, reaction, hints...) 103 } 104 105 func (s *RedisSupplier) ReactionGetForPost(ctx context.Context, postId string, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { 106 var resultdata []*model.Reaction 107 found, err := s.load("reactions:"+postId, &resultdata) 108 if found { 109 result := NewSupplierResult() 110 result.Data = resultdata 111 return result 112 } 113 if err != nil { 114 l4g.Error("Redis encountered an error on read: " + err.Error()) 115 } 116 117 result := s.Next().ReactionGetForPost(ctx, postId, hints...) 118 119 if err := s.save("reactions:"+postId, result.Data, REDIS_EXPIRY_TIME); err != nil { 120 l4g.Error("Redis encountered and error on write: " + err.Error()) 121 } 122 123 return result 124 } 125 126 func (s *RedisSupplier) ReactionDeleteAllWithEmojiName(ctx context.Context, emojiName string, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { 127 // Ignoring this. It's probably OK to have the emoji slowly expire from Redis. 128 return s.Next().ReactionDeleteAllWithEmojiName(ctx, emojiName, hints...) 129 } 130 131 func (s *RedisSupplier) ReactionPermanentDeleteBatch(ctx context.Context, endTime int64, limit int64, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { 132 // Ignoring this. It's probably OK to have the emoji slowly expire from Redis. 133 return s.Next().ReactionPermanentDeleteBatch(ctx, endTime, limit, hints...) 134 }