2024-02-19 17:48:04 +00:00
|
|
|
|
package app
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
2024-07-11 09:06:24 +00:00
|
|
|
|
"github.com/go-redis/redis/v8"
|
2024-02-19 17:48:04 +00:00
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
|
|
|
"github.com/skeris/appInit"
|
|
|
|
|
"github.com/themakers/hlog"
|
|
|
|
|
"go.uber.org/zap"
|
2024-06-25 14:41:26 +00:00
|
|
|
|
"go.uber.org/zap/zapcore"
|
2024-07-08 10:47:16 +00:00
|
|
|
|
"penahub.gitlab.yandexcloud.net/backend/penahub_common/log_mw"
|
2024-03-25 09:47:18 +00:00
|
|
|
|
"penahub.gitlab.yandexcloud.net/backend/penahub_common/privilege"
|
2024-02-19 17:48:04 +00:00
|
|
|
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
|
|
|
|
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/healthchecks"
|
2024-07-08 10:47:16 +00:00
|
|
|
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/middleware"
|
2024-03-25 09:47:18 +00:00
|
|
|
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
|
2024-06-12 13:27:42 +00:00
|
|
|
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/brokers"
|
|
|
|
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/clients/auth"
|
2024-06-25 14:37:26 +00:00
|
|
|
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/clients/telegram"
|
2024-06-12 13:27:42 +00:00
|
|
|
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/initialize"
|
|
|
|
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/models"
|
|
|
|
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/server"
|
|
|
|
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/service"
|
|
|
|
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/tools"
|
2024-07-11 09:06:24 +00:00
|
|
|
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/workers"
|
2024-07-08 10:46:12 +00:00
|
|
|
|
"penahub.gitlab.yandexcloud.net/external/trashlog/wrappers/zaptrashlog"
|
2024-03-25 13:24:14 +00:00
|
|
|
|
"time"
|
2024-02-19 17:48:04 +00:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
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"`
|
2024-03-26 17:48:49 +00:00
|
|
|
|
PostgresCredentials string `env:"PG_CRED" default:"host=localhost port=35432 user=squiz password=Redalert2 dbname=squiz sslmode=disable"`
|
2024-03-25 13:24:14 +00:00
|
|
|
|
HubAdminUrl string `env:"HUB_ADMIN_URL" default:"http://localhost:8001/"`
|
2024-03-25 09:47:18 +00:00
|
|
|
|
ServiceName string `env:"SERVICE_NAME" default:"squiz"`
|
2024-03-26 17:48:49 +00:00
|
|
|
|
AuthServiceURL string `env:"AUTH_URL" default:"http://localhost:8000/"`
|
2024-04-03 15:32:05 +00:00
|
|
|
|
GrpcHost string `env:"GRPC_HOST" default:"localhost"`
|
|
|
|
|
GrpcPort string `env:"GRPC_PORT" default:"9000"`
|
2024-04-26 18:51:34 +00:00
|
|
|
|
KafkaBrokers string `env:"KAFKA_BROKERS" default:"localhost:9092"`
|
|
|
|
|
KafkaTopic string `env:"KAFKA_TOPIC" default:"test-topic"`
|
|
|
|
|
KafkaGroup string `env:"KAFKA_GROUP" default:"mailnotifier"`
|
2024-06-02 08:19:22 +00:00
|
|
|
|
TrashLogHost string `env:"TRASH_LOG_HOST" default:"localhost:7113"`
|
|
|
|
|
ModuleLogger string `env:"MODULE_LOGGER" default:"core-local"`
|
2024-06-13 16:14:16 +00:00
|
|
|
|
ClickHouseCred string `env:"CLICK_HOUSE_CRED" default:"tcp://10.8.0.15:9000/default?sslmode=disable"`
|
2024-07-11 09:06:24 +00:00
|
|
|
|
RedisHost string `env:"REDIS_HOST" default:"localhost:6379"`
|
2024-07-11 15:10:16 +00:00
|
|
|
|
RedisPassword string `env:"REDIS_PASSWORD" default:"admin"`
|
2024-07-11 09:06:24 +00:00
|
|
|
|
RedisDB uint64 `env:"REDIS_DB" default:"2"`
|
2024-07-18 19:41:49 +00:00
|
|
|
|
S3Prefix string `env:"S3_PREFIX"`
|
2024-02-19 17:48:04 +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 19:36:34 +00:00
|
|
|
|
zapLogger = zapLogger.With(
|
|
|
|
|
zap.String("SvcCommit", ver.Commit),
|
|
|
|
|
zap.String("SvcVersion", ver.Release),
|
|
|
|
|
zap.String("SvcBuildTime", ver.BuildTime),
|
|
|
|
|
)
|
2024-06-02 08:19:22 +00:00
|
|
|
|
|
2024-06-25 14:41:26 +00:00
|
|
|
|
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)
|
|
|
|
|
}))
|
2024-02-19 17:48:04 +00:00
|
|
|
|
|
2024-06-25 14:41:26 +00:00
|
|
|
|
loggerHlog := hlog.New(loggerForHlog).Module(options.ModuleLogger)
|
2024-06-02 08:19:22 +00:00
|
|
|
|
loggerHlog.With(models.AllFields{})
|
|
|
|
|
loggerHlog.Emit(InfoSvcStarted{})
|
2024-02-19 17:48:04 +00:00
|
|
|
|
|
2024-03-25 09:47:18 +00:00
|
|
|
|
authClient := auth.NewAuthClient(options.AuthServiceURL)
|
2024-02-19 17:48:04 +00:00
|
|
|
|
|
2024-04-16 08:56:47 +00:00
|
|
|
|
pgdal, err := dal.New(ctx, options.PostgresCredentials, nil)
|
2024-02-19 17:48:04 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println("NEW", err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-13 16:14:16 +00:00
|
|
|
|
chDal, err := dal.NewClickHouseDAL(ctx, options.ClickHouseCred)
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println("failed init clickhouse", err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-26 18:51:34 +00:00
|
|
|
|
kafkaClient, err := initialize.KafkaInit(ctx, initialize.KafkaDeps{
|
|
|
|
|
KafkaGroup: options.KafkaGroup,
|
|
|
|
|
KafkaBrokers: options.KafkaBrokers,
|
|
|
|
|
KafkaTopic: options.KafkaTopic,
|
|
|
|
|
})
|
2024-04-26 18:54:18 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2024-04-26 18:51:34 +00:00
|
|
|
|
|
|
|
|
|
producer := brokers.NewProducer(brokers.ProducerDeps{
|
|
|
|
|
KafkaClient: kafkaClient,
|
|
|
|
|
Logger: zapLogger,
|
|
|
|
|
})
|
|
|
|
|
|
2024-07-11 09:06:24 +00:00
|
|
|
|
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))
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-25 09:47:18 +00:00
|
|
|
|
clientData := privilege.Client{
|
|
|
|
|
URL: options.HubAdminUrl,
|
|
|
|
|
ServiceName: options.ServiceName,
|
|
|
|
|
Privileges: model.Privileges,
|
|
|
|
|
}
|
|
|
|
|
fiberClient := &fiber.Client{}
|
|
|
|
|
privilegeController := privilege.NewPrivilege(clientData, fiberClient)
|
2024-03-25 13:24:14 +00:00
|
|
|
|
go tools.PublishPrivilege(privilegeController, 10, 5*time.Minute)
|
2024-03-25 09:47:18 +00:00
|
|
|
|
|
2024-07-09 20:07:44 +00:00
|
|
|
|
tgClient, err := telegram.NewTelegramClient(ctx, pgdal)
|
2024-06-25 14:37:26 +00:00
|
|
|
|
if err != nil {
|
2024-06-30 18:02:23 +00:00
|
|
|
|
panic(fmt.Sprintf("failed init tg clietns: %v", err))
|
2024-06-25 14:37:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-11 09:06:24 +00:00
|
|
|
|
tgWC := workers.NewTgListenerWC(workers.Deps{
|
2024-07-11 15:10:16 +00:00
|
|
|
|
BotID: int64(6712573453), // todo убрать
|
|
|
|
|
Redis: redisClient,
|
|
|
|
|
Dal: pgdal,
|
|
|
|
|
TgClient: tgClient,
|
2024-07-11 09:06:24 +00:00
|
|
|
|
})
|
2024-07-08 10:46:12 +00:00
|
|
|
|
|
2024-07-11 09:06:24 +00:00
|
|
|
|
go tgWC.Start(ctx)
|
2024-07-09 20:07:44 +00:00
|
|
|
|
|
2024-04-03 15:32:05 +00:00
|
|
|
|
// 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,
|
|
|
|
|
})
|
|
|
|
|
|
2024-02-19 17:48:04 +00:00
|
|
|
|
app := fiber.New()
|
2024-07-08 10:47:16 +00:00
|
|
|
|
app.Use(middleware.JWTAuth())
|
|
|
|
|
app.Use(log_mw.ContextLogger(loggerHlog))
|
2024-02-19 17:48:04 +00:00
|
|
|
|
app.Get("/liveness", healthchecks.Liveness)
|
|
|
|
|
app.Get("/readiness", healthchecks.Readiness(&workerErr)) //todo parametrized readiness. should discuss ready reason
|
|
|
|
|
|
2024-03-22 12:42:52 +00:00
|
|
|
|
svc := service.New(service.Deps{
|
2024-06-30 18:02:23 +00:00
|
|
|
|
Dal: pgdal,
|
|
|
|
|
AuthClient: authClient,
|
|
|
|
|
Producer: producer,
|
|
|
|
|
ServiceName: options.ServiceName,
|
|
|
|
|
ChDAL: chDal,
|
|
|
|
|
TelegramClient: tgClient,
|
2024-07-11 09:06:24 +00:00
|
|
|
|
RedisClient: redisClient,
|
2024-09-17 11:21:26 +00:00
|
|
|
|
S3Prefix: options.S3Prefix,
|
2024-03-22 12:42:52 +00:00
|
|
|
|
})
|
|
|
|
|
|
2024-02-19 17:48:04 +00:00
|
|
|
|
svc.Register(app)
|
|
|
|
|
|
2024-06-02 08:19:22 +00:00
|
|
|
|
loggerHlog.Emit(InfoSvcReady{})
|
2024-02-19 17:48:04 +00:00
|
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
|
defer func() {
|
|
|
|
|
if pgdal != nil {
|
|
|
|
|
pgdal.Close()
|
|
|
|
|
}
|
2024-06-13 16:14:16 +00:00
|
|
|
|
if chDal != nil {
|
2024-08-06 13:56:51 +00:00
|
|
|
|
if derr := chDal.Close(ctx); derr != nil {
|
|
|
|
|
fmt.Printf("error closing clickhouse: %v", derr)
|
|
|
|
|
}
|
2024-06-13 16:14:16 +00:00
|
|
|
|
}
|
2024-04-03 15:32:05 +00:00
|
|
|
|
err := grpc.Stop(ctx)
|
|
|
|
|
err = app.Shutdown()
|
2024-06-02 08:19:22 +00:00
|
|
|
|
loggerHlog.Emit(InfoSvcShutdown{Signal: err.Error()})
|
2024-02-19 17:48:04 +00:00
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
if options.IsProd {
|
|
|
|
|
if err := app.ListenTLS(fmt.Sprintf(":%s", options.NumberPort), options.CrtFile, options.KeyFile); err != nil {
|
2024-06-02 08:19:22 +00:00
|
|
|
|
loggerHlog.Emit(ErrorCanNotServe{
|
2024-02-19 17:48:04 +00:00
|
|
|
|
Err: err,
|
|
|
|
|
})
|
|
|
|
|
errChan <- err
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if err := app.Listen(fmt.Sprintf(":%s", options.NumberPort)); err != nil {
|
2024-06-02 08:19:22 +00:00
|
|
|
|
loggerHlog.Emit(ErrorCanNotServe{
|
2024-02-19 17:48:04 +00:00
|
|
|
|
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
|
|
|
|
|
}
|