Files
2025-04-25 12:12:05 +03:00

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}
}