Introduce di into the project

This commit is contained in:
ErickSkrauch 2020-04-16 19:42:38 +03:00
parent 0c81494559
commit 9046338396
No known key found for this signature in database
GPG Key ID: 669339FCBB30EE0E
12 changed files with 398 additions and 8 deletions

14
Gopkg.lock generated
View File

@ -63,6 +63,19 @@
pruneopts = ""
revision = "919484f041ea21e7e27be291cee1d6af7bc98864"
[[projects]]
digest = "1:c17a0163edf9a1b0f5d9e856673413b924939cf433ebf041ec309e8273fd9d2b"
name = "github.com/goava/di"
packages = [
".",
"internal/graph",
"internal/reflection",
"internal/stacktrace",
]
pruneopts = ""
revision = "6dcd92e58bd0fb2ff77cec60557abea1dae46571"
version = "v1.1.0"
[[projects]]
digest = "1:65c7ed49d9f36dd4752e43013323fa9229db60b29aa4f5a75aaecda3130c74e2"
name = "github.com/gorilla/mux"
@ -321,6 +334,7 @@
"github.com/asaskevich/EventBus",
"github.com/etherlabsio/healthcheck",
"github.com/getsentry/raven-go",
"github.com/goava/di",
"github.com/gorilla/mux",
"github.com/h2non/gock",
"github.com/mediocregopher/radix.v2/pool",

View File

@ -45,6 +45,10 @@ ignored = ["github.com/elyby/chrly"]
name = "github.com/etherlabsio/healthcheck"
version = "2.0.3"
[[constraint]]
name = "github.com/goava/di"
version = "^1.0.2"
# Testing dependencies
[[constraint]]

View File

