mirror of
				https://github.com/elyby/chrly.git
				synced 2025-05-31 14:11:51 +05:30 
			
		
		
		
	Fixes #8. Replace radix v2 with v4
This commit is contained in:
		| @@ -13,6 +13,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||||||
| ### Changed | ### Changed | ||||||
| - Bumped Go version to 1.21. | - Bumped Go version to 1.21. | ||||||
|  |  | ||||||
|  | ### Removed | ||||||
|  | - StatsD metrics: | ||||||
|  |  - Gauges: | ||||||
|  |    - `ely.skinsystem.{hostname}.app.redis.pool.available` | ||||||
|  |  | ||||||
| ## [4.6.0] - 2021-03-04 | ## [4.6.0] - 2021-03-04 | ||||||
| ### Added | ### Added | ||||||
| - `/profile/{username}` endpoint, which returns a profile and its textures, equivalent of the Mojang's | - `/profile/{username}` endpoint, which returns a profile and its textures, equivalent of the Mojang's | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ package redis | |||||||
| import ( | import ( | ||||||
| 	"bytes" | 	"bytes" | ||||||
| 	"compress/zlib" | 	"compress/zlib" | ||||||
|  | 	"context" | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"io" | 	"io" | ||||||
| @@ -10,23 +11,22 @@ import ( | |||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/mediocregopher/radix.v2/pool" | 	"github.com/mediocregopher/radix/v4" | ||||||
| 	"github.com/mediocregopher/radix.v2/redis" |  | ||||||
| 	"github.com/mediocregopher/radix.v2/util" |  | ||||||
|  |  | ||||||
| 	"github.com/elyby/chrly/model" | 	"github.com/elyby/chrly/model" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var now = time.Now | var now = time.Now | ||||||
|  |  | ||||||
| func New(addr string, poolSize int) (*Redis, error) { | func New(ctx context.Context, addr string, poolSize int) (*Redis, error) { | ||||||
| 	conn, err := pool.New("tcp", addr, poolSize) | 	client, err := (radix.PoolConfig{Size: poolSize}).New(ctx, "tcp", addr) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return &Redis{ | 	return &Redis{ | ||||||
| 		pool: conn, | 		client:  client, | ||||||
|  | 		context: ctx, | ||||||
| 	}, nil | 	}, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -34,27 +34,34 @@ const accountIdToUsernameKey = "hash:username-to-account-id" // TODO: this shoul | |||||||
| const mojangUsernameToUuidKey = "hash:mojang-username-to-uuid" | const mojangUsernameToUuidKey = "hash:mojang-username-to-uuid" | ||||||
|  |  | ||||||
| type Redis struct { | type Redis struct { | ||||||
| 	pool *pool.Pool | 	client  radix.Client | ||||||
|  | 	context context.Context | ||||||
| } | } | ||||||
|  |  | ||||||
| func (db *Redis) FindSkinByUsername(username string) (*model.Skin, error) { | func (db *Redis) FindSkinByUsername(username string) (*model.Skin, error) { | ||||||
| 	conn, err := db.pool.Get() | 	var skin *model.Skin | ||||||
|  | 	err := db.client.Do(db.context, radix.WithConn("", func(ctx context.Context, conn radix.Conn) error { | ||||||
|  | 		var err error | ||||||
|  | 		skin, err = findByUsername(ctx, conn, username) | ||||||
|  |  | ||||||
|  | 		return err | ||||||
|  | 	})) | ||||||
|  |  | ||||||
|  | 	return skin, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func findByUsername(ctx context.Context, conn radix.Conn, username string) (*model.Skin, error) { | ||||||
|  | 	redisKey := buildUsernameKey(username) | ||||||
|  | 	var encodedResult []byte | ||||||
|  | 	err := conn.Do(ctx, radix.Cmd(&encodedResult, "GET", redisKey)) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	defer db.pool.Put(conn) |  | ||||||
|  |  | ||||||
| 	return findByUsername(username, conn) | 	if len(encodedResult) == 0 { | ||||||
| } |  | ||||||
|  |  | ||||||
| func findByUsername(username string, conn util.Cmder) (*model.Skin, error) { |  | ||||||
| 	redisKey := buildUsernameKey(username) |  | ||||||
| 	response := conn.Cmd("GET", redisKey) |  | ||||||
| 	if response.IsType(redis.Nil) { |  | ||||||
| 		return nil, nil | 		return nil, nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	encodedResult, _ := response.Bytes() |  | ||||||
| 	result, err := zlibDecode(encodedResult) | 	result, err := zlibDecode(encodedResult) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| @@ -72,56 +79,66 @@ func findByUsername(username string, conn util.Cmder) (*model.Skin, error) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (db *Redis) FindSkinByUserId(id int) (*model.Skin, error) { | func (db *Redis) FindSkinByUserId(id int) (*model.Skin, error) { | ||||||
| 	conn, err := db.pool.Get() | 	var skin *model.Skin | ||||||
|  | 	err := db.client.Do(db.context, radix.WithConn("", func(ctx context.Context, conn radix.Conn) error { | ||||||
|  | 		var err error | ||||||
|  | 		skin, err = findByUserId(ctx, conn, id) | ||||||
|  |  | ||||||
|  | 		return err | ||||||
|  | 	})) | ||||||
|  |  | ||||||
|  | 	return skin, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func findByUserId(ctx context.Context, conn radix.Conn, id int) (*model.Skin, error) { | ||||||
|  | 	var username string | ||||||
|  | 	err := conn.Do(ctx, radix.FlatCmd(&username, "HGET", accountIdToUsernameKey, id)) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	defer db.pool.Put(conn) |  | ||||||
|  |  | ||||||
| 	return findByUserId(id, conn) | 	if username == "" { | ||||||
| } |  | ||||||
|  |  | ||||||
| func findByUserId(id int, conn util.Cmder) (*model.Skin, error) { |  | ||||||
| 	response := conn.Cmd("HGET", accountIdToUsernameKey, id) |  | ||||||
| 	if response.IsType(redis.Nil) { |  | ||||||
| 		return nil, nil | 		return nil, nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	username, err := response.Str() | 	return findByUsername(ctx, conn, username) | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return findByUsername(username, conn) |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func (db *Redis) SaveSkin(skin *model.Skin) error { | func (db *Redis) SaveSkin(skin *model.Skin) error { | ||||||
| 	conn, err := db.pool.Get() | 	return db.client.Do(db.context, radix.WithConn("", func(ctx context.Context, conn radix.Conn) error { | ||||||
|  | 		return save(ctx, conn, skin) | ||||||
|  | 	})) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func save(ctx context.Context, conn radix.Conn, skin *model.Skin) error { | ||||||
|  | 	err := conn.Do(ctx, radix.Cmd(nil, "MULTI")) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	defer db.pool.Put(conn) |  | ||||||
|  |  | ||||||
| 	return save(skin, conn) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func save(skin *model.Skin, conn util.Cmder) error { |  | ||||||
| 	conn.Cmd("MULTI") |  | ||||||
|  |  | ||||||
| 	// If user has changed username, then we must delete his old username record | 	// If user has changed username, then we must delete his old username record | ||||||
| 	if skin.OldUsername != "" && skin.OldUsername != skin.Username { | 	if skin.OldUsername != "" && skin.OldUsername != skin.Username { | ||||||
| 		conn.Cmd("DEL", buildUsernameKey(skin.OldUsername)) | 		err = conn.Do(ctx, radix.Cmd(nil, "DEL", buildUsernameKey(skin.OldUsername))) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// If this is a new record or if the user has changed username, we set the value in the hash table | 	// If this is a new record or if the user has changed username, we set the value in the hash table | ||||||
| 	if skin.OldUsername != "" || skin.OldUsername != skin.Username { | 	if skin.OldUsername != "" || skin.OldUsername != skin.Username { | ||||||
| 		conn.Cmd("HSET", accountIdToUsernameKey, skin.UserId, skin.Username) | 		err = conn.Do(ctx, radix.FlatCmd(nil, "HSET", accountIdToUsernameKey, skin.UserId, skin.Username)) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	str, _ := json.Marshal(skin) | 	str, _ := json.Marshal(skin) | ||||||
| 	conn.Cmd("SET", buildUsernameKey(skin.Username), zlibEncode(str)) | 	err = conn.Do(ctx, radix.FlatCmd(nil, "SET", buildUsernameKey(skin.Username), zlibEncode(str))) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	conn.Cmd("EXEC") | 	err = conn.Do(ctx, radix.Cmd(nil, "EXEC")) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	skin.OldUsername = skin.Username | 	skin.OldUsername = skin.Username | ||||||
|  |  | ||||||
| @@ -129,45 +146,45 @@ func save(skin *model.Skin, conn util.Cmder) error { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (db *Redis) RemoveSkinByUserId(id int) error { | func (db *Redis) RemoveSkinByUserId(id int) error { | ||||||
| 	conn, err := db.pool.Get() | 	return db.client.Do(db.context, radix.WithConn("", func(ctx context.Context, conn radix.Conn) error { | ||||||
| 	if err != nil { | 		return removeByUserId(ctx, conn, id) | ||||||
| 		return err | 	})) | ||||||
| 	} |  | ||||||
| 	defer db.pool.Put(conn) |  | ||||||
|  |  | ||||||
| 	return removeByUserId(id, conn) |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func removeByUserId(id int, conn util.Cmder) error { | func removeByUserId(ctx context.Context, conn radix.Conn, id int) error { | ||||||
| 	record, err := findByUserId(id, conn) | 	record, err := findByUserId(ctx, conn, id) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	conn.Cmd("MULTI") | 	err = conn.Do(ctx, radix.Cmd(nil, "MULTI")) | ||||||
|  | 	if err != nil { | ||||||
| 	conn.Cmd("HDEL", accountIdToUsernameKey, id) | 		return err | ||||||
| 	if record != nil { |  | ||||||
| 		conn.Cmd("DEL", buildUsernameKey(record.Username)) |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	conn.Cmd("EXEC") | 	err = conn.Do(ctx, radix.FlatCmd(nil, "HDEL", accountIdToUsernameKey, id)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	return nil | 	if record != nil { | ||||||
|  | 		err = conn.Do(ctx, radix.Cmd(nil, "DEL", buildUsernameKey(record.Username))) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return conn.Do(ctx, radix.Cmd(nil, "EXEC")) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (db *Redis) RemoveSkinByUsername(username string) error { | func (db *Redis) RemoveSkinByUsername(username string) error { | ||||||
| 	conn, err := db.pool.Get() | 	return db.client.Do(db.context, radix.WithConn("", func(ctx context.Context, conn radix.Conn) error { | ||||||
| 	if err != nil { | 		return removeByUsername(ctx, conn, username) | ||||||
| 		return err | 	})) | ||||||
| 	} |  | ||||||
| 	defer db.pool.Put(conn) |  | ||||||
|  |  | ||||||
| 	return removeByUsername(username, conn) |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func removeByUsername(username string, conn util.Cmder) error { | func removeByUsername(ctx context.Context, conn radix.Conn, username string) error { | ||||||
| 	record, err := findByUsername(username, conn) | 	record, err := findByUsername(ctx, conn, username) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| @@ -176,45 +193,68 @@ func removeByUsername(username string, conn util.Cmder) error { | |||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	conn.Cmd("MULTI") | 	err = conn.Do(ctx, radix.Cmd(nil, "MULTI")) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	conn.Cmd("DEL", buildUsernameKey(record.Username)) | 	err = conn.Do(ctx, radix.Cmd(nil, "DEL", buildUsernameKey(record.Username))) | ||||||
| 	conn.Cmd("HDEL", accountIdToUsernameKey, record.UserId) | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	conn.Cmd("EXEC") | 	err = conn.Do(ctx, radix.FlatCmd(nil, "HDEL", accountIdToUsernameKey, record.UserId)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	return nil | 	return conn.Do(ctx, radix.Cmd(nil, "EXEC")) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (db *Redis) GetUuid(username string) (string, bool, error) { | func (db *Redis) GetUuid(username string) (string, bool, error) { | ||||||
| 	conn, err := db.pool.Get() | 	var uuid string | ||||||
|  | 	var found bool | ||||||
|  | 	err := db.client.Do(db.context, radix.WithConn("", func(ctx context.Context, conn radix.Conn) error { | ||||||
|  | 		var err error | ||||||
|  | 		uuid, found, err = findMojangUuidByUsername(ctx, conn, username) | ||||||
|  |  | ||||||
|  | 		return err | ||||||
|  | 	})) | ||||||
|  |  | ||||||
|  | 	return uuid, found, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func findMojangUuidByUsername(ctx context.Context, conn radix.Conn, username string) (string, bool, error) { | ||||||
|  | 	key := strings.ToLower(username) | ||||||
|  | 	var result string | ||||||
|  | 	err := conn.Do(ctx, radix.Cmd(&result, "HGET", mojangUsernameToUuidKey, key)) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return "", false, err | 		return "", false, err | ||||||
| 	} | 	} | ||||||
| 	defer db.pool.Put(conn) |  | ||||||
|  |  | ||||||
| 	return findMojangUuidByUsername(username, conn) | 	if result == "" { | ||||||
| } |  | ||||||
|  |  | ||||||
| func findMojangUuidByUsername(username string, conn util.Cmder) (string, bool, error) { |  | ||||||
| 	key := strings.ToLower(username) |  | ||||||
| 	response := conn.Cmd("HGET", mojangUsernameToUuidKey, key) |  | ||||||
| 	if response.IsType(redis.Nil) { |  | ||||||
| 		return "", false, nil | 		return "", false, nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	data, _ := response.Str() | 	parts := strings.Split(result, ":") | ||||||
| 	parts := strings.Split(data, ":") |  | ||||||
| 	// https://github.com/elyby/chrly/issues/28 | 	// https://github.com/elyby/chrly/issues/28 | ||||||
| 	if len(parts) < 2 { | 	if len(parts) < 2 { | ||||||
| 		conn.Cmd("HDEL", mojangUsernameToUuidKey, key) | 		err = conn.Do(ctx, radix.Cmd(nil, "HDEL", mojangUsernameToUuidKey, key)) | ||||||
| 		return "", false, fmt.Errorf("Got unexpected response from the mojangUsernameToUuid hash: \"%s\"", data) | 		if err != nil { | ||||||
|  | 			return "", false, err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return "", false, fmt.Errorf("got unexpected response from the mojangUsernameToUuid hash: \"%s\"", result) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	timestamp, _ := strconv.ParseInt(parts[1], 10, 64) | 	timestamp, _ := strconv.ParseInt(parts[1], 10, 64) | ||||||
| 	storedAt := time.Unix(timestamp, 0) | 	storedAt := time.Unix(timestamp, 0) | ||||||
| 	if storedAt.Add(time.Hour * 24 * 30).Before(now()) { | 	if storedAt.Add(time.Hour * 24 * 30).Before(now()) { | ||||||
| 		conn.Cmd("HDEL", mojangUsernameToUuidKey, key) | 		err = conn.Do(ctx, radix.Cmd(nil, "HDEL", mojangUsernameToUuidKey, key)) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return "", false, err | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		return "", false, nil | 		return "", false, nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -222,36 +262,23 @@ func findMojangUuidByUsername(username string, conn util.Cmder) (string, bool, e | |||||||
| } | } | ||||||
|  |  | ||||||
| func (db *Redis) StoreUuid(username string, uuid string) error { | func (db *Redis) StoreUuid(username string, uuid string) error { | ||||||
| 	conn, err := db.pool.Get() | 	return db.client.Do(db.context, radix.WithConn("", func(ctx context.Context, conn radix.Conn) error { | ||||||
| 	if err != nil { | 		return storeMojangUuid(ctx, conn, username, uuid) | ||||||
| 		return err | 	})) | ||||||
| 	} |  | ||||||
| 	defer db.pool.Put(conn) |  | ||||||
|  |  | ||||||
| 	return storeMojangUuid(username, uuid, conn) |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func storeMojangUuid(username string, uuid string, conn util.Cmder) error { | func storeMojangUuid(ctx context.Context, conn radix.Conn, username string, uuid string) error { | ||||||
| 	value := uuid + ":" + strconv.FormatInt(now().Unix(), 10) | 	value := uuid + ":" + strconv.FormatInt(now().Unix(), 10) | ||||||
| 	res := conn.Cmd("HSET", mojangUsernameToUuidKey, strings.ToLower(username), value) | 	err := conn.Do(ctx, radix.Cmd(nil, "HSET", mojangUsernameToUuidKey, strings.ToLower(username), value)) | ||||||
| 	if res.IsType(redis.Err) { | 	if err != nil { | ||||||
| 		return res.Err | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (db *Redis) Ping() error { | func (db *Redis) Ping() error { | ||||||
| 	r := db.pool.Cmd("PING") | 	return db.client.Do(db.context, radix.Cmd(nil, "PING")) | ||||||
| 	if r.Err != nil { |  | ||||||
| 		return r.Err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (db *Redis) Avail() int { |  | ||||||
| 	return db.pool.Avail() |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func buildUsernameKey(username string) string { | func buildUsernameKey(username string) string { | ||||||
|   | |||||||
| @@ -1,17 +1,16 @@ | |||||||
| //go:build redis | //go:build redis | ||||||
| // +build redis |  | ||||||
|  |  | ||||||
| package redis | package redis | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"context" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"os" | 	"os" | ||||||
| 	"reflect" |  | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"testing" | 	"testing" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/mediocregopher/radix.v2/redis" | 	"github.com/mediocregopher/radix/v4" | ||||||
| 	assert "github.com/stretchr/testify/require" | 	assert "github.com/stretchr/testify/require" | ||||||
| 	"github.com/stretchr/testify/suite" | 	"github.com/stretchr/testify/suite" | ||||||
|  |  | ||||||
| @@ -36,15 +35,13 @@ func init() { | |||||||
|  |  | ||||||
| func TestNew(t *testing.T) { | func TestNew(t *testing.T) { | ||||||
| 	t.Run("should connect", func(t *testing.T) { | 	t.Run("should connect", func(t *testing.T) { | ||||||
| 		conn, err := New(redisAddr, 12) | 		conn, err := New(context.Background(), redisAddr, 12) | ||||||
| 		assert.Nil(t, err) | 		assert.Nil(t, err) | ||||||
| 		assert.NotNil(t, conn) | 		assert.NotNil(t, conn) | ||||||
| 		internalPool := reflect.ValueOf(conn.pool).Elem().FieldByName("pool") |  | ||||||
| 		assert.Equal(t, 12, internalPool.Cap()) |  | ||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
| 	t.Run("should return error", func(t *testing.T) { | 	t.Run("should return error", func(t *testing.T) { | ||||||
| 		conn, err := New("localhost:12345", 12) // Use localhost to avoid DNS resolution | 		conn, err := New(context.Background(), "localhost:12345", 12) // Use localhost to avoid DNS resolution | ||||||
| 		assert.Error(t, err) | 		assert.Error(t, err) | ||||||
| 		assert.Nil(t, conn) | 		assert.Nil(t, conn) | ||||||
| 	}) | 	}) | ||||||
| @@ -55,21 +52,30 @@ type redisTestSuite struct { | |||||||
|  |  | ||||||
| 	Redis *Redis | 	Redis *Redis | ||||||
|  |  | ||||||
| 	cmd func(cmd string, args ...interface{}) *redis.Resp | 	cmd func(cmd string, args ...interface{}) string | ||||||
| } | } | ||||||
|  |  | ||||||
| func (suite *redisTestSuite) SetupSuite() { | func (suite *redisTestSuite) SetupSuite() { | ||||||
| 	conn, err := New(redisAddr, 10) | 	ctx := context.Background() | ||||||
|  | 	conn, err := New(ctx, redisAddr, 10) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		panic(fmt.Errorf("cannot establish connection to redis: %w", err)) | 		panic(fmt.Errorf("cannot establish connection to redis: %w", err)) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	suite.Redis = conn | 	suite.Redis = conn | ||||||
| 	suite.cmd = conn.pool.Cmd | 	suite.cmd = func(cmd string, args ...interface{}) string { | ||||||
|  | 		var result string | ||||||
|  | 		err := suite.Redis.client.Do(ctx, radix.FlatCmd(&result, cmd, args...)) | ||||||
|  | 		if err != nil { | ||||||
|  | 			panic(err) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return result | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (suite *redisTestSuite) SetupTest() { | func (suite *redisTestSuite) SetupTest() { | ||||||
| 	// Cleanup database before the each test | 	// Cleanup database before each test | ||||||
| 	suite.cmd("FLUSHALL") | 	suite.cmd("FLUSHALL") | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -101,7 +107,7 @@ func TestRedis(t *testing.T) { | |||||||
|  *     mojangSignature: "mock-mojang-signature" |  *     mojangSignature: "mock-mojang-signature" | ||||||
|  * } |  * } | ||||||
|  */ |  */ | ||||||
| var skinRecord = []byte{ | var skinRecord = string([]byte{ | ||||||
| 	0x78, 0x9c, 0x5c, 0xce, 0x4b, 0x4a, 0x4, 0x41, 0xc, 0xc6, 0xf1, 0xbb, 0x7c, 0xeb, 0x1a, 0xdb, 0xd6, 0xb2, | 	0x78, 0x9c, 0x5c, 0xce, 0x4b, 0x4a, 0x4, 0x41, 0xc, 0xc6, 0xf1, 0xbb, 0x7c, 0xeb, 0x1a, 0xdb, 0xd6, 0xb2, | ||||||
| 	0x9c, 0xc9, 0xd, 0x5c, 0x88, 0x8b, 0xd1, 0xb5, 0x84, 0x4e, 0xa6, 0xa7, 0xec, 0x7a, 0xc, 0xf5, 0x0, 0x41, | 	0x9c, 0xc9, 0xd, 0x5c, 0x88, 0x8b, 0xd1, 0xb5, 0x84, 0x4e, 0xa6, 0xa7, 0xec, 0x7a, 0xc, 0xf5, 0x0, 0x41, | ||||||
| 	0xbc, 0xbb, 0xb4, 0xd2, 0xa, 0x2e, 0xf3, 0xe3, 0x9f, 0x90, 0xf, 0xf4, 0xaa, 0xe5, 0x41, 0x40, 0xa3, 0x41, | 	0xbc, 0xbb, 0xb4, 0xd2, 0xa, 0x2e, 0xf3, 0xe3, 0x9f, 0x90, 0xf, 0xf4, 0xaa, 0xe5, 0x41, 0x40, 0xa3, 0x41, | ||||||
| @@ -112,7 +118,7 @@ var skinRecord = []byte{ | |||||||
| 	0xa0, 0x13, 0x87, 0xaa, 0x6, 0x31, 0xbf, 0x71, 0x9a, 0x9f, 0xf5, 0xbd, 0xf5, 0xa2, 0x15, 0x84, 0x98, 0xa7, | 	0xa0, 0x13, 0x87, 0xaa, 0x6, 0x31, 0xbf, 0x71, 0x9a, 0x9f, 0xf5, 0xbd, 0xf5, 0xa2, 0x15, 0x84, 0x98, 0xa7, | ||||||
| 	0x65, 0xf7, 0xa3, 0xbb, 0xb6, 0xf1, 0xd6, 0x1d, 0xfd, 0x9c, 0x78, 0xa5, 0x7f, 0x61, 0xfd, 0x75, 0x83, 0xa7, | 	0x65, 0xf7, 0xa3, 0xbb, 0xb6, 0xf1, 0xd6, 0x1d, 0xfd, 0x9c, 0x78, 0xa5, 0x7f, 0x61, 0xfd, 0x75, 0x83, 0xa7, | ||||||
| 	0x20, 0x2f, 0x7f, 0xff, 0xe2, 0xf3, 0x2b, 0x0, 0x0, 0xff, 0xff, 0x6f, 0xdd, 0x51, 0x71, | 	0x20, 0x2f, 0x7f, 0xff, 0xe2, 0xf3, 0x2b, 0x0, 0x0, 0xff, 0xff, 0x6f, 0xdd, 0x51, 0x71, | ||||||
| } | }) | ||||||
|  |  | ||||||
| func (suite *redisTestSuite) TestFindSkinByUsername() { | func (suite *redisTestSuite) TestFindSkinByUsername() { | ||||||
| 	suite.RunSubTest("exists record", func() { | 	suite.RunSubTest("exists record", func() { | ||||||
| @@ -198,14 +204,11 @@ func (suite *redisTestSuite) TestSaveSkin() { | |||||||
| 		suite.Require().Nil(err) | 		suite.Require().Nil(err) | ||||||
|  |  | ||||||
| 		usernameResp := suite.cmd("GET", "username:mock") | 		usernameResp := suite.cmd("GET", "username:mock") | ||||||
| 		suite.Require().False(usernameResp.IsType(redis.Nil)) | 		suite.Require().NotEmpty(usernameResp) | ||||||
| 		bytes, _ := usernameResp.Bytes() | 		suite.Require().Equal(skinRecord, usernameResp) | ||||||
| 		suite.Require().Equal(skinRecord, bytes) |  | ||||||
|  |  | ||||||
| 		idResp := suite.cmd("HGET", "hash:username-to-account-id", 1) | 		idResp := suite.cmd("HGET", "hash:username-to-account-id", 1) | ||||||
| 		suite.Require().False(usernameResp.IsType(redis.Nil)) | 		suite.Require().Equal("Mock", idResp) | ||||||
| 		str, _ := idResp.Str() |  | ||||||
| 		suite.Require().Equal("Mock", str) |  | ||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
| 	suite.RunSubTest("save exists record with changed username", func() { | 	suite.RunSubTest("save exists record with changed username", func() { | ||||||
| @@ -227,9 +230,8 @@ func (suite *redisTestSuite) TestSaveSkin() { | |||||||
| 		suite.Require().Nil(err) | 		suite.Require().Nil(err) | ||||||
|  |  | ||||||
| 		usernameResp := suite.cmd("GET", "username:newmock") | 		usernameResp := suite.cmd("GET", "username:newmock") | ||||||
| 		suite.Require().False(usernameResp.IsType(redis.Nil)) | 		suite.Require().NotEmpty(usernameResp) | ||||||
| 		bytes, _ := usernameResp.Bytes() | 		suite.Require().Equal(string([]byte{ | ||||||
| 		suite.Require().Equal([]byte{ |  | ||||||
| 			0x78, 0x9c, 0x5c, 0x8e, 0xcb, 0x4e, 0xc3, 0x40, 0xc, 0x45, 0xff, 0xe5, 0xae, 0xa7, 0x84, 0x40, 0x18, 0x5a, | 			0x78, 0x9c, 0x5c, 0x8e, 0xcb, 0x4e, 0xc3, 0x40, 0xc, 0x45, 0xff, 0xe5, 0xae, 0xa7, 0x84, 0x40, 0x18, 0x5a, | ||||||
| 			0xff, 0x1, 0xb, 0x60, 0x51, 0x58, 0x23, 0x2b, 0x76, 0xd3, 0x21, 0xf3, 0xa8, 0xe6, 0x21, 0x90, 0x10, 0xff, | 			0xff, 0x1, 0xb, 0x60, 0x51, 0x58, 0x23, 0x2b, 0x76, 0xd3, 0x21, 0xf3, 0xa8, 0xe6, 0x21, 0x90, 0x10, 0xff, | ||||||
| 			0x8e, 0x52, 0x14, 0x90, 0xba, 0xf4, 0xd1, 0xf1, 0xd5, 0xf9, 0x42, 0x2b, 0x9a, 0x1f, 0x4, 0xd4, 0x1b, 0xb4, | 			0x8e, 0x52, 0x14, 0x90, 0xba, 0xf4, 0xd1, 0xf1, 0xd5, 0xf9, 0x42, 0x2b, 0x9a, 0x1f, 0x4, 0xd4, 0x1b, 0xb4, | ||||||
| @@ -241,15 +243,14 @@ func (suite *redisTestSuite) TestSaveSkin() { | |||||||
| 			0x42, 0x1a, 0xe7, 0xcd, 0x2f, 0xdd, 0xd4, 0x15, 0xaf, 0xde, 0xde, 0x4d, 0x91, 0x17, 0x74, 0x21, 0x96, 0x3f, | 			0x42, 0x1a, 0xe7, 0xcd, 0x2f, 0xdd, 0xd4, 0x15, 0xaf, 0xde, 0xde, 0x4d, 0x91, 0x17, 0x74, 0x21, 0x96, 0x3f, | ||||||
| 			0x6e, 0xf0, 0xec, 0xe5, 0xf5, 0x3f, 0xf9, 0xdc, 0xfb, 0xfd, 0x13, 0x0, 0x0, 0xff, 0xff, 0xca, 0xc3, 0x54, | 			0x6e, 0xf0, 0xec, 0xe5, 0xf5, 0x3f, 0xf9, 0xdc, 0xfb, 0xfd, 0x13, 0x0, 0x0, 0xff, 0xff, 0xca, 0xc3, 0x54, | ||||||
| 			0x25, | 			0x25, | ||||||
| 		}, bytes) | 		}), usernameResp) | ||||||
|  |  | ||||||
| 		oldUsernameResp := suite.cmd("GET", "username:mock") | 		oldUsernameResp := suite.cmd("GET", "username:mock") | ||||||
| 		suite.Require().True(oldUsernameResp.IsType(redis.Nil)) | 		suite.Require().Empty(oldUsernameResp) | ||||||
|  |  | ||||||
| 		idResp := suite.cmd("HGET", "hash:username-to-account-id", 1) | 		idResp := suite.cmd("HGET", "hash:username-to-account-id", 1) | ||||||
| 		suite.Require().False(usernameResp.IsType(redis.Nil)) | 		suite.Require().NotEmpty(usernameResp) | ||||||
| 		str, _ := idResp.Str() | 		suite.Require().Equal("NewMock", idResp) | ||||||
| 		suite.Require().Equal("NewMock", str) |  | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -262,10 +263,10 @@ func (suite *redisTestSuite) TestRemoveSkinByUserId() { | |||||||
| 		suite.Require().Nil(err) | 		suite.Require().Nil(err) | ||||||
|  |  | ||||||
| 		usernameResp := suite.cmd("GET", "username:mock") | 		usernameResp := suite.cmd("GET", "username:mock") | ||||||
| 		suite.Require().True(usernameResp.IsType(redis.Nil)) | 		suite.Require().Empty(usernameResp) | ||||||
|  |  | ||||||
| 		idResp := suite.cmd("HGET", "hash:username-to-account-id", 1) | 		idResp := suite.cmd("HGET", "hash:username-to-account-id", 1) | ||||||
| 		suite.Require().True(idResp.IsType(redis.Nil)) | 		suite.Require().Empty(idResp) | ||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
| 	suite.RunSubTest("exists only id", func() { | 	suite.RunSubTest("exists only id", func() { | ||||||
| @@ -275,7 +276,7 @@ func (suite *redisTestSuite) TestRemoveSkinByUserId() { | |||||||
| 		suite.Require().Nil(err) | 		suite.Require().Nil(err) | ||||||
|  |  | ||||||
| 		idResp := suite.cmd("HGET", "hash:username-to-account-id", 1) | 		idResp := suite.cmd("HGET", "hash:username-to-account-id", 1) | ||||||
| 		suite.Require().True(idResp.IsType(redis.Nil)) | 		suite.Require().Empty(idResp) | ||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
| 	suite.RunSubTest("error when querying skin record", func() { | 	suite.RunSubTest("error when querying skin record", func() { | ||||||
| @@ -296,10 +297,10 @@ func (suite *redisTestSuite) TestRemoveSkinByUsername() { | |||||||
| 		suite.Require().Nil(err) | 		suite.Require().Nil(err) | ||||||
|  |  | ||||||
| 		usernameResp := suite.cmd("GET", "username:mock") | 		usernameResp := suite.cmd("GET", "username:mock") | ||||||
| 		suite.Require().True(usernameResp.IsType(redis.Nil)) | 		suite.Require().Empty(usernameResp) | ||||||
|  |  | ||||||
| 		idResp := suite.cmd("HGET", "hash:username-to-account-id", 1) | 		idResp := suite.cmd("HGET", "hash:username-to-account-id", 1) | ||||||
| 		suite.Require().True(idResp.IsType(redis.Nil)) | 		suite.Require().Empty(idResp) | ||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
| 	suite.RunSubTest("exists only username", func() { | 	suite.RunSubTest("exists only username", func() { | ||||||
| @@ -309,7 +310,7 @@ func (suite *redisTestSuite) TestRemoveSkinByUsername() { | |||||||
| 		suite.Require().Nil(err) | 		suite.Require().Nil(err) | ||||||
|  |  | ||||||
| 		usernameResp := suite.cmd("GET", "username:mock") | 		usernameResp := suite.cmd("GET", "username:mock") | ||||||
| 		suite.Require().True(usernameResp.IsType(redis.Nil)) | 		suite.Require().Empty(usernameResp) | ||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
| 	suite.RunSubTest("no records", func() { | 	suite.RunSubTest("no records", func() { | ||||||
| @@ -372,7 +373,7 @@ func (suite *redisTestSuite) TestGetUuid() { | |||||||
| 		suite.Require().Nil(err) | 		suite.Require().Nil(err) | ||||||
|  |  | ||||||
| 		resp := suite.cmd("HGET", "hash:mojang-username-to-uuid", "mock") | 		resp := suite.cmd("HGET", "hash:mojang-username-to-uuid", "mock") | ||||||
| 		suite.Require().True(resp.IsType(redis.Nil), "should cleanup expired records") | 		suite.Require().Empty(resp, "should cleanup expired records") | ||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
| 	suite.RunSubTest("exists, but corrupted record", func() { | 	suite.RunSubTest("exists, but corrupted record", func() { | ||||||
| @@ -388,7 +389,7 @@ func (suite *redisTestSuite) TestGetUuid() { | |||||||
| 		suite.Require().Error(err, "Got unexpected response from the mojangUsernameToUuid hash: \"corrupted value\"") | 		suite.Require().Error(err, "Got unexpected response from the mojangUsernameToUuid hash: \"corrupted value\"") | ||||||
|  |  | ||||||
| 		resp := suite.cmd("HGET", "hash:mojang-username-to-uuid", "mock") | 		resp := suite.cmd("HGET", "hash:mojang-username-to-uuid", "mock") | ||||||
| 		suite.Require().True(resp.IsType(redis.Nil), "should cleanup expired records") | 		suite.Require().Empty(resp, "should cleanup expired records") | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -402,9 +403,7 @@ func (suite *redisTestSuite) TestStoreUuid() { | |||||||
| 		suite.Require().Nil(err) | 		suite.Require().Nil(err) | ||||||
|  |  | ||||||
| 		resp := suite.cmd("HGET", "hash:mojang-username-to-uuid", "mock") | 		resp := suite.cmd("HGET", "hash:mojang-username-to-uuid", "mock") | ||||||
| 		suite.Require().False(resp.IsType(redis.Nil)) | 		suite.Require().Equal(resp, "d3ca513eb3e14946b58047f2bd3530fd:1587435016") | ||||||
| 		str, _ := resp.Str() |  | ||||||
| 		suite.Require().Equal(str, "d3ca513eb3e14946b58047f2bd3530fd:1587435016") |  | ||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
| 	suite.RunSubTest("store empty uuid", func() { | 	suite.RunSubTest("store empty uuid", func() { | ||||||
| @@ -416,9 +415,7 @@ func (suite *redisTestSuite) TestStoreUuid() { | |||||||
| 		suite.Require().Nil(err) | 		suite.Require().Nil(err) | ||||||
|  |  | ||||||
| 		resp := suite.cmd("HGET", "hash:mojang-username-to-uuid", "mock") | 		resp := suite.cmd("HGET", "hash:mojang-username-to-uuid", "mock") | ||||||
| 		suite.Require().False(resp.IsType(redis.Nil)) | 		suite.Require().Equal(resp, ":1587435016") | ||||||
| 		str, _ := resp.Str() |  | ||||||
| 		suite.Require().Equal(str, ":1587435016") |  | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -426,8 +423,3 @@ func (suite *redisTestSuite) TestPing() { | |||||||
| 	err := suite.Redis.Ping() | 	err := suite.Redis.Ping() | ||||||
| 	suite.Require().Nil(err) | 	suite.Require().Nil(err) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (suite *redisTestSuite) TestAvail() { |  | ||||||
| 	avail := suite.Redis.Avail() |  | ||||||
| 	suite.Require().True(avail > 0) |  | ||||||
| } |  | ||||||
|   | |||||||
							
								
								
									
										8
									
								
								di/db.go
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								di/db.go
									
									
									
									
									
								
							| @@ -4,7 +4,6 @@ import ( | |||||||
| 	"context" | 	"context" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"path" | 	"path" | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"github.com/defval/di" | 	"github.com/defval/di" | ||||||
| 	"github.com/spf13/viper" | 	"github.com/spf13/viper" | ||||||
| @@ -38,6 +37,7 @@ func newRedis(container *di.Container, config *viper.Viper) (*redis.Redis, error | |||||||
| 	config.SetDefault("storage.redis.poolSize", 10) | 	config.SetDefault("storage.redis.poolSize", 10) | ||||||
|  |  | ||||||
| 	conn, err := redis.New( | 	conn, err := redis.New( | ||||||
|  | 		context.Background(), | ||||||
| 		fmt.Sprintf("%s:%d", config.GetString("storage.redis.host"), config.GetInt("storage.redis.port")), | 		fmt.Sprintf("%s:%d", config.GetString("storage.redis.host"), config.GetInt("storage.redis.port")), | ||||||
| 		config.GetInt("storage.redis.poolSize"), | 		config.GetInt("storage.redis.poolSize"), | ||||||
| 	) | 	) | ||||||
| @@ -45,12 +45,6 @@ func newRedis(container *di.Container, config *viper.Viper) (*redis.Redis, error | |||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if err := container.Provide(func() es.ReporterFunc { |  | ||||||
| 		return es.AvailableRedisPoolSizeReporter(conn, time.Second, context.Background()) |  | ||||||
| 	}, di.As(new(es.Reporter))); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if err := container.Provide(func() *namedHealthChecker { | 	if err := container.Provide(func() *namedHealthChecker { | ||||||
| 		return &namedHealthChecker{ | 		return &namedHealthChecker{ | ||||||
| 			Name:    "redis", | 			Name:    "redis", | ||||||
|   | |||||||
| @@ -1,7 +1,6 @@ | |||||||
| package eventsubscribers | package eventsubscribers | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"context" |  | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"sync" | 	"sync" | ||||||
| @@ -30,7 +29,7 @@ func (f ReporterFunc) Enable(reporter slf.StatsReporter) { | |||||||
| 	f(reporter) | 	f(reporter) | ||||||
| } | } | ||||||
|  |  | ||||||
| // TODO: rework all reporters in the same style as AvailableRedisPoolSizeReporter | // TODO: rework all reporters in the same style as it was there: https://github.com/elyby/chrly/blob/1543e98b/di/db.go#L48-L52 | ||||||
| func (s *StatsReporter) ConfigureWithDispatcher(d Subscriber) { | func (s *StatsReporter) ConfigureWithDispatcher(d Subscriber) { | ||||||
| 	s.timersMap = make(map[string]time.Time) | 	s.timersMap = make(map[string]time.Time) | ||||||
|  |  | ||||||
| @@ -189,24 +188,3 @@ func (s *StatsReporter) finalizeTimeRecording(timeKey string, statName string) { | |||||||
|  |  | ||||||
| 	s.RecordTimer(statName, time.Since(startedAt)) | 	s.RecordTimer(statName, time.Since(startedAt)) | ||||||
| } | } | ||||||
|  |  | ||||||
| type RedisPoolCheckable interface { |  | ||||||
| 	Avail() int |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func AvailableRedisPoolSizeReporter(pool RedisPoolCheckable, d time.Duration, stop context.Context) ReporterFunc { |  | ||||||
| 	return func(reporter slf.StatsReporter) { |  | ||||||
| 		go func() { |  | ||||||
| 			ticker := time.NewTicker(d) |  | ||||||
| 			for { |  | ||||||
| 				select { |  | ||||||
| 				case <-stop.Done(): |  | ||||||
| 					ticker.Stop() |  | ||||||
| 					return |  | ||||||
| 				case <-ticker.C: |  | ||||||
| 					reporter.UpdateGauge("redis.pool.available", int64(pool.Avail())) |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		}() |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -1,7 +1,6 @@ | |||||||
| package eventsubscribers | package eventsubscribers | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"context" |  | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"net/http/httptest" | 	"net/http/httptest" | ||||||
| 	"testing" | 	"testing" | ||||||
| @@ -401,30 +400,3 @@ func TestStatsReporter(t *testing.T) { | |||||||
| 		}) | 		}) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| type redisPoolCheckableMock struct { |  | ||||||
| 	mock.Mock |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (r *redisPoolCheckableMock) Avail() int { |  | ||||||
| 	return r.Called().Int(0) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestAvailableRedisPoolSizeReporter(t *testing.T) { |  | ||||||
| 	poolMock := &redisPoolCheckableMock{} |  | ||||||
| 	poolMock.On("Avail").Return(5).Times(3) |  | ||||||
| 	reporterMock := &StatsReporterMock{} |  | ||||||
| 	reporterMock.On("UpdateGauge", "redis.pool.available", int64(5)).Times(3) |  | ||||||
|  |  | ||||||
| 	ctx, cancel := context.WithCancel(context.Background()) |  | ||||||
|  |  | ||||||
| 	creator := AvailableRedisPoolSizeReporter(poolMock, 10*time.Millisecond, ctx) |  | ||||||
| 	creator(reporterMock) |  | ||||||
|  |  | ||||||
| 	time.Sleep(35 * time.Millisecond) |  | ||||||
|  |  | ||||||
| 	cancel() |  | ||||||
|  |  | ||||||
| 	poolMock.AssertExpectations(t) |  | ||||||
| 	reporterMock.AssertExpectations(t) |  | ||||||
| } |  | ||||||
|   | |||||||
							
								
								
									
										5
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								go.mod
									
									
									
									
									
								
							| @@ -12,7 +12,7 @@ require ( | |||||||
| 	github.com/etherlabsio/healthcheck/v2 v2.0.0 | 	github.com/etherlabsio/healthcheck/v2 v2.0.0 | ||||||
| 	github.com/getsentry/raven-go v0.2.1-0.20190419175539-919484f041ea | 	github.com/getsentry/raven-go v0.2.1-0.20190419175539-919484f041ea | ||||||
| 	github.com/gorilla/mux v1.8.1 | 	github.com/gorilla/mux v1.8.1 | ||||||
| 	github.com/mediocregopher/radix.v2 v0.0.0-20181115013041-b67df6e626f9 | 	github.com/mediocregopher/radix/v4 v4.1.4 | ||||||
| 	github.com/mono83/slf v0.0.0-20170919161409-79153e9636db | 	github.com/mono83/slf v0.0.0-20170919161409-79153e9636db | ||||||
| 	github.com/spf13/cobra v1.8.0 | 	github.com/spf13/cobra v1.8.0 | ||||||
| 	github.com/spf13/viper v1.18.1 | 	github.com/spf13/viper v1.18.1 | ||||||
| @@ -32,11 +32,9 @@ require ( | |||||||
| 	github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect | 	github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect | ||||||
| 	github.com/hashicorp/hcl v1.0.0 // indirect | 	github.com/hashicorp/hcl v1.0.0 // indirect | ||||||
| 	github.com/inconshreveable/mousetrap v1.1.0 // indirect | 	github.com/inconshreveable/mousetrap v1.1.0 // indirect | ||||||
| 	github.com/levenlabs/golib v0.0.0-20180911183212-0f8974794783 // indirect |  | ||||||
| 	github.com/magiconair/properties v1.8.7 // indirect | 	github.com/magiconair/properties v1.8.7 // indirect | ||||||
| 	github.com/mitchellh/mapstructure v1.5.0 // indirect | 	github.com/mitchellh/mapstructure v1.5.0 // indirect | ||||||
| 	github.com/mono83/udpwriter v1.0.2 // indirect | 	github.com/mono83/udpwriter v1.0.2 // indirect | ||||||
| 	github.com/oschwald/geoip2-golang v1.9.0 // indirect |  | ||||||
| 	github.com/pelletier/go-toml/v2 v2.1.1 // indirect | 	github.com/pelletier/go-toml/v2 v2.1.1 // indirect | ||||||
| 	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect | 	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect | ||||||
| 	github.com/sagikazarmark/locafero v0.4.0 // indirect | 	github.com/sagikazarmark/locafero v0.4.0 // indirect | ||||||
| @@ -47,6 +45,7 @@ require ( | |||||||
| 	github.com/spf13/pflag v1.0.5 // indirect | 	github.com/spf13/pflag v1.0.5 // indirect | ||||||
| 	github.com/stretchr/objx v0.5.0 // indirect | 	github.com/stretchr/objx v0.5.0 // indirect | ||||||
| 	github.com/subosito/gotenv v1.6.0 // indirect | 	github.com/subosito/gotenv v1.6.0 // indirect | ||||||
|  | 	github.com/tilinna/clock v1.0.2 // indirect | ||||||
| 	go.uber.org/multierr v1.11.0 // indirect | 	go.uber.org/multierr v1.11.0 // indirect | ||||||
| 	golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb // indirect | 	golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb // indirect | ||||||
| 	golang.org/x/sys v0.15.0 // indirect | 	golang.org/x/sys v0.15.0 // indirect | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								go.sum
									
									
									
									
									
								
							| @@ -35,12 +35,10 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= | |||||||
| github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= | ||||||
| github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= | ||||||
| github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= | ||||||
| github.com/levenlabs/golib v0.0.0-20180911183212-0f8974794783 h1:ErBsqZpyadTBr2zGsgMau0JdyghyLdwRRHAKJukexrQ= |  | ||||||
| github.com/levenlabs/golib v0.0.0-20180911183212-0f8974794783/go.mod h1:zw8z7nRRkGDZHexz1aMbZGtwxli5so0CBVZeIa3G+RE= |  | ||||||
| github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= | github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= | ||||||
| github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= | github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= | ||||||
| github.com/mediocregopher/radix.v2 v0.0.0-20181115013041-b67df6e626f9 h1:ViNuGS149jgnttqhc6XQNPwdupEMBXqCx9wtlW7P3sA= | github.com/mediocregopher/radix/v4 v4.1.4 h1:Uze6DEbEAvL+VHXUEu/EDBTkUk5CLct5h3nVSGpc6Ts= | ||||||
| github.com/mediocregopher/radix.v2 v0.0.0-20181115013041-b67df6e626f9/go.mod h1:fLRUbhbSd5Px2yKUaGYYPltlyxi1guJz1vCmo1RQL50= | github.com/mediocregopher/radix/v4 v4.1.4/go.mod h1:ajchozX/6ELmydxWeWM6xCFHVpZ4+67LXHOTOVR0nCE= | ||||||
| github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= | github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= | ||||||
| github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= | github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= | ||||||
| github.com/mono83/slf v0.0.0-20170919161409-79153e9636db h1:tlz4fTklh5mttoq5M+0yEc5Lap8W/02A2HCXCJn5iz0= | github.com/mono83/slf v0.0.0-20170919161409-79153e9636db h1:tlz4fTklh5mttoq5M+0yEc5Lap8W/02A2HCXCJn5iz0= | ||||||
| @@ -49,10 +47,6 @@ github.com/mono83/udpwriter v1.0.2 h1:JiQ/N646oZoJA1G0FOMvn2teMt6SdL1KwNH2mszOlQ | |||||||
| github.com/mono83/udpwriter v1.0.2/go.mod h1:mTDiyLtA0tXoxckkV9T4NUkJTgSQIuO8pAUKx/dSRkQ= | github.com/mono83/udpwriter v1.0.2/go.mod h1:mTDiyLtA0tXoxckkV9T4NUkJTgSQIuO8pAUKx/dSRkQ= | ||||||
| github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4= | github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4= | ||||||
| github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= | github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= | ||||||
| github.com/oschwald/geoip2-golang v1.9.0 h1:uvD3O6fXAXs+usU+UGExshpdP13GAqp4GBrzN7IgKZc= |  | ||||||
| github.com/oschwald/geoip2-golang v1.9.0/go.mod h1:BHK6TvDyATVQhKNbQBdrj9eAvuwOMi2zSFXizL3K81Y= |  | ||||||
| github.com/oschwald/maxminddb-golang v1.11.0 h1:aSXMqYR/EPNjGE8epgqwDay+P30hCBZIveY0WZbAWh0= |  | ||||||
| github.com/oschwald/maxminddb-golang v1.11.0/go.mod h1:YmVI+H0zh3ySFR3w+oz8PCfglAFj3PuCmui13+P9zDg= |  | ||||||
| github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= | github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= | ||||||
| github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= | github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= | ||||||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||||
| @@ -81,6 +75,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ | |||||||
| github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= | ||||||
| github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= | github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= | ||||||
| github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= | ||||||
|  | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | ||||||
| github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||||||
| github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||||||
| github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= | ||||||
| @@ -90,6 +85,8 @@ github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8 | |||||||
| github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= | github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= | ||||||
| github.com/thedevsaddam/govalidator v1.9.10 h1:m3dLRbSZ5Hts3VUWYe+vxLMG+FdyQuWOjzTeQRiMCvU= | github.com/thedevsaddam/govalidator v1.9.10 h1:m3dLRbSZ5Hts3VUWYe+vxLMG+FdyQuWOjzTeQRiMCvU= | ||||||
| github.com/thedevsaddam/govalidator v1.9.10/go.mod h1:Ilx8u7cg5g3LXbSS943cx5kczyNuUn7LH/cK5MYuE90= | github.com/thedevsaddam/govalidator v1.9.10/go.mod h1:Ilx8u7cg5g3LXbSS943cx5kczyNuUn7LH/cK5MYuE90= | ||||||
|  | github.com/tilinna/clock v1.0.2 h1:6BO2tyAC9JbPExKH/z9zl44FLu1lImh3nDNKA0kgrkI= | ||||||
|  | github.com/tilinna/clock v1.0.2/go.mod h1:ZsP7BcY7sEEz7ktc0IVy8Us6boDrK8VradlKRUGfOao= | ||||||
| go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= | go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= | ||||||
| go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= | go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= | ||||||
| golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb h1:c0vyKkb6yr3KR7jEfJaOSv4lG7xPkbN6r52aJz1d8a8= | golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb h1:c0vyKkb6yr3KR7jEfJaOSv4lG7xPkbN6r52aJz1d8a8= | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user