api/internal/app/app.go

168 lines
3.6 KiB
Go
Raw Normal View History

//go:generate mockgen -source=$GOFILE -destination=./mock/app.mock.go -package=mock
package app
import (
"context"
"os"
"os/signal"
"syscall"
"github.com/spf13/cobra"
"gitlab.com/inetmock/inetmock/internal/endpoints"
"gitlab.com/inetmock/inetmock/pkg/api"
"gitlab.com/inetmock/inetmock/pkg/cert"
"gitlab.com/inetmock/inetmock/pkg/config"
"gitlab.com/inetmock/inetmock/pkg/health"
"gitlab.com/inetmock/inetmock/pkg/logging"
"gitlab.com/inetmock/inetmock/pkg/path"
"go.uber.org/zap"
)
var (
configFilePath string
logLevel string
developmentLogs bool
)
type App interface {
api.PluginContext
Config() config.Config
Checker() health.Checker
EndpointManager() endpoints.EndpointManager
HandlerRegistry() api.HandlerRegistry
Context() context.Context
MustRun()
Shutdown()
WithCommands(cmds ...*cobra.Command) App
}
type app struct {
cfg config.Config
rootCmd *cobra.Command
rootLogger logging.Logger
certStore cert.Store
checker health.Checker
endpointManager endpoints.EndpointManager
registry api.HandlerRegistry
ctx context.Context
cancel context.CancelFunc
}
func (a *app) MustRun() {
if err := a.rootCmd.Execute(); err != nil {
if a.rootLogger != nil {
a.rootLogger.Error(
"Failed to run inetmock",
zap.Error(err),
)
} else {
panic(err)
}
}
}
func (a app) Logger() logging.Logger {
return a.rootLogger
}
func (a app) Config() config.Config {
return a.cfg
}
func (a app) CertStore() cert.Store {
return a.certStore
}
func (a app) Checker() health.Checker {
return a.checker
}
func (a app) EndpointManager() endpoints.EndpointManager {
return a.endpointManager
}
func (a app) HandlerRegistry() api.HandlerRegistry {
return a.registry
}
func (a app) Context() context.Context {
return a.ctx
}
func (a app) Shutdown() {
a.cancel()
}
func (a *app) WithCommands(cmds ...*cobra.Command) App {
a.rootCmd.AddCommand(cmds...)
return a
}
func NewApp(registrations ...api.Registration) (inetmockApp App, err error) {
registry := api.NewHandlerRegistry()
for _, registration := range registrations {
if err = registration(registry); err != nil {
return
}
}
ctx, cancel := initAppContext()
a := &app{
rootCmd: &cobra.Command{
Short: "INetMock is lightweight internet mock",
},
checker: health.New(),
registry: registry,
ctx: ctx,
cancel: cancel,
}
a.rootCmd.PersistentFlags().StringVar(&configFilePath, "config", "", "Path to config file that should be used")
a.rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "logging level to use")
a.rootCmd.PersistentFlags().BoolVar(&developmentLogs, "development-logs", false, "Enable development mode logs")
a.rootCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) (err error) {
logging.ConfigureLogging(
logging.ParseLevel(logLevel),
developmentLogs,
map[string]interface{}{
"cwd": path.WorkingDirectory(),
},
)
if a.rootLogger, err = logging.CreateLogger(); err != nil {
return
}
a.cfg = config.CreateConfig(cmd.Flags())
if err = a.cfg.ReadConfig(configFilePath); err != nil {
return
}
a.certStore, err = cert.NewDefaultStore(a.cfg, a.rootLogger)
a.endpointManager = endpoints.NewEndpointManager(a.registry, a.Logger().Named("EndpointManager"), a.checker, a)
return
}
return a, nil
}
func initAppContext() (context.Context, context.CancelFunc) {
ctx, cancel := context.WithCancel(context.Background())
signals := make(chan os.Signal, 1)
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
go func() {
<-signals
cancel()
}()
return ctx, cancel
}