@ -1,9 +1,9 @@
package db
import (
"github.com/elyby/chrly/http"
"github.com/spf13/viper"
"github.com/elyby/chrly/http"
"github.com/elyby/chrly/mojangtextures"
)
@ -17,6 +17,7 @@ type RepositoriesCreator interface {
CreateMojangUuidsRepository() (mojangtextures.UuidsStorage, error)
}
// TODO: redundant
func (factory *StorageFactory) CreateFactory(backend string) RepositoriesCreator {
switch backend {
case "redis":

14
di/config.go Normal file
View File

@ -0,0 +1,14 @@
package di
import (
"github.com/goava/di"
"github.com/spf13/viper"
)
var config = di.Options(
di.Provide(newConfig),
)
func newConfig() *viper.Viper {
return viper.GetViper()
}

77
di/db.go Normal file
View File

@ -0,0 +1,77 @@
package di
import (
"github.com/goava/di"
"github.com/spf13/viper"
dbModule "github.com/elyby/chrly/db"
"github.com/elyby/chrly/http"
"github.com/elyby/chrly/mojangtextures"
)
var db = di.Options(
di.Provide(newRedisFactory, di.WithName("redis")),
di.Provide(newFSFactory, di.WithName("fs")),
di.Provide(newSkinsRepository),
di.Provide(newCapesRepository),
di.Provide(newMojangUUIDsRepository),
di.Provide(newMojangSignedTexturesStorage),
)
func newRedisFactory(config *viper.Viper) dbModule.RepositoriesCreator {
return &dbModule.RedisFactory{
Host: config.GetString("storage.redis.host"),
Port: config.GetInt("storage.redis.port"),
PoolSize: config.GetInt("storage.redis.poolSize"),
}
}
func newFSFactory(config *viper.Viper) dbModule.RepositoriesCreator {
return &dbModule.FilesystemFactory{
BasePath: config.GetString("storage.filesystem.basePath"),
CapesDirName: config.GetString("storage.filesystem.capesDirName"),
}
}
// v4 had the idea that it would be possible to separate backends for storing skins and capes.
// But in v5 the storage will be unified, so this is just temporary constructors before large reworking.
//
// Since there are no options for selecting target backends,
// all constants in this case point to static specific implementations.
func newSkinsRepository(container *di.Container) (http.SkinsRepository, error) {
var factory dbModule.RepositoriesCreator
err := container.Resolve(&factory, di.Name("redis"))
if err != nil {
return nil, err
}
return factory.CreateSkinsRepository()
}
func newCapesRepository(container *di.Container) (http.CapesRepository, error) {
var factory dbModule.RepositoriesCreator
err := container.Resolve(&factory, di.Name("fs"))
if err != nil {
return nil, err
}
return factory.CreateCapesRepository()
}
func newMojangUUIDsRepository(container *di.Container) (mojangtextures.UuidsStorage, error) {
var factory dbModule.RepositoriesCreator
err := container.Resolve(&factory, di.Name("redis"))
if err != nil {
return nil, err
}
return factory.CreateMojangUuidsRepository()
}
func newMojangSignedTexturesStorage() mojangtextures.TexturesStorage {
texturesStorage := mojangtextures.NewInMemoryTexturesStorage()
texturesStorage.Start()
return texturesStorage
}

33
di/di.go Normal file
View File

@ -0,0 +1,33 @@
package di
import "github.com/goava/di"
func New() (*di.Container, error) {
container, err := di.New(
di.WithCompile(),
config,
dispatcher,
logger,
db,
mojangTextures,
)
if err != nil {
return nil, err
}
// Inject container itself into dependencies graph
// See https://github.com/goava/di/issues/8#issuecomment-614227320
err = container.Provide(func() *di.Container {
return container
})
if err != nil {
return nil, err
}
err = container.Compile()
if err != nil {
return nil, err
}
return container, nil
}

20
di/dispatcher.go Normal file
View File

@ -0,0 +1,20 @@
package di
import (
"github.com/goava/di"
dispatcherModule "github.com/elyby/chrly/dispatcher"
"github.com/elyby/chrly/http"
"github.com/elyby/chrly/mojangtextures"
)
var dispatcher = di.Options(
di.Provide(newDispatcher,
di.As(new(http.Emitter)),
di.As(new(mojangtextures.Emitter)),
),
)
func newDispatcher() dispatcherModule.EventDispatcher {
return dispatcherModule.New()
}

41
di/handlers.go Normal file
View File

@ -0,0 +1,41 @@
package di
import (
"github.com/goava/di"
"github.com/gorilla/mux"
"github.com/spf13/viper"
"github.com/elyby/chrly/http"
)
var handlers = di.Options(
di.Provide(newSkinsystemHandler, di.WithName("skinsystem")),
)
func newSkinsystemHandler(
config *viper.Viper,
emitter http.Emitter,
skinsRepository http.SkinsRepository,
capesRepository http.CapesRepository,
mojangTexturesProvider http.MojangTexturesProvider,
) *mux.Router {
handlerFactory := &http.Skinsystem{
Emitter: emitter,
SkinsRepo: skinsRepository,
CapesRepo: capesRepository,
MojangTexturesProvider: mojangTexturesProvider,
TexturesExtraParamName: config.GetString("textures.extra_param_name"),
TexturesExtraParamValue: config.GetString("textures.extra_param_value"),
}
return handlerFactory.CreateHandler()
}
// TODO: pin implementation to make it non-configurable
func newUUIDsWorkerHandler(mojangUUIDsProvider http.MojangUuidsProvider) *mux.Router {
handlerFactory := &http.UUIDsWorker{
UUIDsProvider: mojangUUIDsProvider,
}
return handlerFactory.CreateHandler()
}

96
di/logger.go Normal file
View File

@ -0,0 +1,96 @@
package di
import (
"os"
"github.com/getsentry/raven-go"
"github.com/goava/di"
"github.com/mono83/slf"
"github.com/mono83/slf/rays"
"github.com/mono83/slf/recievers/sentry"
"github.com/mono83/slf/recievers/statsd"
"github.com/mono83/slf/recievers/writer"
"github.com/mono83/slf/wd"
"github.com/spf13/viper"
"github.com/elyby/chrly/version"
)
var logger = di.Options(
di.Provide(newLogger),
di.Provide(newSentry),
di.Provide(newStatsReporter),
)
type loggerParams struct {
di.Inject
SentryRaven *raven.Client `di:"" optional:"true"`
}
func newLogger(params loggerParams) slf.Logger {
dispatcher := &slf.Dispatcher{}
dispatcher.AddReceiver(writer.New(writer.Options{
Marker: false,
TimeFormat: "15:04:05.000",
}))
if params.SentryRaven != nil {
sentryReceiver, _ := sentry.NewReceiverWithCustomRaven(
params.SentryRaven,
&sentry.Config{
MinLevel: "warn",
},
)
dispatcher.AddReceiver(sentryReceiver)
}
logger := wd.Custom("", "", dispatcher)
logger.WithParams(rays.Host)
return logger
}
func newSentry(config *viper.Viper) (*raven.Client, error) {
sentryAddr := config.GetString("sentry.dsn")
if sentryAddr == "" {
return nil, nil
}
ravenClient, err := raven.New(sentryAddr)
if err != nil {
return nil, err
}
ravenClient.SetEnvironment("production")
ravenClient.SetDefaultLoggerName("sentry-watchdog-receiver")
ravenClient.SetRelease(version.Version())
return ravenClient, nil
}
func newStatsReporter(config *viper.Viper) (slf.StatsReporter, error) {
statsdAddr := config.GetString("statsd.addr")
if statsdAddr == "" {
return nil, nil
}
hostname, err := os.Hostname()
if err != nil {
return nil, err
}
statsdReceiver, err := statsd.NewReceiver(statsd.Config{
Address: statsdAddr,
Prefix: "ely.skinsystem." + hostname + ".app.",
FlushEvery: 1,
})
if err != nil {
return nil, err
}
dispatcher := &slf.Dispatcher{}
dispatcher.AddReceiver(statsdReceiver)
return wd.Custom("", "", dispatcher), nil
}

91
di/mojang_textures.go Normal file
View File

@ -0,0 +1,91 @@
package di
import (
"fmt"
"net/url"
"github.com/goava/di"
"github.com/spf13/viper"
"github.com/elyby/chrly/http"
"github.com/elyby/chrly/mojangtextures"
)
var mojangTextures = di.Options(
di.Provide(newMojangTexturesProviderFactory),
di.Provide(newMojangTexturesProvider),
di.Provide(newMojangTexturesUuidsProvider),
di.Provide(newMojangSignedTexturesProvider),
di.Provide(newMojangTexturesStorageFactory),
)
func newMojangTexturesProviderFactory(
container *di.Container,
config *viper.Viper,
) (http.MojangTexturesProvider, error) {
if !config.GetBool("mojang_textures.enabled") {
return &mojangtextures.NilProvider{}, nil
}
var provider *mojangtextures.Provider
err := container.Resolve(&provider)
if err != nil {
return nil, err
}
return provider, nil
}
func newMojangTexturesProvider(
emitter mojangtextures.Emitter,
uuidsProvider mojangtextures.UUIDsProvider,
texturesProvider mojangtextures.TexturesProvider,
storage mojangtextures.Storage,
) *mojangtextures.Provider {
return &mojangtextures.Provider{
Emitter: emitter,
UUIDsProvider: uuidsProvider,
TexturesProvider: texturesProvider,
Storage: storage,
}
}
func newMojangTexturesUuidsProvider(
config *viper.Viper,
emitter mojangtextures.Emitter,
) (mojangtextures.UUIDsProvider, error) {
preferredUuidsProvider := config.GetString("mojang_textures.uuids_provider.driver")
if preferredUuidsProvider == "remote" {
remoteUrl, err := url.Parse(config.GetString("mojang_textures.uuids_provider.url"))
if err != nil {
return nil, fmt.Errorf("Unable to parse remote url: %w", err)
}
return &mojangtextures.RemoteApiUuidsProvider{
Emitter: emitter,
Url: *remoteUrl,
}, nil
}
return &mojangtextures.BatchUuidsProvider{
Emitter: emitter,
IterationDelay: config.GetDuration("queue.loop_delay"),
IterationSize: config.GetInt("queue.batch_size"),
}, nil
}
func newMojangSignedTexturesProvider(emitter mojangtextures.Emitter) mojangtextures.TexturesProvider {
return &mojangtextures.MojangApiTexturesProvider{
Emitter: emitter,
}
}
func newMojangTexturesStorageFactory(
uuidsStorage mojangtextures.UuidsStorage,
texturesStorage mojangtextures.TexturesStorage,
) mojangtextures.Storage {
return &mojangtextures.SeparatedStorage{
UuidsStorage: uuidsStorage,
TexturesStorage: texturesStorage,
}
}

View File

@ -7,20 +7,20 @@ type EventDispatcher interface {
Emit(topic string, args ...interface{})
}
type LocalEventDispatcher struct {
type localEventDispatcher struct {
bus EventBus.Bus
}
func (d *LocalEventDispatcher) Subscribe(topic string, fn interface{}) {
func (d *localEventDispatcher) Subscribe(topic string, fn interface{}) {
_ = d.bus.Subscribe(topic, fn)
}
func (d *LocalEventDispatcher) Emit(topic string, args ...interface{}) {
func (d *localEventDispatcher) Emit(topic string, args ...interface{}) {
d.bus.Publish(topic, args...)
}
func New() EventDispatcher {
return &LocalEventDispatcher{
return &localEventDispatcher{
bus: EventBus.New(),
}
}

View File

@ -7,16 +7,15 @@ import (
"github.com/gorilla/mux"
"github.com/elyby/chrly/api/mojang"
"github.com/elyby/chrly/mojangtextures"
)
type UuidsProvider interface {
type MojangUuidsProvider interface {
GetUuid(username string) (*mojang.ProfileInfo, error)
}
type UUIDsWorker struct {
Emitter
UUIDsProvider mojangtextures.UUIDsProvider
UUIDsProvider MojangUuidsProvider
}
func (ctx *UUIDsWorker) CreateHandler() *mux.Router {