mirror of
https://github.com/elyby/chrly.git
synced 2024-11-22 21:23:17 +05:30
Fixes #8. Replace radix v2 with v4
This commit is contained in:
parent
d678f61df7
commit
883a7bda3c
@ -13,6 +13,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Changed
|
||||
- Bumped Go version to 1.21.
|
||||
|
||||
### Removed
|
||||
- StatsD metrics:
|
||||
- Gauges:
|
||||
- `ely.skinsystem.{hostname}.app.redis.pool.available`
|
||||
|
||||
## [4.6.0] - 2021-03-04
|
||||
### Added
|
||||
- `/profile/{username}` endpoint, which returns a profile and its textures, equivalent of the Mojang's
|
||||
|
@ -3,6 +3,7 @@ package redis
|
||||
import (
|
||||
"bytes"
|
||||
"compress/zlib"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
@ -10,23 +11,22 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mediocregopher/radix.v2/pool"
|
||||
"github.com/mediocregopher/radix.v2/redis"
|
||||
"github.com/mediocregopher/radix.v2/util"
|
||||
"github.com/mediocregopher/radix/v4"
|
||||
|
||||
"github.com/elyby/chrly/model"
|
||||
)
|
||||
|
||||
var now = time.Now
|
||||
|
||||
func New(addr string, poolSize int) (*Redis, error) {
|
||||
conn, err := pool.New("tcp", addr, poolSize)
|
||||
func New(ctx context.Context, addr string, poolSize int) (*Redis, error) {
|
||||
client, err := (radix.PoolConfig{Size: poolSize}).New(ctx, "tcp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Redis{
|
||||
pool: conn,
|
||||
client: client,
|
||||
context: ctx,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -34,27 +34,34 @@ const accountIdToUsernameKey = "hash:username-to-account-id" // TODO: this shoul
|
||||
const mojangUsernameToUuidKey = "hash:mojang-username-to-uuid"
|
||||
|
||||
type Redis struct {
|
||||
pool *pool.Pool
|
||||
client radix.Client
|
||||
context context.Context
|
||||
}
|
||||
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
defer db.pool.Put(conn)
|
||||
|
||||
return findByUsername(username, conn)
|
||||
}
|
||||
|
||||
func findByUsername(username string, conn util.Cmder) (*model.Skin, error) {
|
||||
redisKey := buildUsernameKey(username)
|
||||
response := conn.Cmd("GET", redisKey)
|
||||
if response.IsType(redis.Nil) {
|
||||
if len(encodedResult) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
encodedResult, _ := response.Bytes()
|
||||
result, err := zlibDecode(encodedResult)
|
||||
if err != nil {
|
||||
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) {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
defer db.pool.Put(conn)
|
||||
|
||||
return findByUserId(id, conn)
|
||||
}
|
||||
|
||||
func findByUserId(id int, conn util.Cmder) (*model.Skin, error) {
|
||||
response := conn.Cmd("HGET", accountIdToUsernameKey, id)
|
||||
if response.IsType(redis.Nil) {
|
||||
if username == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
username, err := response.Str()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return findByUsername(username, conn)
|
||||
return findByUsername(ctx, conn, username)
|
||||
}
|
||||
|
||||
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 {
|
||||
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 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 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)
|
||||
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
|
||||
|
||||
@ -129,45 +146,45 @@ func save(skin *model.Skin, conn util.Cmder) error {
|
||||
}
|
||||
|
||||
func (db *Redis) RemoveSkinByUserId(id int) error {
|
||||
conn, err := db.pool.Get()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer db.pool.Put(conn)
|
||||
|
||||
return removeByUserId(id, conn)
|
||||
return db.client.Do(db.context, radix.WithConn("", func(ctx context.Context, conn radix.Conn) error {
|
||||
return removeByUserId(ctx, conn, id)
|
||||
}))
|
||||
}
|
||||
|
||||
func removeByUserId(id int, conn util.Cmder) error {
|
||||
record, err := findByUserId(id, conn)
|
||||
func removeByUserId(ctx context.Context, conn radix.Conn, id int) error {
|
||||
record, err := findByUserId(ctx, conn, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
conn.Cmd("MULTI")
|
||||
|
||||
conn.Cmd("HDEL", accountIdToUsernameKey, id)
|
||||
if record != nil {
|
||||
conn.Cmd("DEL", buildUsernameKey(record.Username))
|
||||
err = conn.Do(ctx, radix.Cmd(nil, "MULTI"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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 {
|
||||
conn, err := db.pool.Get()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer db.pool.Put(conn)
|
||||
|
||||
return removeByUsername(username, conn)
|
||||
return db.client.Do(db.context, radix.WithConn("", func(ctx context.Context, conn radix.Conn) error {
|
||||
return removeByUsername(ctx, conn, username)
|
||||
}))
|
||||
}
|
||||
|
||||
func removeByUsername(username string, conn util.Cmder) error {
|
||||
record, err := findByUsername(username, conn)
|
||||
func removeByUsername(ctx context.Context, conn radix.Conn, username string) error {
|
||||
record, err := findByUsername(ctx, conn, username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -176,45 +193,68 @@ func removeByUsername(username string, conn util.Cmder) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
conn.Cmd("MULTI")
|
||||
err = conn.Do(ctx, radix.Cmd(nil, "MULTI"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
conn.Cmd("DEL", buildUsernameKey(record.Username))
|
||||
conn.Cmd("HDEL", accountIdToUsernameKey, record.UserId)
|
||||
err = conn.Do(ctx, radix.Cmd(nil, "DEL", buildUsernameKey(record.Username)))
|
||||
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) {
|
||||
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 {
|
||||
return "", false, err
|
||||
}
|
||||
defer db.pool.Put(conn)
|
||||
|
||||
return findMojangUuidByUsername(username, conn)
|
||||
}
|
||||
|
||||
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) {
|
||||
if result == "" {
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
data, _ := response.Str()
|
||||
parts := strings.Split(data, ":")
|
||||
parts := strings.Split(result, ":")
|
||||
// https://github.com/elyby/chrly/issues/28
|
||||
if len(parts) < 2 {
|
||||
conn.Cmd("HDEL", mojangUsernameToUuidKey, key)
|
||||
return "", false, fmt.Errorf("Got unexpected response from the mojangUsernameToUuid hash: \"%s\"", data)
|
||||
err = conn.Do(ctx, radix.Cmd(nil, "HDEL", mojangUsernameToUuidKey, key))
|
||||
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)
|
||||
storedAt := time.Unix(timestamp, 0)
|
||||
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
|
||||
}
|
||||
|
||||
@ -222,36 +262,23 @@ func findMojangUuidByUsername(username string, conn util.Cmder) (string, bool, e
|
||||
}
|
||||
|
||||
func (db *Redis) StoreUuid(username string, uuid string) error {
|
||||
conn, err := db.pool.Get()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer db.pool.Put(conn)
|
||||
|
||||
return storeMojangUuid(username, uuid, conn)
|
||||
return db.client.Do(db.context, radix.WithConn("", func(ctx context.Context, conn radix.Conn) error {
|
||||
return storeMojangUuid(ctx, conn, username, uuid)
|
||||
}))
|
||||
}
|
||||
|
||||
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)
|
||||
res := conn.Cmd("HSET", mojangUsernameToUuidKey, strings.ToLower(username), value)
|
||||
if res.IsType(redis.Err) {
|
||||
return res.Err
|
||||
err := conn.Do(ctx, radix.Cmd(nil, "HSET", mojangUsernameToUuidKey, strings.ToLower(username), value))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Redis) Ping() error {
|
||||
r := db.pool.Cmd("PING")
|
||||
if r.Err != nil {
|
||||
return r.Err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Redis) Avail() int {
|
||||
return db.pool.Avail()
|
||||
return db.client.Do(db.context, radix.Cmd(nil, "PING"))
|
||||
}
|
||||
|
||||
func buildUsernameKey(username string) string {
|
||||
|
@ -1,17 +1,16 @@
|
||||
//go:build redis
|
||||
// +build redis
|
||||
|
||||
package redis
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/mediocregopher/radix.v2/redis"
|
||||
"github.com/mediocregopher/radix/v4"
|
||||
assert "github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
@ -36,15 +35,13 @@ func init() {
|
||||
|
||||
func TestNew(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.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) {
|
||||
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.Nil(t, conn)
|
||||
})
|
||||
@ -55,21 +52,30 @@ type redisTestSuite struct {
|
||||
|
||||
Redis *Redis
|
||||
|
||||
cmd func(cmd string, args ...interface{}) *redis.Resp
|
||||
cmd func(cmd string, args ...interface{}) string
|
||||
}
|
||||
|
||||
func (suite *redisTestSuite) SetupSuite() {
|
||||
conn, err := New(redisAddr, 10)
|
||||
ctx := context.Background()
|
||||
conn, err := New(ctx, redisAddr, 10)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot establish connection to redis: %w", err))
|
||||
}
|
||||
|
||||
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() {
|
||||
// Cleanup database before the each test
|
||||
// Cleanup database before each test
|
||||
suite.cmd("FLUSHALL")
|
||||
}
|
||||
|
||||
@ -101,7 +107,7 @@ func TestRedis(t *testing.T) {
|
||||
* 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,
|
||||
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,
|
||||
@ -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,
|
||||
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,
|
||||
}
|
||||
})
|
||||
|
||||
func (suite *redisTestSuite) TestFindSkinByUsername() {
|
||||
suite.RunSubTest("exists record", func() {
|
||||
@ -198,14 +204,11 @@ func (suite *redisTestSuite) TestSaveSkin() {
|
||||
suite.Require().Nil(err)
|
||||
|
||||
usernameResp := suite.cmd("GET", "username:mock")
|
||||
suite.Require().False(usernameResp.IsType(redis.Nil))
|
||||
bytes, _ := usernameResp.Bytes()
|
||||
suite.Require().Equal(skinRecord, bytes)
|
||||
suite.Require().NotEmpty(usernameResp)
|
||||
suite.Require().Equal(skinRecord, usernameResp)
|
||||
|
||||
idResp := suite.cmd("HGET", "hash:username-to-account-id", 1)
|
||||
suite.Require().False(usernameResp.IsType(redis.Nil))
|
||||
str, _ := idResp.Str()
|
||||
suite.Require().Equal("Mock", str)
|
||||
suite.Require().Equal("Mock", idResp)
|
||||
})
|
||||
|
||||
suite.RunSubTest("save exists record with changed username", func() {
|
||||
@ -227,9 +230,8 @@ func (suite *redisTestSuite) TestSaveSkin() {
|
||||
suite.Require().Nil(err)
|
||||
|
||||
usernameResp := suite.cmd("GET", "username:newmock")
|
||||
suite.Require().False(usernameResp.IsType(redis.Nil))
|
||||
bytes, _ := usernameResp.Bytes()
|
||||
suite.Require().Equal([]byte{
|
||||
suite.Require().NotEmpty(usernameResp)
|
||||
suite.Require().Equal(string([]byte{
|
||||
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,
|
||||
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,
|
||||
0x6e, 0xf0, 0xec, 0xe5, 0xf5, 0x3f, 0xf9, 0xdc, 0xfb, 0xfd, 0x13, 0x0, 0x0, 0xff, 0xff, 0xca, 0xc3, 0x54,
|
||||
0x25,
|
||||
}, bytes)
|
||||
}), usernameResp)
|
||||
|
||||
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)
|
||||
suite.Require().False(usernameResp.IsType(redis.Nil))
|
||||
str, _ := idResp.Str()
|
||||
suite.Require().Equal("NewMock", str)
|
||||
suite.Require().NotEmpty(usernameResp)
|
||||
suite.Require().Equal("NewMock", idResp)
|
||||
})
|
||||
}
|
||||
|
||||
@ -262,10 +263,10 @@ func (suite *redisTestSuite) TestRemoveSkinByUserId() {
|
||||
suite.Require().Nil(err)
|
||||
|
||||
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)
|
||||
suite.Require().True(idResp.IsType(redis.Nil))
|
||||
suite.Require().Empty(idResp)
|
||||
})
|
||||
|
||||
suite.RunSubTest("exists only id", func() {
|
||||
@ -275,7 +276,7 @@ func (suite *redisTestSuite) TestRemoveSkinByUserId() {
|
||||
suite.Require().Nil(err)
|
||||
|
||||
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() {
|
||||
@ -296,10 +297,10 @@ func (suite *redisTestSuite) TestRemoveSkinByUsername() {
|
||||
suite.Require().Nil(err)
|
||||
|
||||
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)
|
||||
suite.Require().True(idResp.IsType(redis.Nil))
|
||||
suite.Require().Empty(idResp)
|
||||
})
|
||||
|
||||
suite.RunSubTest("exists only username", func() {
|
||||
@ -309,7 +310,7 @@ func (suite *redisTestSuite) TestRemoveSkinByUsername() {
|
||||
suite.Require().Nil(err)
|
||||
|
||||
usernameResp := suite.cmd("GET", "username:mock")
|
||||
suite.Require().True(usernameResp.IsType(redis.Nil))
|
||||
suite.Require().Empty(usernameResp)
|
||||
})
|
||||
|
||||
suite.RunSubTest("no records", func() {
|
||||
@ -372,7 +373,7 @@ func (suite *redisTestSuite) TestGetUuid() {
|
||||
suite.Require().Nil(err)
|
||||
|
||||
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() {
|
||||
@ -388,7 +389,7 @@ func (suite *redisTestSuite) TestGetUuid() {
|
||||
suite.Require().Error(err, "Got unexpected response from the mojangUsernameToUuid hash: \"corrupted value\"")
|
||||
|
||||
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)
|
||||
|
||||
resp := suite.cmd("HGET", "hash:mojang-username-to-uuid", "mock")
|
||||
suite.Require().False(resp.IsType(redis.Nil))
|
||||
str, _ := resp.Str()
|
||||
suite.Require().Equal(str, "d3ca513eb3e14946b58047f2bd3530fd:1587435016")
|
||||
suite.Require().Equal(resp, "d3ca513eb3e14946b58047f2bd3530fd:1587435016")
|
||||
})
|
||||
|
||||
suite.RunSubTest("store empty uuid", func() {
|
||||
@ -416,9 +415,7 @@ func (suite *redisTestSuite) TestStoreUuid() {
|
||||
suite.Require().Nil(err)
|
||||
|
||||
resp := suite.cmd("HGET", "hash:mojang-username-to-uuid", "mock")
|
||||
suite.Require().False(resp.IsType(redis.Nil))
|
||||
str, _ := resp.Str()
|
||||
suite.Require().Equal(str, ":1587435016")
|
||||
suite.Require().Equal(resp, ":1587435016")
|
||||
})
|
||||
}
|
||||
|
||||
@ -426,8 +423,3 @@ func (suite *redisTestSuite) TestPing() {
|
||||
err := suite.Redis.Ping()
|
||||
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"
|
||||
"fmt"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/defval/di"
|
||||
"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)
|
||||
|
||||
conn, err := redis.New(
|
||||
context.Background(),
|
||||
fmt.Sprintf("%s:%d", config.GetString("storage.redis.host"), config.GetInt("storage.redis.port")),
|
||||
config.GetInt("storage.redis.poolSize"),
|
||||
)
|
||||
@ -45,12 +45,6 @@ func newRedis(container *di.Container, config *viper.Viper) (*redis.Redis, error
|
||||
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 {
|
||||
return &namedHealthChecker{
|
||||
Name: "redis",
|
||||
|
@ -1,7 +1,6 @@
|
||||
package eventsubscribers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -30,7 +29,7 @@ func (f ReporterFunc) Enable(reporter slf.StatsReporter) {
|
||||
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) {
|
||||
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))
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http/httptest"
|
||||
"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/getsentry/raven-go v0.2.1-0.20190419175539-919484f041ea
|
||||
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/spf13/cobra v1.8.0
|
||||
github.com/spf13/viper v1.18.1
|
||||
@ -32,11 +32,9 @@ require (
|
||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect
|
||||
github.com/hashicorp/hcl v1.0.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/mitchellh/mapstructure v1.5.0 // 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/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||
@ -47,6 +45,7 @@ require (
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/stretchr/objx v0.5.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
|
||||
golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb // 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/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
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/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mediocregopher/radix.v2 v0.0.0-20181115013041-b67df6e626f9 h1:ViNuGS149jgnttqhc6XQNPwdupEMBXqCx9wtlW7P3sA=
|
||||
github.com/mediocregopher/radix.v2 v0.0.0-20181115013041-b67df6e626f9/go.mod h1:fLRUbhbSd5Px2yKUaGYYPltlyxi1guJz1vCmo1RQL50=
|
||||
github.com/mediocregopher/radix/v4 v4.1.4 h1:Uze6DEbEAvL+VHXUEu/EDBTkUk5CLct5h3nVSGpc6Ts=
|
||||
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/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
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/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/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/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||
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.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||
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.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
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/thedevsaddam/govalidator v1.9.10 h1:m3dLRbSZ5Hts3VUWYe+vxLMG+FdyQuWOjzTeQRiMCvU=
|
||||
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/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb h1:c0vyKkb6yr3KR7jEfJaOSv4lG7xPkbN6r52aJz1d8a8=
|
||||
|
Loading…
Reference in New Issue
Block a user