222 lines
4.8 KiB
Go
222 lines
4.8 KiB
Go
package components
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"time"
|
|
|
|
"git.loyso.art/frx/eway/internal/config"
|
|
"git.loyso.art/frx/eway/internal/dimension"
|
|
"git.loyso.art/frx/eway/internal/interconnect/eway"
|
|
"git.loyso.art/frx/eway/internal/storage"
|
|
xbadger "git.loyso.art/frx/eway/internal/storage/badger"
|
|
|
|
"github.com/BurntSushi/toml"
|
|
"github.com/dgraph-io/badger/v4"
|
|
"github.com/rs/zerolog"
|
|
"github.com/samber/do"
|
|
)
|
|
|
|
// Yeah, singleton is not good UNLESS you're really lazy
|
|
var diInjector *do.Injector
|
|
|
|
func GetEwayClient() (eway.Client, error) {
|
|
return do.Invoke[eway.Client](diInjector)
|
|
}
|
|
|
|
func GetRepository() (storage.Repository, error) {
|
|
adapter, err := do.Invoke[*storageRepositoryAdapter](diInjector)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return adapter.entity, nil
|
|
}
|
|
|
|
func GetLogger() (zerolog.Logger, error) {
|
|
log, err := do.Invoke[*loggerAdapter](diInjector)
|
|
if err != nil {
|
|
return zerolog.Nop(), err
|
|
}
|
|
|
|
return log.entity.log, nil
|
|
}
|
|
|
|
func GetDimensionMatcher() (*dimension.Matcher, error) {
|
|
return do.Invoke[*dimension.Matcher](diInjector)
|
|
}
|
|
|
|
func SetupDI(ctx context.Context, cfgpath string, verbose bool, logAsJSON bool) error {
|
|
cfg, err := parseSettings(cfgpath)
|
|
if err != nil {
|
|
// if no settings provided allow cli to run without them.
|
|
if errors.Is(err, os.ErrNotExist) {
|
|
return nil
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
diInjector = do.New()
|
|
|
|
do.Provide(diInjector, func(i *do.Injector) (*loggerAdapter, error) {
|
|
tsSet := func(wr *zerolog.ConsoleWriter) {
|
|
wr.TimeFormat = time.RFC3339
|
|
}
|
|
|
|
var outfile *os.File
|
|
var output io.Writer
|
|
switch cfg.Log.Output {
|
|
case "", "stdout":
|
|
output = os.Stdout
|
|
case "stderr":
|
|
output = os.Stderr
|
|
default:
|
|
outfile, err = os.OpenFile(cfg.Log.Output, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("creating file for logging: %w", err)
|
|
}
|
|
|
|
output = zerolog.SyncWriter(outfile)
|
|
}
|
|
|
|
var writer io.Writer
|
|
if logAsJSON {
|
|
writer = output
|
|
} else {
|
|
writer = zerolog.NewConsoleWriter(tsSet, func(w *zerolog.ConsoleWriter) {
|
|
w.Out = output
|
|
})
|
|
}
|
|
|
|
log := zerolog.
|
|
New(writer).
|
|
With().
|
|
Timestamp().
|
|
Str("app", "converter").
|
|
Logger()
|
|
|
|
if verbose {
|
|
log = log.Level(zerolog.DebugLevel)
|
|
} else {
|
|
log = log.Level(zerolog.InfoLevel)
|
|
}
|
|
|
|
out := &logger{
|
|
log: log,
|
|
underlyingFile: outfile,
|
|
}
|
|
return &loggerAdapter{
|
|
entity: out,
|
|
}, nil
|
|
})
|
|
|
|
do.Provide[eway.Client](diInjector, func(i *do.Injector) (eway.Client, error) {
|
|
log, err := GetLogger()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("getting logger: %w", err)
|
|
}
|
|
|
|
client, err := eway.New(ctx, eway.Config(cfg.Eway), log)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("making new eway client: %w", err)
|
|
}
|
|
|
|
return client, nil
|
|
})
|
|
|
|
do.Provide[*badgerDBAdapter](diInjector, func(i *do.Injector) (*badgerDBAdapter, error) {
|
|
db, err := xbadger.Open(ctx, cfg.Badger.Dir, cfg.Badger.Debug, zerolog.Nop())
|
|
if err != nil {
|
|
return nil, fmt.Errorf("getting db: %w", err)
|
|
}
|
|
|
|
out := &badgerDBAdapter{entity: db}
|
|
return out, nil
|
|
})
|
|
|
|
do.Provide[*storageRepositoryAdapter](diInjector, func(i *do.Injector) (*storageRepositoryAdapter, error) {
|
|
db, err := getDB()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
client, err := xbadger.NewClient(db)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("getting badger client: %w", err)
|
|
}
|
|
|
|
out := &storageRepositoryAdapter{entity: client}
|
|
return out, nil
|
|
})
|
|
|
|
do.Provide[*dimension.Matcher](diInjector, func(i *do.Injector) (*dimension.Matcher, error) {
|
|
matcher := dimension.New(cfg.DimensionMatcher)
|
|
|
|
return matcher, nil
|
|
})
|
|
|
|
return nil
|
|
}
|
|
|
|
func Shutdown() error {
|
|
if diInjector == nil {
|
|
return nil
|
|
}
|
|
|
|
return diInjector.Shutdown()
|
|
}
|
|
|
|
func getDB() (*badger.DB, error) {
|
|
adapter, err := do.Invoke[*badgerDBAdapter](diInjector)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return adapter.entity, nil
|
|
}
|
|
|
|
type settings struct {
|
|
Badger config.Badger `toml:"badger"`
|
|
Log config.Log `toml:"log"`
|
|
Eway config.Eway `toml:"eway"`
|
|
DimensionMatcher config.DimensionMatcher `toml:"dimension_matcher"`
|
|
}
|
|
|
|
func parseSettings(cfgpath string) (cfg settings, err error) {
|
|
_, err = toml.DecodeFile(cfgpath, &cfg)
|
|
if err != nil {
|
|
return cfg, fmt.Errorf("parsing file: %w", err)
|
|
}
|
|
|
|
return cfg, nil
|
|
}
|
|
|
|
type logger struct {
|
|
log zerolog.Logger
|
|
underlyingFile *os.File
|
|
}
|
|
|
|
func (l *logger) Close() error {
|
|
if l.underlyingFile == nil {
|
|
return nil
|
|
}
|
|
|
|
return l.underlyingFile.Close()
|
|
}
|
|
|
|
type entityCloserAdapter[T io.Closer] struct {
|
|
entity T
|
|
}
|
|
|
|
func (a entityCloserAdapter[T]) Shutdown() error {
|
|
return a.entity.Close()
|
|
}
|
|
|
|
type storageRepositoryAdapter entityCloserAdapter[storage.Repository]
|
|
type badgerDBAdapter entityCloserAdapter[*badger.DB]
|
|
type loggerAdapter entityCloserAdapter[*logger]
|