90 lines
2.0 KiB
Go
90 lines
2.0 KiB
Go
package app
|
|
|
|
import (
|
|
"go.uber.org/fx"
|
|
"go.uber.org/fx/fxevent"
|
|
"go.uber.org/zap"
|
|
"go.uber.org/zap/zapcore"
|
|
"sync/atomic"
|
|
"universe.mrlokop.dev/core/config"
|
|
"universe.mrlokop.dev/core/errors"
|
|
"universe.mrlokop.dev/core/modules"
|
|
)
|
|
|
|
var (
|
|
ErrAlreadyStarted = errors.Type("ErrAlreadyStarted", "already started")
|
|
ErrUnknownModule = errors.Type("ErrUnknownModule", "specified module does not exist")
|
|
)
|
|
|
|
type Application interface {
|
|
Config() *config.UniverseConfig
|
|
Run() error
|
|
}
|
|
|
|
type UniverseApplication struct {
|
|
fx *fx.App
|
|
config *config.UniverseConfig
|
|
options []fx.Option
|
|
started atomic.Bool
|
|
}
|
|
|
|
func (app *UniverseApplication) Config() *config.UniverseConfig {
|
|
return app.config
|
|
}
|
|
|
|
func (app *UniverseApplication) Run() error {
|
|
if !app.started.CompareAndSwap(false, true) {
|
|
return ErrAlreadyStarted.CreateEmpty()
|
|
}
|
|
|
|
options := make([]fx.Option, 0)
|
|
options = append(options, app.options...)
|
|
options = append(options,
|
|
fx.Provide(func() Application {
|
|
return app
|
|
}),
|
|
fx.WithLogger(func(log *zap.Logger) fxevent.Logger {
|
|
logger := &fxevent.ZapLogger{Logger: log.WithOptions(zap.AddCallerSkip(2))}
|
|
logger.UseLogLevel(zapcore.DebugLevel)
|
|
return logger
|
|
}),
|
|
)
|
|
|
|
if app.config.Modules != nil && len(app.config.Modules) > 0 {
|
|
for id, modConf := range app.config.Modules {
|
|
kind := modConf["kind"].(string)
|
|
module := modules.GetModule(kind)
|
|
if module == nil {
|
|
return ErrUnknownModule.Builder().
|
|
Messagef("module '%s' is not registered", kind).
|
|
WithField("module", kind).
|
|
Build()
|
|
}
|
|
|
|
option, err := module.Create(id, modConf)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
options = append(options, option)
|
|
}
|
|
}
|
|
|
|
app.fx = fx.New(options...)
|
|
app.fx.Run()
|
|
return nil
|
|
}
|
|
|
|
func (app *UniverseApplication) WithOption(options ...fx.Option) *UniverseApplication {
|
|
if app.started.Load() {
|
|
panic(ErrAlreadyStarted)
|
|
}
|
|
|
|
app.options = append(app.options, options...)
|
|
return app
|
|
}
|
|
|
|
func NewUniverseApplication(config *config.UniverseConfig) *UniverseApplication {
|
|
return &UniverseApplication{config: config}
|
|
}
|