Skip to content

Commit

Permalink
#1: Implement UuidsStorage in Redis
Browse files Browse the repository at this point in the history
  • Loading branch information
erickskrauch committed Apr 24, 2019
1 parent 533afcc commit f369068
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 7 deletions.
4 changes: 3 additions & 1 deletion db/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package db
import (
"github.com/spf13/viper"

"github.com/elyby/chrly/api/mojang/queue"
"github.com/elyby/chrly/interfaces"
)

Expand All @@ -13,6 +14,7 @@ type StorageFactory struct {
type RepositoriesCreator interface {
CreateSkinsRepository() (interfaces.SkinsRepository, error)
CreateCapesRepository() (interfaces.CapesRepository, error)
CreateMojangUuidsRepository() (queue.UuidsStorage, error)
}

func (factory *StorageFactory) CreateFactory(backend string) RepositoriesCreator {
Expand All @@ -25,7 +27,7 @@ func (factory *StorageFactory) CreateFactory(backend string) RepositoriesCreator
}
case "filesystem":
return &FilesystemFactory{
BasePath : factory.Config.GetString("storage.filesystem.basePath"),
BasePath: factory.Config.GetString("storage.filesystem.basePath"),
CapesDirName: factory.Config.GetString("storage.filesystem.capesDirName"),
}
}
Expand Down
9 changes: 7 additions & 2 deletions db/filesystem.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ import (
"path"
"strings"

"github.com/elyby/chrly/api/mojang/queue"
"github.com/elyby/chrly/interfaces"
"github.com/elyby/chrly/model"
)

type FilesystemFactory struct {
BasePath string
BasePath string
CapesDirName string
}

Expand All @@ -26,6 +27,10 @@ func (f FilesystemFactory) CreateCapesRepository() (interfaces.CapesRepository,
return &filesStorage{path: path.Join(f.BasePath, f.CapesDirName)}, nil
}

func (f FilesystemFactory) CreateMojangUuidsRepository() (queue.UuidsStorage, error) {
panic("implement me")
}

func (f FilesystemFactory) validateFactoryConfig() error {
if f.BasePath == "" {
return &ParamRequired{"basePath"}
Expand All @@ -47,7 +52,7 @@ func (repository *filesStorage) FindByUsername(username string) (*model.Cape, er
return nil, &CapeNotFoundError{username}
}

capePath := path.Join(repository.path, strings.ToLower(username) + ".png")
capePath := path.Join(repository.path, strings.ToLower(username)+".png")
file, err := os.Open(capePath)
if err != nil {
return nil, &CapeNotFoundError{username}
Expand Down
51 changes: 47 additions & 4 deletions db/redis.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import (
"fmt"
"io"
"log"
"strconv"
"strings"
"time"

"github.com/mediocregopher/radix.v2/pool"
"github.com/mediocregopher/radix.v2/redis"
"github.com/mediocregopher/radix.v2/util"

"github.com/elyby/chrly/api/mojang/queue"
"github.com/elyby/chrly/interfaces"
"github.com/elyby/chrly/model"
)
Expand All @@ -27,7 +29,20 @@ type RedisFactory struct {

// TODO: maybe we should manually return connection to the pool?

// TODO: Why isn't a pointer used here?
func (f RedisFactory) CreateSkinsRepository() (interfaces.SkinsRepository, error) {
return f.createInstance()
}

func (f RedisFactory) CreateCapesRepository() (interfaces.CapesRepository, error) {
panic("capes repository not supported for this storage type")
}

func (f RedisFactory) CreateMojangUuidsRepository() (queue.UuidsStorage, error) {
return f.createInstance()
}

func (f RedisFactory) createInstance() (*redisDb, error) {
connection, err := f.getConnection()
if err != nil {
return nil, err
Expand All @@ -36,10 +51,6 @@ func (f RedisFactory) CreateSkinsRepository() (interfaces.SkinsRepository, error
return &redisDb{connection}, nil
}

func (f RedisFactory) CreateCapesRepository() (interfaces.CapesRepository, error) {
panic("capes repository not supported for this storage type")
}

func (f RedisFactory) getConnection() (*pool.Pool, error) {
if f.connection == nil {
if f.Host == "" {
Expand Down Expand Up @@ -89,7 +100,9 @@ type redisDb struct {
}

const accountIdToUsernameKey = "hash:username-to-account-id"
const mojangUsernameToUuidKey = "hash:mojang-username-to-uuid"

// TODO: return connection to the pool after usage
func (db *redisDb) FindByUsername(username string) (*model.Skin, error) {
return findByUsername(username, db.getConn())
}
Expand All @@ -110,6 +123,14 @@ func (db *redisDb) RemoveByUsername(username string) error {
return removeByUsername(username, db.getConn())
}

func (db *redisDb) GetUuid(username string) (string, error) {
return findMojangUuidByUsername(username, db.getConn())
}

func (db *redisDb) StoreUuid(username string, uuid string) {
storeMojangUuid(username, uuid, db.getConn())
}

func (db *redisDb) getConn() util.Cmder {
conn, _ := db.conn.Get()
return conn
Expand Down Expand Up @@ -221,6 +242,28 @@ func save(skin *model.Skin, conn util.Cmder) error {
return nil
}

func findMojangUuidByUsername(username string, conn util.Cmder) (string, error) {
response := conn.Cmd("HGET", mojangUsernameToUuidKey, strings.ToLower(username))
if response.IsType(redis.Nil) {
return "", &queue.ValueNotFound{}
}

data, _ := response.Str()
parts := strings.Split(data, ":")
timestamp, _ := strconv.ParseInt(parts[1], 10, 64)
storedAt := time.Unix(timestamp, 0)
if storedAt.Add(time.Hour * 24 * 30).Before(time.Now()) {
return "", &queue.ValueNotFound{}
}

return parts[0], nil
}

func storeMojangUuid(username string, uuid string, conn util.Cmder) {
value := uuid + ":" + strconv.FormatInt(time.Now().Unix(), 10)
conn.Cmd("HSET", mojangUsernameToUuidKey, strings.ToLower(username), value)
}

func buildUsernameKey(username string) string {
return "username:" + strings.ToLower(username)
}
Expand Down

0 comments on commit f369068

Please sign in to comment.