From b99697d26e90e3ce73ed2e2f054a59fdef9b4999 Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Mon, 14 Aug 2017 21:06:22 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=BE=D0=BF=D1=8B=D1=82=D0=BA=D0=B0=20?= =?UTF-8?q?=D1=81=D0=B4=D0=B5=D0=BB=D0=B0=D1=82=D1=8C=20=D1=84=D0=B0=D0=B1?= =?UTF-8?q?=D1=80=D0=B8=D0=BA=D0=B8=20=D1=80=D0=B5=D0=BF=D0=BE=D0=B7=D0=B8?= =?UTF-8?q?=D1=82=D0=BE=D1=80=D0=B8=D0=B5=D0=B2=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=B0=D0=B1=D1=81=D1=82=D1=80=D0=B0=D0=BA=D1=82=D0=BD=D1=8B?= =?UTF-8?q?=D1=85=20=D1=85=D1=80=D0=B0=D0=BD=D0=B8=D0=BB=D0=B8=D1=89=20?= =?UTF-8?q?=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85.=20=D0=94=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=BE=20=D1=87=D1=82=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=BA=D0=BE=D0=BD=D1=84=D0=B8=D0=B3=D1=83=D1=80?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D0=B8=20=D0=B8=D0=B7=20=D1=84=D0=B0=D0=B9?= =?UTF-8?q?=D0=BB=D0=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/serve.go | 39 +++++++++------------------ daemon/http.go | 8 +++--- db/capes/base.go | 17 ------------ db/capes/filesystem.go | 39 --------------------------- db/commons.go | 25 +++++++++++++++++ db/factory.go | 34 +++++++++++++++++++++++ db/filesystem.go | 60 +++++++++++++++++++++++++++++++++++++++++ db/{skins => }/redis.go | 54 ++++++++++++++++++++++++++++++------- db/skins/base.go | 17 ------------ 9 files changed, 178 insertions(+), 115 deletions(-) delete mode 100644 db/capes/base.go delete mode 100644 db/capes/filesystem.go create mode 100644 db/commons.go create mode 100644 db/factory.go create mode 100644 db/filesystem.go rename db/{skins => }/redis.go (62%) delete mode 100644 db/skins/base.go diff --git a/cmd/serve.go b/cmd/serve.go index d505a83..adeae9e 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -2,18 +2,15 @@ package cmd import ( "fmt" - "path" - "path/filepath" - "runtime" "github.com/mono83/slf/rays" "github.com/mono83/slf/recievers/ansi" "github.com/mono83/slf/wd" "github.com/spf13/cobra" + "github.com/spf13/viper" "elyby/minecraft-skinsystem/daemon" - "elyby/minecraft-skinsystem/db/capes" - "elyby/minecraft-skinsystem/db/skins" + "elyby/minecraft-skinsystem/db" "elyby/minecraft-skinsystem/ui" ) @@ -23,41 +20,29 @@ var serveCmd = &cobra.Command{ Short: "Запускает сервер системы скинов", Long: "Более длинное описание пока не было придумано", Run: func(cmd *cobra.Command, args []string) { - // TODO: извлечь все инициализации зависимостей в парсер конфигурации - - // Logger wd.AddReceiver(ansi.New(true, true, false)) logger := wd.New("", "").WithParams(rays.Host) - // Skins repository - logger.Info("Connecting to redis") - skinsRepoCfg := &skins.RedisSkinsFactory{ - //Addr: "redis:6379", - Addr: "localhost:16379", - PollSize: 10, - } - skinsRepo, err := skinsRepoCfg.Create() + storageFactory := db.StorageFactory{Config: viper.GetViper()} + + logger.Info("Initializing skins repository") + skinsRepo, err := storageFactory.CreateFactory("redis").CreateSkinsRepository() if err != nil { - logger.Emergency(fmt.Sprintf("Error on creating skins repo: %v", err)) + logger.Emergency(fmt.Sprintf("Error on creating skins repo: %+v", err)) return } - logger.Info("Successfully connected to redis") + logger.Info("Skins repository successfully initialized") - // Capes repository - _, file, _, _ := runtime.Caller(0) - capesRepoCfg := &capes.FilesystemCapesFactory{ - StoragePath: path.Join(filepath.Dir(file), "data/capes"), - } - capesRepo, err := capesRepoCfg.Create() + logger.Info("Initializing capes repository") + capesRepo, err := storageFactory.CreateFactory("filesystem").CreateCapesRepository() if err != nil { logger.Emergency(fmt.Sprintf("Error on creating capes repo: %v", err)) return } - - + logger.Info("Capes repository successfully initialized") cfg := &daemon.Config{ - ListenSpec: "localhost:35644", + ListenSpec: fmt.Sprintf("%s:%d", viper.GetString("server.host"), viper.GetInt("server.port")), SkinsRepo: skinsRepo, CapesRepo: capesRepo, Logger: logger, diff --git a/daemon/http.go b/daemon/http.go index 978a424..60bb15b 100644 --- a/daemon/http.go +++ b/daemon/http.go @@ -1,18 +1,16 @@ package daemon import ( - "net" - - "elyby/minecraft-skinsystem/ui" - "fmt" - + "net" "os" "os/signal" "syscall" "github.com/mono83/slf/wd" + "elyby/minecraft-skinsystem/repositories" + "elyby/minecraft-skinsystem/ui" ) type Config struct { diff --git a/db/capes/base.go b/db/capes/base.go deleted file mode 100644 index d0903fc..0000000 --- a/db/capes/base.go +++ /dev/null @@ -1,17 +0,0 @@ -package capes - -import ( - "elyby/minecraft-skinsystem/repositories" -) - -type CapesRepositoryCreator interface { - Create() (repositories.CapesRepository, error) -} - -type CapeNotFoundError struct { - Who string -} - -func (e CapeNotFoundError) Error() string { - return "Cape file not found." -} diff --git a/db/capes/filesystem.go b/db/capes/filesystem.go deleted file mode 100644 index f791305..0000000 --- a/db/capes/filesystem.go +++ /dev/null @@ -1,39 +0,0 @@ -package capes - -import ( - "os" - "path" - "strings" - - "elyby/minecraft-skinsystem/model" - "elyby/minecraft-skinsystem/repositories" -) - -type FilesystemCapesFactory struct { - StoragePath string -} - -func (cfg *FilesystemCapesFactory) Create() (repositories.CapesRepository, error) { - return &filesDb{path: cfg.StoragePath}, nil -} - -type filesDb struct { - path string -} - -func (repository *filesDb) FindByUsername(username string) (model.Cape, error) { - var record model.Cape - if username == "" { - return record, &CapeNotFoundError{username} - } - - capePath := path.Join(repository.path, strings.ToLower(username) + ".png") - file, err := os.Open(capePath) - if err != nil { - return record, &CapeNotFoundError{username} - } - - record.File = file - - return record, nil -} diff --git a/db/commons.go b/db/commons.go new file mode 100644 index 0000000..55be43e --- /dev/null +++ b/db/commons.go @@ -0,0 +1,25 @@ +package db + +type ParamRequired struct { + Param string +} + +func (e ParamRequired) Error() string { + return "Required parameter not provided" +} + +type SkinNotFoundError struct { + Who string +} + +func (e SkinNotFoundError) Error() string { + return "Skin data not found." +} + +type CapeNotFoundError struct { + Who string +} + +func (e CapeNotFoundError) Error() string { + return "Cape file not found." +} diff --git a/db/factory.go b/db/factory.go new file mode 100644 index 0000000..5c2eb33 --- /dev/null +++ b/db/factory.go @@ -0,0 +1,34 @@ +package db + +import ( + "github.com/spf13/viper" + + "elyby/minecraft-skinsystem/repositories" +) + +type StorageFactory struct { + Config *viper.Viper +} + +type RepositoriesCreator interface { + CreateSkinsRepository() (repositories.SkinsRepository, error) + CreateCapesRepository() (repositories.CapesRepository, error) +} + +func (factory *StorageFactory) CreateFactory(backend string) RepositoriesCreator { + switch backend { + case "redis": + return &RedisFactory{ + Host: factory.Config.GetString("storage.redis.host"), + Port: factory.Config.GetInt("storage.redis.port"), + PoolSize: factory.Config.GetInt("storage.redis.poolSize"), + } + case "filesystem": + return &FilesystemFactory{ + BasePath : factory.Config.GetString("storage.filesystem.basePath"), + CapesDirName: factory.Config.GetString("storage.filesystem.capesDirName"), + } + } + + return nil +} diff --git a/db/filesystem.go b/db/filesystem.go new file mode 100644 index 0000000..3fb2f03 --- /dev/null +++ b/db/filesystem.go @@ -0,0 +1,60 @@ +package db + +import ( + "os" + "path" + "strings" + + "elyby/minecraft-skinsystem/model" + "elyby/minecraft-skinsystem/repositories" +) + +type FilesystemFactory struct { + BasePath string + CapesDirName string +} + +func (f FilesystemFactory) CreateSkinsRepository() (repositories.SkinsRepository, error) { + panic("skins repository not supported for this storage type") +} + +func (f FilesystemFactory) CreateCapesRepository() (repositories.CapesRepository, error) { + if err := f.validateFactoryConfig(); err != nil { + return nil, err + } + + return &filesStorage{path: path.Join(f.BasePath, f.CapesDirName)}, nil +} + +func (f FilesystemFactory) validateFactoryConfig() error { + if f.BasePath == "" { + return &ParamRequired{"basePath"} + } + + if f.CapesDirName == "" { + f.CapesDirName = "capes" + } + + return nil +} + +type filesStorage struct { + path string +} + +func (repository *filesStorage) FindByUsername(username string) (model.Cape, error) { + var record model.Cape + if username == "" { + return record, &CapeNotFoundError{username} + } + + capePath := path.Join(repository.path, strings.ToLower(username) + ".png") + file, err := os.Open(capePath) + if err != nil { + return record, &CapeNotFoundError{username} + } + + record.File = file + + return record, nil +} diff --git a/db/skins/redis.go b/db/redis.go similarity index 62% rename from db/skins/redis.go rename to db/redis.go index 56e0ad6..19ab91b 100644 --- a/db/skins/redis.go +++ b/db/redis.go @@ -1,9 +1,10 @@ -package skins +package db import ( "bytes" "compress/zlib" "encoding/json" + "fmt" "io" "log" "strings" @@ -16,20 +17,53 @@ import ( "elyby/minecraft-skinsystem/repositories" ) -type RedisSkinsFactory struct { - Addr string - PollSize int +type RedisFactory struct { + Host string + Port int + PoolSize int + connection util.Cmder } -func (cfg *RedisSkinsFactory) Create() (repositories.SkinsRepository, error) { - conn, err := pool.New("tcp", cfg.Addr, cfg.PollSize) +func (f RedisFactory) CreateSkinsRepository() (repositories.SkinsRepository, error) { + connection, err := f.getConnection() if err != nil { return nil, err } - // TODO: здесь можно запустить горутину по восстановлению соединения + return &redisDb{connection}, nil +} - return &redisDb{conn: conn}, nil +func (f RedisFactory) CreateCapesRepository() (repositories.CapesRepository, error) { + panic("capes repository not supported for this storage type") +} + +func (f RedisFactory) getConnection() (util.Cmder, error) { + if f.connection == nil { + if f.Host == "" { + return nil, &ParamRequired{"host"} + } + + if f.Port == 0 { + return nil, &ParamRequired{"port"} + } + + var conn util.Cmder + var err error + addr := fmt.Sprintf("%s:%d", f.Host, f.Port) + if f.PoolSize > 1 { + conn, err = pool.New("tcp", addr, f.PoolSize) + } else { + conn, err = redis.Dial("tcp", addr) + } + + if err != nil { + return nil, err + } + + f.connection = conn + } + + return f.connection, nil } type redisDb struct { @@ -54,13 +88,13 @@ func (db *redisDb) FindByUsername(username string) (model.Skin, error) { if err == nil { result, err := zlibDecode(encodedResult) if err != nil { - log.Println("Cannot uncompress zlib for key " + redisKey) + log.Println("Cannot uncompress zlib for key " + redisKey) // TODO: replace with valid error return record, err } err = json.Unmarshal(result, &record) if err != nil { - log.Println("Cannot decode record data for key" + redisKey) + log.Println("Cannot decode record data for key" + redisKey) // TODO: replace with valid error return record, nil } diff --git a/db/skins/base.go b/db/skins/base.go deleted file mode 100644 index 9da5fbc..0000000 --- a/db/skins/base.go +++ /dev/null @@ -1,17 +0,0 @@ -package skins - -import ( - "elyby/minecraft-skinsystem/repositories" -) - -type SkinsRepositoryCreator interface { - Create() (repositories.SkinsRepository, error) -} - -type SkinNotFoundError struct { - Who string -} - -func (e SkinNotFoundError) Error() string { - return "Skin data not found." -}