Full Mattermost server source with integrated Community Enterprise features. Includes vendor directory for offline/air-gapped builds. Structure: - enterprise-impl/: Enterprise feature implementations - enterprise-community/: Init files that register implementations - enterprise/: Bridge imports (community_imports.go) - vendor/: All dependencies for offline builds Build (online): go build ./cmd/mattermost Build (offline/air-gapped): go build -mod=vendor ./cmd/mattermost 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
317 lines
10 KiB
Go
317 lines
10 KiB
Go
package redis
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// PrefixedRedisClient struct
|
|
type PrefixedRedisClient struct {
|
|
prefix string
|
|
client Client
|
|
}
|
|
|
|
// Prefix returns the prefix attached to the client
|
|
func (p *PrefixedRedisClient) Prefix() string {
|
|
return p.prefix
|
|
}
|
|
|
|
// ClusterMode returns true if the client is working in cluster mode
|
|
func (p *PrefixedRedisClient) ClusterMode() bool {
|
|
return p.client.ClusterMode()
|
|
}
|
|
|
|
// ClusterSlotForKey returns the slot for the supplied key
|
|
func (p *PrefixedRedisClient) ClusterSlotForKey(key string) (int64, error) {
|
|
return p.client.ClusterSlotForKey(withPrefix(p.prefix, key)).Result()
|
|
}
|
|
|
|
// ClusterCountKeysInSlot returns the number of keys in slot
|
|
func (p *PrefixedRedisClient) ClusterCountKeysInSlot(slot int) (int64, error) {
|
|
return p.client.ClusterCountKeysInSlot(slot).Result()
|
|
}
|
|
|
|
// ClusterKeysInSlot returns all the keys in the supplied slot
|
|
func (p *PrefixedRedisClient) ClusterKeysInSlot(slot int, count int) ([]string, error) {
|
|
keys, err := p.client.ClusterKeysInSlot(slot, count).Multi()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
woPrefix := make([]string, len(keys))
|
|
for index, key := range keys {
|
|
woPrefix[index] = withoutPrefix(p.prefix, key)
|
|
}
|
|
return woPrefix, nil
|
|
}
|
|
|
|
// Get wraps around redis get method by adding prefix and returning string and error directly
|
|
func (p *PrefixedRedisClient) Get(key string) (string, error) {
|
|
return p.client.Get(withPrefix(p.prefix, key)).ResultString()
|
|
}
|
|
|
|
// Set wraps around redis get method by adding prefix and returning error directly
|
|
func (p *PrefixedRedisClient) Set(key string, value interface{}, expiration time.Duration) error {
|
|
return p.client.Set(withPrefix(p.prefix, key), value, expiration).Err()
|
|
}
|
|
|
|
// Keys wraps around redis keys method by adding prefix and returning []string and error directly
|
|
func (p *PrefixedRedisClient) Keys(pattern string) ([]string, error) {
|
|
keys, err := p.client.Keys(withPrefix(p.prefix, pattern)).Multi()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
woPrefix := make([]string, len(keys))
|
|
for index, key := range keys {
|
|
woPrefix[index] = withoutPrefix(p.prefix, key)
|
|
}
|
|
return woPrefix, nil
|
|
|
|
}
|
|
|
|
// Del wraps around redis del method by adding prefix and returning int64 and error directly
|
|
func (p *PrefixedRedisClient) Del(keys ...string) (int64, error) {
|
|
prefixedKeys := make([]string, len(keys))
|
|
for i, k := range keys {
|
|
prefixedKeys[i] = withPrefix(p.prefix, k)
|
|
}
|
|
return p.client.Del(prefixedKeys...).Result()
|
|
}
|
|
|
|
// SMembers returns a slice with all the members of a set
|
|
func (p *PrefixedRedisClient) SMembers(key string) ([]string, error) {
|
|
return p.client.SMembers(withPrefix(p.prefix, key)).Multi()
|
|
}
|
|
|
|
// SIsMember returns true if members is in the set
|
|
func (p *PrefixedRedisClient) SIsMember(key string, member interface{}) bool {
|
|
return p.client.SIsMember(withPrefix(p.prefix, key), member).Bool()
|
|
}
|
|
|
|
// SAdd adds new members to a set
|
|
func (p *PrefixedRedisClient) SAdd(key string, members ...interface{}) (int64, error) {
|
|
return p.client.SAdd(withPrefix(p.prefix, key), members...).Result()
|
|
}
|
|
|
|
// SRem removes members from a set
|
|
func (p *PrefixedRedisClient) SRem(key string, members ...interface{}) (int64, error) {
|
|
return p.client.SRem(withPrefix(p.prefix, key), members...).Result()
|
|
}
|
|
|
|
// Exists returns true if a key exists in redis
|
|
func (p *PrefixedRedisClient) Exists(keys ...string) (int64, error) {
|
|
prefixedKeys := make([]string, len(keys))
|
|
for i, k := range keys {
|
|
prefixedKeys[i] = withPrefix(p.prefix, k)
|
|
}
|
|
val, err := p.client.Exists(prefixedKeys...).Result()
|
|
return val, err
|
|
}
|
|
|
|
// Incr increments a key. Sets it in one if it doesn't exist
|
|
func (p *PrefixedRedisClient) Incr(key string) (int64, error) {
|
|
return p.client.Incr(withPrefix(p.prefix, key)).Result()
|
|
}
|
|
|
|
// Decr increments a key. Sets it in one if it doesn't exist
|
|
func (p *PrefixedRedisClient) Decr(key string) (int64, error) {
|
|
return p.client.Decr(withPrefix(p.prefix, key)).Result()
|
|
}
|
|
|
|
// RPush insert all the specified values at the tail of the list stored at key
|
|
func (p *PrefixedRedisClient) RPush(key string, values ...interface{}) (int64, error) {
|
|
return p.client.RPush(withPrefix(p.prefix, key), values...).Result()
|
|
}
|
|
|
|
// LRange Returns the specified elements of the list stored at key
|
|
func (p *PrefixedRedisClient) LRange(key string, start, stop int64) ([]string, error) {
|
|
return p.client.LRange(withPrefix(p.prefix, key), start, stop).Multi()
|
|
}
|
|
|
|
// LTrim Trim an existing list so that it will contain only the specified range of elements specified
|
|
func (p *PrefixedRedisClient) LTrim(key string, start, stop int64) error {
|
|
return p.client.LTrim(withPrefix(p.prefix, key), start, stop).Err()
|
|
}
|
|
|
|
// LLen Returns the length of the list stored at key
|
|
func (p *PrefixedRedisClient) LLen(key string) (int64, error) {
|
|
return p.client.LLen(withPrefix(p.prefix, key)).Result()
|
|
}
|
|
|
|
// Expire set expiration time for particular key
|
|
func (p *PrefixedRedisClient) Expire(key string, value time.Duration) bool {
|
|
return p.client.Expire(withPrefix(p.prefix, key), value).Bool()
|
|
}
|
|
|
|
// TTL for particular key
|
|
func (p *PrefixedRedisClient) TTL(key string) time.Duration {
|
|
return p.client.TTL(withPrefix(p.prefix, key)).Duration()
|
|
}
|
|
|
|
// MGet fetchs multiple results
|
|
func (p *PrefixedRedisClient) MGet(keys []string) ([]interface{}, error) {
|
|
keysWithPrefix := make([]string, 0)
|
|
for _, key := range keys {
|
|
keysWithPrefix = append(keysWithPrefix, withPrefix(p.prefix, key))
|
|
}
|
|
return p.client.MGet(keysWithPrefix).MultiInterface()
|
|
}
|
|
|
|
// SCard implements SCard wrapper for redis
|
|
func (p *PrefixedRedisClient) SCard(key string) (int64, error) {
|
|
return p.client.SCard(withPrefix(p.prefix, key)).Result()
|
|
}
|
|
|
|
// Eval implements Eval wrapper for redis
|
|
func (p *PrefixedRedisClient) Eval(script string, keys []string, args ...interface{}) error {
|
|
return p.client.Eval(script, keys, args...).Err()
|
|
}
|
|
|
|
// HIncrBy implements HIncrBy wrapper for redis
|
|
func (p *PrefixedRedisClient) HIncrBy(key string, field string, value int64) (int64, error) {
|
|
return p.client.HIncrBy(withPrefix(p.prefix, key), field, value).Result()
|
|
}
|
|
|
|
// HSet implements HGetAll wrapper for redis
|
|
func (p *PrefixedRedisClient) HSet(key string, hashKey string, value interface{}) error {
|
|
return p.client.HSet(withPrefix(p.prefix, key), hashKey, value).Err()
|
|
}
|
|
|
|
// HGetAll implements HGetAll wrapper for redis
|
|
func (p *PrefixedRedisClient) HGetAll(key string) (map[string]string, error) {
|
|
return p.client.HGetAll(withPrefix(p.prefix, key)).MapStringString()
|
|
}
|
|
|
|
// Type implements Type wrapper for redis with prefix
|
|
func (p *PrefixedRedisClient) Type(key string) (string, error) {
|
|
return p.client.Type(withPrefix(p.prefix, key)).ResultString()
|
|
}
|
|
|
|
func (p *PrefixedRedisClient) Scan(cursor uint64, match string, count int64) ([]string, uint64, error) {
|
|
toReturn := make([]string, 0)
|
|
|
|
res := p.client.Scan(cursor, withPrefix(p.prefix, match), count)
|
|
if res.Err() != nil {
|
|
return nil, 0, res.Err()
|
|
}
|
|
|
|
cursor = uint64(res.Int())
|
|
|
|
keys, err := res.Multi()
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
for _, key := range keys {
|
|
toReturn = append(toReturn, withoutPrefix(p.prefix, key))
|
|
}
|
|
|
|
return toReturn, cursor, nil
|
|
}
|
|
|
|
// Pipeline wrapper
|
|
func (p *PrefixedRedisClient) Pipeline() Pipeline {
|
|
return &PrefixedPipeline{wrapped: p.client.Pipeline(), prefix: p.prefix}
|
|
}
|
|
|
|
// NewPrefixedRedisClient returns a new Prefixed Redis Client
|
|
func NewPrefixedRedisClient(redisClient Client, prefix string) (*PrefixedRedisClient, error) {
|
|
return &PrefixedRedisClient{
|
|
client: redisClient,
|
|
prefix: prefix,
|
|
}, nil
|
|
}
|
|
|
|
// PrefixedPipeline adds a prefix to all pipelined operations involving keys
|
|
type PrefixedPipeline struct {
|
|
prefix string
|
|
wrapped Pipeline
|
|
}
|
|
|
|
// LRange schedules an lrange operation on this pipeline
|
|
func (p *PrefixedPipeline) LRange(key string, start, stop int64) {
|
|
p.wrapped.LRange(withPrefix(p.prefix, key), start, stop)
|
|
}
|
|
|
|
// LTrim schedules an ltrim operation on this pipeline
|
|
func (p *PrefixedPipeline) LTrim(key string, start, stop int64) {
|
|
p.wrapped.LTrim(withPrefix(p.prefix, key), start, stop)
|
|
}
|
|
|
|
// LLen schedules an llen operation on this pipeline
|
|
func (p *PrefixedPipeline) LLen(key string) {
|
|
p.wrapped.LLen(withPrefix(p.prefix, key))
|
|
}
|
|
|
|
// HIncrBy schedules an hincrby operation on this pipeline
|
|
func (p *PrefixedPipeline) HIncrBy(key string, field string, value int64) {
|
|
p.wrapped.HIncrBy(withPrefix(p.prefix, key), field, value)
|
|
}
|
|
|
|
// HLen schedules an HLen operation on this pipeline
|
|
func (p *PrefixedPipeline) HLen(key string) {
|
|
p.wrapped.HLen(withPrefix(p.prefix, key))
|
|
}
|
|
|
|
// Set schedules a Set operation on this pipeline
|
|
func (p *PrefixedPipeline) Set(key string, value interface{}, expiration time.Duration) {
|
|
p.wrapped.Set(withPrefix(p.prefix, key), value, expiration)
|
|
}
|
|
|
|
// Incr schedules an Incr operation on this pipeline
|
|
func (p *PrefixedPipeline) Incr(key string) {
|
|
p.wrapped.Incr(withPrefix(p.prefix, key))
|
|
}
|
|
|
|
// Decr schedules a Decr operation on this pipeline
|
|
func (p *PrefixedPipeline) Decr(key string) {
|
|
p.wrapped.Decr(withPrefix(p.prefix, key))
|
|
}
|
|
|
|
// SAdd schedules a SAdd operation on this pipeline
|
|
func (p *PrefixedPipeline) SAdd(key string, members ...interface{}) {
|
|
p.wrapped.SAdd(withPrefix(p.prefix, key), members...)
|
|
}
|
|
|
|
// SRem schedules a SRem operation on this pipeline
|
|
func (p *PrefixedPipeline) SRem(key string, members ...interface{}) {
|
|
p.wrapped.SRem(withPrefix(p.prefix, key), members...)
|
|
}
|
|
|
|
// SMembers schedules a SMembers operation on this pipeline
|
|
func (p *PrefixedPipeline) SMembers(key string) {
|
|
p.wrapped.SMembers(withPrefix(p.prefix, key))
|
|
}
|
|
|
|
// Del schedules a Del operation on this pipeline
|
|
func (p *PrefixedPipeline) Del(keys ...string) {
|
|
prefixedKeys := make([]string, len(keys))
|
|
for i, k := range keys {
|
|
prefixedKeys[i] = withPrefix(p.prefix, k)
|
|
}
|
|
p.wrapped.Del(prefixedKeys...)
|
|
}
|
|
|
|
// Exec executes the pipeline
|
|
func (p *PrefixedPipeline) Exec() ([]Result, error) {
|
|
return p.wrapped.Exec()
|
|
}
|
|
|
|
// withPrefix adds a prefix to the key if the prefix supplied has a length greater than 0
|
|
func withPrefix(prefix string, key string) string {
|
|
if len(prefix) > 0 {
|
|
return fmt.Sprintf("%s.%s", prefix, key)
|
|
}
|
|
return key
|
|
}
|
|
|
|
// withoutPrefix removes the prefix from a key if the prefix has a length greater than 0
|
|
func withoutPrefix(prefix string, key string) string {
|
|
if len(prefix) > 0 {
|
|
return strings.Replace(key, fmt.Sprintf("%s.", prefix), "", 1)
|
|
}
|
|
return key
|
|
}
|