core/app/app.go

260 lines
7.4 KiB
Go
Raw Normal View History

2025-04-19 23:01:02 +00:00
package app
import (
"context"
"errors"
"fmt"
"github.com/go-redis/redis/v8"
"github.com/gofiber/fiber/v2"
"github.com/skeris/appInit"
"go.uber.org/zap"
"gitea.pena/PenaSide/hlog"
"go.uber.org/zap/zapcore"
"gitea.pena/PenaSide/common/log_mw"
"gitea.pena/PenaSide/common/privilege"
"gitea.pena/SQuiz/common/dal"
"gitea.pena/SQuiz/common/healthchecks"
"gitea.pena/SQuiz/common/middleware"
"gitea.pena/SQuiz/common/model"
"gitea.pena/SQuiz/core/brokers"
"gitea.pena/SQuiz/core/clients/auth"
//"gitea.pena/SQuiz/core/clients/telegram"
"gitea.pena/SQuiz/core/initialize"
"gitea.pena/SQuiz/core/models"
"gitea.pena/SQuiz/core/server"
"gitea.pena/SQuiz/core/service"
"gitea.pena/SQuiz/core/tools"
//"gitea.pena/SQuiz/core/workers"
"gitea.pena/PenaSide/trashlog/wrappers/zaptrashlog"
"time"
)
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:"1488"`
CrtFile string `env:"CRT" default:"server.crt"`
KeyFile string `env:"KEY" default:"server.key"`
PostgresCredentials string `env:"PG_CRED" default:"host=localhost port=35432 user=squiz password=Redalert2 dbname=squiz sslmode=disable"`
HubAdminUrl string `env:"HUB_ADMIN_URL" default:"http://localhost:8001/"`
ServiceName string `env:"SERVICE_NAME" default:"squiz"`
AuthServiceURL string `env:"AUTH_URL" default:"http://localhost:8000/"`
GrpcHost string `env:"GRPC_HOST" default:"localhost"`
GrpcPort string `env:"GRPC_PORT" default:"9000"`
KafkaBrokers string `env:"KAFKA_BROKERS" default:"localhost:9092"`
KafkaTopic string `env:"KAFKA_TOPIC" default:"test-topic"`
KafkaGroup string `env:"KAFKA_GROUP" default:"mailnotifier"`
TrashLogHost string `env:"TRASH_LOG_HOST" default:"localhost:7113"`
ModuleLogger string `env:"MODULE_LOGGER" default:"core-local"`
ClickHouseCred string `env:"CLICK_HOUSE_CRED" default:"tcp://10.8.0.15:9000/default?sslmode=disable"`
RedisHost string `env:"REDIS_HOST" default:"localhost:6379"`
RedisPassword string `env:"REDIS_PASSWORD" default:"admin"`
RedisDB uint64 `env:"REDIS_DB" default:"2"`
S3Prefix string `env:"S3_PREFIX"`
}
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
}
}
zapLogger = zapLogger.With(
zap.String("SvcCommit", ver.Commit),
zap.String("SvcVersion", ver.Release),
zap.String("SvcBuildTime", ver.BuildTime),
)
clickHouseLogger, err := zaptrashlog.NewCore(ctx, zap.InfoLevel, options.TrashLogHost, ver.Release, ver.Commit, time.Now().Unix())
if err != nil {
panic(err)
}
loggerForHlog := zapLogger.WithOptions(zap.WrapCore(func(core zapcore.Core) zapcore.Core {
return zapcore.NewTee(core, clickHouseLogger)
}))
loggerHlog := hlog.New(loggerForHlog).Module(options.ModuleLogger)
loggerHlog.With(models.AllFields{})
loggerHlog.Emit(InfoSvcStarted{})
authClient := auth.NewAuthClient(options.AuthServiceURL)
pgdal, err := dal.New(ctx, options.PostgresCredentials, nil)
if err != nil {
fmt.Println("NEW", err)
return nil, err
}
chDal, err := dal.NewClickHouseDAL(ctx, options.ClickHouseCred)
if err != nil {
fmt.Println("failed init clickhouse", err)
return nil, err
}
kafkaClient, err := initialize.KafkaInit(ctx, initialize.KafkaDeps{
KafkaGroup: options.KafkaGroup,
KafkaBrokers: options.KafkaBrokers,
KafkaTopic: options.KafkaTopic,
})
if err != nil {
return nil, err
}
producer := brokers.NewProducer(brokers.ProducerDeps{
KafkaClient: kafkaClient,
Logger: zapLogger,
})
redisClient := redis.NewClient(&redis.Options{
Addr: options.RedisHost,
Password: options.RedisPassword,
DB: int(options.RedisDB),
})
err = redisClient.Ping(ctx).Err()
if err != nil {
panic(fmt.Sprintf("error ping to redis db %v", err))
}
clientData := privilege.Client{
URL: options.HubAdminUrl,
ServiceName: options.ServiceName,
Privileges: model.Privileges,
}
fiberClient := &fiber.Client{}
privilegeController := privilege.NewPrivilege(clientData, fiberClient)
go tools.PublishPrivilege(privilegeController, 10, 5*time.Minute)
// tgClient, err := telegram.NewTelegramClient(ctx, pgdal)
// if err != nil {
// panic(fmt.Sprintf("failed init tg clietns: %v", err))
// }
//
// tgWC := workers.NewTgListenerWC(workers.Deps{
// BotID: int64(6712573453), // todo убрать
// Redis: redisClient,
// Dal: pgdal,
// TgClient: tgClient,
// })
//
// go tgWC.Start(ctx)
// todo подумать над реализацией всего а то пока мне кажется что немного каша получается такой предикт что через некоторое время
// сложно будет разобраться что есть где
grpcControllers := initialize.InitRpcControllers(pgdal)
grpc, err := server.NewGRPC(zapLogger)
if err != nil {
fmt.Println("error:", err)
panic("err init grpc server")
}
grpc.Register(grpcControllers)
go grpc.Run(server.DepsGrpcRun{
Host: options.GrpcHost,
Port: options.GrpcPort,
})
app := fiber.New()
app.Use(middleware.JWTAuth())
app.Use(log_mw.ContextLogger(loggerHlog))
app.Get("/liveness", healthchecks.Liveness)
app.Get("/readiness", healthchecks.Readiness(&workerErr)) //todo parametrized readiness. should discuss ready reason
svc := service.New(service.Deps{
Dal: pgdal,
AuthClient: authClient,
Producer: producer,
ServiceName: options.ServiceName,
ChDAL: chDal,
// TelegramClient: tgClient,
RedisClient: redisClient,
S3Prefix: options.S3Prefix,
})
svc.Register(app)
loggerHlog.Emit(InfoSvcReady{})
go func() {
defer func() {
if pgdal != nil {
pgdal.Close()
}
if chDal != nil {
if derr := chDal.Close(ctx); derr != nil {
fmt.Printf("error closing clickhouse: %v", derr)
}
}
err := grpc.Stop(ctx)
err = app.Shutdown()
loggerHlog.Emit(InfoSvcShutdown{Signal: err.Error()})
}()
if options.IsProd {
if err := app.ListenTLS(fmt.Sprintf(":%s", options.NumberPort), options.CrtFile, options.KeyFile); err != nil {
loggerHlog.Emit(ErrorCanNotServe{
Err: err,
})
errChan <- err
}
} else {
if err := app.Listen(fmt.Sprintf(":%s", options.NumberPort)); err != nil {
loggerHlog.Emit(ErrorCanNotServe{
Err: err,
})
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
}