mirror of
https://github.com/elyby/chrly.git
synced 2024-11-30 02:32:19 +05:30
Попытка сделать фабрики репозиториев для абстрактных хранилищ данных.
Добавлено чтение конфигурации из файла.
This commit is contained in:
parent
d51c358ef6
commit
b99697d26e
39
cmd/serve.go
39
cmd/serve.go
@ -2,18 +2,15 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
|
|
||||||
"github.com/mono83/slf/rays"
|
"github.com/mono83/slf/rays"
|
||||||
"github.com/mono83/slf/recievers/ansi"
|
"github.com/mono83/slf/recievers/ansi"
|
||||||
"github.com/mono83/slf/wd"
|
"github.com/mono83/slf/wd"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
"elyby/minecraft-skinsystem/daemon"
|
"elyby/minecraft-skinsystem/daemon"
|
||||||
"elyby/minecraft-skinsystem/db/capes"
|
"elyby/minecraft-skinsystem/db"
|
||||||
"elyby/minecraft-skinsystem/db/skins"
|
|
||||||
"elyby/minecraft-skinsystem/ui"
|
"elyby/minecraft-skinsystem/ui"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -23,41 +20,29 @@ var serveCmd = &cobra.Command{
|
|||||||
Short: "Запускает сервер системы скинов",
|
Short: "Запускает сервер системы скинов",
|
||||||
Long: "Более длинное описание пока не было придумано",
|
Long: "Более длинное описание пока не было придумано",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
// TODO: извлечь все инициализации зависимостей в парсер конфигурации
|
|
||||||
|
|
||||||
// Logger
|
|
||||||
wd.AddReceiver(ansi.New(true, true, false))
|
wd.AddReceiver(ansi.New(true, true, false))
|
||||||
logger := wd.New("", "").WithParams(rays.Host)
|
logger := wd.New("", "").WithParams(rays.Host)
|
||||||
|
|
||||||
// Skins repository
|
storageFactory := db.StorageFactory{Config: viper.GetViper()}
|
||||||
logger.Info("Connecting to redis")
|
|
||||||
skinsRepoCfg := &skins.RedisSkinsFactory{
|
logger.Info("Initializing skins repository")
|
||||||
//Addr: "redis:6379",
|
skinsRepo, err := storageFactory.CreateFactory("redis").CreateSkinsRepository()
|
||||||
Addr: "localhost:16379",
|
|
||||||
PollSize: 10,
|
|
||||||
}
|
|
||||||
skinsRepo, err := skinsRepoCfg.Create()
|
|
||||||
if err != nil {
|
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
|
return
|
||||||
}
|
}
|
||||||
logger.Info("Successfully connected to redis")
|
logger.Info("Skins repository successfully initialized")
|
||||||
|
|
||||||
// Capes repository
|
logger.Info("Initializing capes repository")
|
||||||
_, file, _, _ := runtime.Caller(0)
|
capesRepo, err := storageFactory.CreateFactory("filesystem").CreateCapesRepository()
|
||||||
capesRepoCfg := &capes.FilesystemCapesFactory{
|
|
||||||
StoragePath: path.Join(filepath.Dir(file), "data/capes"),
|
|
||||||
}
|
|
||||||
capesRepo, err := capesRepoCfg.Create()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Emergency(fmt.Sprintf("Error on creating capes repo: %v", err))
|
logger.Emergency(fmt.Sprintf("Error on creating capes repo: %v", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
logger.Info("Capes repository successfully initialized")
|
||||||
|
|
||||||
|
|
||||||
cfg := &daemon.Config{
|
cfg := &daemon.Config{
|
||||||
ListenSpec: "localhost:35644",
|
ListenSpec: fmt.Sprintf("%s:%d", viper.GetString("server.host"), viper.GetInt("server.port")),
|
||||||
SkinsRepo: skinsRepo,
|
SkinsRepo: skinsRepo,
|
||||||
CapesRepo: capesRepo,
|
CapesRepo: capesRepo,
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
package daemon
|
package daemon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
|
||||||
|
|
||||||
"elyby/minecraft-skinsystem/ui"
|
|
||||||
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/mono83/slf/wd"
|
"github.com/mono83/slf/wd"
|
||||||
|
|
||||||
"elyby/minecraft-skinsystem/repositories"
|
"elyby/minecraft-skinsystem/repositories"
|
||||||
|
"elyby/minecraft-skinsystem/ui"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
@ -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."
|
|
||||||
}
|
|
@ -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
|
|
||||||
}
|
|
25
db/commons.go
Normal file
25
db/commons.go
Normal file
@ -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."
|
||||||
|
}
|
34
db/factory.go
Normal file
34
db/factory.go
Normal file
@ -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
|
||||||
|
}
|
60
db/filesystem.go
Normal file
60
db/filesystem.go
Normal file
@ -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
|
||||||
|
}
|
@ -1,9 +1,10 @@
|
|||||||
package skins
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"compress/zlib"
|
"compress/zlib"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
@ -16,20 +17,53 @@ import (
|
|||||||
"elyby/minecraft-skinsystem/repositories"
|
"elyby/minecraft-skinsystem/repositories"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RedisSkinsFactory struct {
|
type RedisFactory struct {
|
||||||
Addr string
|
Host string
|
||||||
PollSize int
|
Port int
|
||||||
|
PoolSize int
|
||||||
|
connection util.Cmder
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *RedisSkinsFactory) Create() (repositories.SkinsRepository, error) {
|
func (f RedisFactory) CreateSkinsRepository() (repositories.SkinsRepository, error) {
|
||||||
conn, err := pool.New("tcp", cfg.Addr, cfg.PollSize)
|
connection, err := f.getConnection()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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 {
|
type redisDb struct {
|
||||||
@ -54,13 +88,13 @@ func (db *redisDb) FindByUsername(username string) (model.Skin, error) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
result, err := zlibDecode(encodedResult)
|
result, err := zlibDecode(encodedResult)
|
||||||
if err != nil {
|
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
|
return record, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = json.Unmarshal(result, &record)
|
err = json.Unmarshal(result, &record)
|
||||||
if err != nil {
|
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
|
return record, nil
|
||||||
}
|
}
|
||||||
|
|
@ -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."
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user