answerer/app/app.go

152 lines
3.8 KiB
Go
Raw Normal View History

2024-02-19 18:27:12 +00:00
package app
import (
"context"
"errors"
"fmt"
2025-04-23 15:39:15 +00:00
"gitea.pena/SQuiz/answerer/clients"
2025-02-27 13:19:02 +00:00
"gitea.pena/SQuiz/answerer/service"
"gitea.pena/SQuiz/common/dal"
"gitea.pena/SQuiz/common/healthchecks"
"gitea.pena/SQuiz/common/middleware"
"gitea.pena/SQuiz/common/utils"
2024-02-19 18:27:12 +00:00
"github.com/gofiber/fiber/v2"
"github.com/skeris/appInit"
"go.uber.org/zap"
)
type App struct {
logger *zap.Logger
err chan error
}
func (a App) GetLogger() *zap.Logger {
return a.logger
}
func (a App) GetErr() chan error {
return a.err
}
var (
errInvalidOptions = errors.New("invalid options")
)
var zapOptions = []zap.Option{
zap.AddCaller(),
zap.AddCallerSkip(2),
zap.AddStacktrace(zap.ErrorLevel),
}
var _ appInit.CommonApp = (*App)(nil)
type Options struct {
LoggerProdMode bool `env:"IS_PROD_LOG" default:"false"`
IsProd bool `env:"IS_PROD" default:"false"`
NumberPort string `env:"PORT" default:"1490"`
CrtFile string `env:"CRT" default:"server.crt"`
KeyFile string `env:"KEY" default:"server.key"`
PostgresCredentials string `env:"PG_CRED" default:"host=localhost port=5432 user=squiz password=Redalert2 dbname=squiz sslmode=disable"`
2024-06-01 13:20:13 +00:00
RedirectURL string `env:"REDIRECT_URL" default:"https://squiz.pena.digital"`
PubKey string `env:"PUBLIC_KEY"`
PrivKey string `env:"PRIVATE_KEY"`
2024-02-19 18:27:12 +00:00
}
func New(ctx context.Context, opts interface{}, ver appInit.Version) (appInit.CommonApp, error) {
var (
err, workerErr error
zapLogger *zap.Logger
errChan = make(chan error)
options Options
ok bool
)
if options, ok = opts.(Options); !ok {
return App{}, errInvalidOptions
}
if options.LoggerProdMode {
zapLogger, err = zap.NewProduction(zapOptions...)
if err != nil {
return nil, err
}
} else {
zapLogger, err = zap.NewDevelopment(zapOptions...)
if err != nil {
return nil, err
}
}
2024-06-15 17:56:55 +00:00
zapLogger = zapLogger.With(
zap.String("SvcCommit", ver.Commit),
zap.String("SvcVersion", ver.Release),
zap.String("SvcBuildTime", ver.BuildTime),
)
2024-02-19 18:27:12 +00:00
2025-07-09 11:40:02 +00:00
pgdal, err := dal.New(ctx, options.PostgresCredentials, nil)
2024-04-01 22:32:17 +00:00
if err != nil {
return nil, err
}
2024-02-19 18:27:12 +00:00
zapLogger.Info("config", zap.Any("options", options))
2024-06-01 13:20:13 +00:00
encrypt := utils.NewEncrypt(options.PubKey, options.PrivKey)
2025-07-09 11:40:02 +00:00
svc, err := service.New(service.ServiceDeps{
Dal: pgdal,
Encrypt: encrypt,
RedirectURl: options.RedirectURL,
AiClient: clients.NewAiClient("https://alvatar.com/api/engine/send_answer"),
})
2024-02-19 18:27:12 +00:00
if err != nil {
2025-07-09 11:40:02 +00:00
zapLogger.Error("failed to create service", zap.Error(err))
2024-02-19 18:27:12 +00:00
return nil, err
}
app := fiber.New(fiber.Config{BodyLimit: 70 * 1024 * 1024})
2025-04-23 15:39:15 +00:00
app.Use(func(c *fiber.Ctx) error {
defer func() {
if err := recover(); err != nil {
c.Status(fiber.StatusInternalServerError).SendString("internal server error")
}
}()
return c.Next()
})
2024-02-19 18:27:12 +00:00
app.Use(middleware.AnswererChain())
app.Get("/liveness", healthchecks.Liveness)
app.Get("/readiness", healthchecks.Readiness(&workerErr)) //todo parametrized readiness. should discuss ready reason
app = svc.Register(app)
fmt.Println("SERVERSTART", fmt.Sprintf(":%s", options.NumberPort))
go func() {
defer func() {
err := app.Shutdown()
if err != nil {
2025-07-09 11:40:02 +00:00
zapLogger.Error("failed graceful shutdown", zap.Error(err))
2024-02-19 18:27:12 +00:00
}
}()
if options.IsProd {
if err := app.ListenTLS(fmt.Sprintf(":%s", options.NumberPort), options.CrtFile, options.KeyFile); err != nil {
2025-07-09 11:40:02 +00:00
zapLogger.Error("failed start server", zap.Error(err))
2024-02-19 18:27:12 +00:00
errChan <- err
}
} else {
if err := app.Listen(fmt.Sprintf(":%s", options.NumberPort)); err != nil {
2025-07-09 11:40:02 +00:00
zapLogger.Error("failed start server", zap.Error(err))
2024-02-19 18:27:12 +00:00
errChan <- err
}
}
errChan <- nil
}()
// todo implement helper func for service app type. such as server preparing, logger preparing, healthchecks and etc.
return &App{
logger: zapLogger,
err: errChan,
}, err
}