fix layout
This commit is contained in:
parent
64d15aff7f
commit
36eec4a2c0
156
app/app.go
156
app/app.go
@ -1,156 +0,0 @@
|
|||||||
package app
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"gitea.pena/SQuiz/common/dal"
|
|
||||||
"gitea.pena/SQuiz/common/healthchecks"
|
|
||||||
"gitea.pena/SQuiz/common/middleware"
|
|
||||||
dalBS "gitea.pena/SQuiz/storer/dal"
|
|
||||||
"gitea.pena/SQuiz/storer/service"
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
|
|
||||||
"gitea.pena/PenaSide/hlog"
|
|
||||||
"github.com/minio/minio-go/v7"
|
|
||||||
"github.com/minio/minio-go/v7/pkg/credentials"
|
|
||||||
"github.com/skeris/appInit"
|
|
||||||
"gitea.pena/PenaSide/hlog"
|
|
||||||
"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"`
|
|
||||||
S3Endpoint string `env:"S3_ENDPOINT" envDefault:"localhost:3002"`
|
|
||||||
S3AccessKey string `env:"S3_ACCESS_KEY" envDefault:"minio"`
|
|
||||||
S3SecretKey string `env:"S3_SECRET_KEY" envDefault:"miniostorage"`
|
|
||||||
ClientHttpURL string `env:"CLIENT_HTTP_URL" envDefault:"0.0.0.0:1489"`
|
|
||||||
CrtFile string `env:"CRT" default:"server.crt"`
|
|
||||||
KeyFile string `env:"KEY" default:"server.key"`
|
|
||||||
PostgresURL string `env:"POSTGRES_URL" envDefault:"host=localhost port=5432 user=squiz password=Redalert2 dbname=squiz sslmode=disable"`
|
|
||||||
}
|
|
||||||
|
|
||||||
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),
|
|
||||||
)
|
|
||||||
|
|
||||||
logger := hlog.New(zapLogger)
|
|
||||||
logger.Emit(InfoSvcStarted{})
|
|
||||||
|
|
||||||
pgdal, err := dal.New(ctx, options.PostgresURL, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize minio client object.
|
|
||||||
minioClient, err := minio.New(options.S3Endpoint, &minio.Options{
|
|
||||||
Creds: credentials.NewStaticV4(options.S3AccessKey, options.S3SecretKey, ""),
|
|
||||||
Secure: options.IsProd,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("MINIOERR", options.S3Endpoint, err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
blobstore, err := dalBS.New(ctx, minioClient)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
svc := service.New(blobstore, pgdal)
|
|
||||||
|
|
||||||
app := fiber.New(fiber.Config{BodyLimit: 70 * 1024 * 1024})
|
|
||||||
app.Use(middleware.JWTAuth())
|
|
||||||
app.Get("/liveness", healthchecks.Liveness)
|
|
||||||
app.Get("/readiness", healthchecks.Readiness(&workerErr)) //todo parametrized readiness. should discuss ready reason
|
|
||||||
svc.Register(app)
|
|
||||||
|
|
||||||
logger.Emit(InfoSvcReady{})
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
defer func() {
|
|
||||||
//if pgdal != nil {
|
|
||||||
// pgdal.CloseStorer()
|
|
||||||
//}
|
|
||||||
err := app.Shutdown()
|
|
||||||
if err != nil {
|
|
||||||
logger.Emit(InfoSvcShutdown{Signal: err.Error()})
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if options.IsProd {
|
|
||||||
if err := app.ListenTLS(options.ClientHttpURL, options.CrtFile, options.KeyFile); err != nil {
|
|
||||||
logger.Emit(ErrorCanNotServe{
|
|
||||||
Err: err,
|
|
||||||
})
|
|
||||||
errChan <- err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if err := app.Listen(options.ClientHttpURL); err != nil {
|
|
||||||
logger.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
|
|
||||||
}
|
|
25
cmd/main.go
Normal file
25
cmd/main.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"gitea.pena/SQuiz/storer/internal/app"
|
||||||
|
"gitea.pena/SQuiz/storer/internal/initialize"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"log"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
config, err := initialize.LoadConfig()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Failed to load config", zap.Error(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
defer stop()
|
||||||
|
|
||||||
|
if err = app.Run(ctx, *config); err != nil {
|
||||||
|
log.Fatal("App exited with error", zap.Error(err))
|
||||||
|
}
|
||||||
|
}
|
2
go.mod
2
go.mod
@ -18,6 +18,7 @@ require (
|
|||||||
gitea.pena/PenaSide/common v0.0.0-20250103085335-91ea31fee517 // indirect
|
gitea.pena/PenaSide/common v0.0.0-20250103085335-91ea31fee517 // indirect
|
||||||
github.com/ClickHouse/clickhouse-go v1.5.4 // indirect
|
github.com/ClickHouse/clickhouse-go v1.5.4 // indirect
|
||||||
github.com/andybalholm/brotli v1.1.0 // indirect
|
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||||
|
github.com/caarlos0/env/v8 v8.0.0 // indirect
|
||||||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 // indirect
|
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 // indirect
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/go-ini/ini v1.67.0 // indirect
|
github.com/go-ini/ini v1.67.0 // indirect
|
||||||
@ -25,6 +26,7 @@ require (
|
|||||||
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
|
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
|
||||||
github.com/golang/protobuf v1.5.4 // indirect
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
|
github.com/joho/godotenv v1.5.1 // indirect
|
||||||
github.com/klauspost/compress v1.17.11 // indirect
|
github.com/klauspost/compress v1.17.11 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
|
||||||
github.com/lib/pq v1.10.9 // indirect
|
github.com/lib/pq v1.10.9 // indirect
|
||||||
|
12
go.sum
12
go.sum
@ -2,8 +2,12 @@ gitea.pena/PenaSide/common v0.0.0-20250103085335-91ea31fee517 h1:EgBe8VcdPwmxbSz
|
|||||||
gitea.pena/PenaSide/common v0.0.0-20250103085335-91ea31fee517/go.mod h1:91EuBCgcqgJ6mG36n2pds8sPwwfaJytLWOzY3h2YFKU=
|
gitea.pena/PenaSide/common v0.0.0-20250103085335-91ea31fee517/go.mod h1:91EuBCgcqgJ6mG36n2pds8sPwwfaJytLWOzY3h2YFKU=
|
||||||
gitea.pena/PenaSide/hlog v0.0.0-20241125221102-a54c29c002a9 h1:tBkXWNIt8icmkMMnq8MA421RWkUy4OZh5P7C3q8uCu4=
|
gitea.pena/PenaSide/hlog v0.0.0-20241125221102-a54c29c002a9 h1:tBkXWNIt8icmkMMnq8MA421RWkUy4OZh5P7C3q8uCu4=
|
||||||
gitea.pena/PenaSide/hlog v0.0.0-20241125221102-a54c29c002a9/go.mod h1:sanhSL8aEsfcq21P+eItYiAnKAre+B67nGJmDfk2cf0=
|
gitea.pena/PenaSide/hlog v0.0.0-20241125221102-a54c29c002a9/go.mod h1:sanhSL8aEsfcq21P+eItYiAnKAre+B67nGJmDfk2cf0=
|
||||||
gitea.pena/SQuiz/common v0.0.0-20250207214652-9994f2d4d43f h1:458FCN98jVkjAqg3yyspgkUdJnKz3BNMiZosrVtPpv8=
|
gitea.pena/PenaSide/linters-golang v0.0.0-20241207122018-933207374735 h1:jDVeUhGBTXBibmW5dmtJg2m2+z5z2Rf6J4G0LpjVoJ0=
|
||||||
gitea.pena/SQuiz/common v0.0.0-20250207214652-9994f2d4d43f/go.mod h1:/YR+uo4RouZshuHPkguk7nAJVKuFt3Z0mTFxUPdlzxQ=
|
gitea.pena/PenaSide/linters-golang v0.0.0-20241207122018-933207374735/go.mod h1:gdd+vOT6up9STkEbxa2qESLIMZFjCmRbkcheFQCVgZU=
|
||||||
|
gitea.pena/SQuiz/common v0.0.0-20250205160239-4ed00d74894b h1:N3DdDWQyTXC0B5mI7OpjxHQuHtt6EJCK+vqRrLqcb1w=
|
||||||
|
gitea.pena/SQuiz/common v0.0.0-20250205160239-4ed00d74894b/go.mod h1:zCrUwDh0APpztKk6NUqTZv+zhjVbWpGBJiJ5z9dAH0U=
|
||||||
|
gitea.pena/SQuiz/common v0.0.0-20250221135056-f98c45e04909 h1:iCiqaJ6a7rGESAEUgtVA9IqhVn0oKiwRk7bryTWPV5w=
|
||||||
|
gitea.pena/SQuiz/common v0.0.0-20250221135056-f98c45e04909/go.mod h1:rQRjqLlLyM71FZcvbM95Nv3ciq44F9DFtUHPZmDK3T8=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/ClickHouse/clickhouse-go v1.5.4 h1:cKjXeYLNWVJIx2J1K6H2CqyRmfwVJVY1OV1coaaFcI0=
|
github.com/ClickHouse/clickhouse-go v1.5.4 h1:cKjXeYLNWVJIx2J1K6H2CqyRmfwVJVY1OV1coaaFcI0=
|
||||||
github.com/ClickHouse/clickhouse-go v1.5.4/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
|
github.com/ClickHouse/clickhouse-go v1.5.4/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
|
||||||
@ -11,6 +15,8 @@ github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1
|
|||||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||||
github.com/bkaradzic/go-lz4 v1.0.0 h1:RXc4wYsyz985CkXXeX04y4VnZFGG8Rd43pRaHsOXAKk=
|
github.com/bkaradzic/go-lz4 v1.0.0 h1:RXc4wYsyz985CkXXeX04y4VnZFGG8Rd43pRaHsOXAKk=
|
||||||
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
|
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
|
||||||
|
github.com/caarlos0/env/v8 v8.0.0 h1:POhxHhSpuxrLMIdvTGARuZqR4Jjm8AYmoi/JKlcScs0=
|
||||||
|
github.com/caarlos0/env/v8 v8.0.0/go.mod h1:7K4wMY9bH0esiXSSHlfHLX5xKGQMnkH5Fk4TDSSSzfo=
|
||||||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 h1:F1EaeKL/ta07PY/k9Os/UFtwERei2/XzGemhpGnBKNg=
|
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 h1:F1EaeKL/ta07PY/k9Os/UFtwERei2/XzGemhpGnBKNg=
|
||||||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
|
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@ -35,6 +41,8 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4
|
|||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
||||||
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
|
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||||
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||||
|
96
internal/app/app.go
Normal file
96
internal/app/app.go
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"gitea.pena/SQuiz/storer/internal/initialize"
|
||||||
|
"gitea.pena/SQuiz/storer/internal/server/http"
|
||||||
|
"gitea.pena/SQuiz/storer/pkg/closer"
|
||||||
|
"github.com/gofiber/fiber/v2/log"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var zapOptions = []zap.Option{
|
||||||
|
zap.AddCaller(),
|
||||||
|
zap.AddCallerSkip(2),
|
||||||
|
zap.AddStacktrace(zap.ErrorLevel),
|
||||||
|
}
|
||||||
|
|
||||||
|
func Run(ctx context.Context, cfg initialize.Config) error {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
zapLogger *zap.Logger
|
||||||
|
)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
log.Error("Recovered from a panic", zap.Any("error", r))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if cfg.LoggerProdMode {
|
||||||
|
zapLogger, err = zap.NewProduction(zapOptions...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
zapLogger, err = zap.NewDevelopment(zapOptions...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shutdownGroup := closer.NewCloserGroup()
|
||||||
|
|
||||||
|
minioClient, err := initialize.NewMinio(cfg)
|
||||||
|
if err != nil {
|
||||||
|
zapLogger.Error("Error initializing minio", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
dalS, err := initialize.NewDALs(ctx, cfg, minioClient)
|
||||||
|
if err != nil {
|
||||||
|
zapLogger.Error("Error initializing dals", zap.Error(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
controllers := initialize.NewControllers(initialize.ControllerDeps{
|
||||||
|
DALs: dalS,
|
||||||
|
})
|
||||||
|
|
||||||
|
srv := http.NewServer(http.ServerConfig{
|
||||||
|
Logger: zapLogger,
|
||||||
|
Controllers: []http.Controller{controllers.HttpControllers.QuizFiles},
|
||||||
|
})
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := srv.Start(cfg.ClientHttpURL); err != nil {
|
||||||
|
zapLogger.Error("HTTP server startup error", zap.Error(err))
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
srv.ListRoutes()
|
||||||
|
|
||||||
|
shutdownGroup.Add(closer.CloserFunc(srv.Shutdown))
|
||||||
|
shutdownGroup.Add(closer.CloserFunc(dalS.PgDAL.Close))
|
||||||
|
|
||||||
|
<-ctx.Done()
|
||||||
|
|
||||||
|
timeoutCtx, timeoutCancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
defer timeoutCancel()
|
||||||
|
if err := shutdownGroup.Call(timeoutCtx); err != nil {
|
||||||
|
if errors.Is(err, context.DeadlineExceeded) {
|
||||||
|
zapLogger.Error("Shutdown timed out", zap.Error(err))
|
||||||
|
} else {
|
||||||
|
zapLogger.Error("Failed to shutdown services gracefully", zap.Error(err))
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
zapLogger.Info("Application has stopped")
|
||||||
|
return nil
|
||||||
|
}
|
@ -1,41 +1,30 @@
|
|||||||
package service
|
package quiz_files
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/gofiber/fiber/v2"
|
"gitea.pena/SQuiz/common/dal"
|
||||||
"io"
|
|
||||||
quizdal "gitea.pena/SQuiz/common/dal"
|
|
||||||
mw "gitea.pena/SQuiz/common/middleware"
|
mw "gitea.pena/SQuiz/common/middleware"
|
||||||
"gitea.pena/SQuiz/storer/dal"
|
"gitea.pena/SQuiz/storer/internal/repository"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/rs/xid"
|
||||||
|
"io"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/rs/xid"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Service struct {
|
type QuizFiles struct {
|
||||||
store *dal.Storer
|
stDal *repository.S3
|
||||||
dal *quizdal.DAL
|
pgDal *dal.DAL
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(s *dal.Storer, q *quizdal.DAL) *Service {
|
func New(stDal *repository.S3, pgDal *dal.DAL) *QuizFiles {
|
||||||
return &Service{
|
return &QuizFiles{
|
||||||
store: s,
|
stDal: stDal,
|
||||||
dal: q,
|
pgDal: pgDal,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) Register(app *fiber.App) {
|
func (r *QuizFiles) UploadCustom(c *fiber.Ctx) error {
|
||||||
app.Put("/quiz/customization", s.UploadCustom)
|
|
||||||
app.Put("/quiz/putImages", s.UploadImages)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MB Size constants
|
|
||||||
const (
|
|
||||||
MB = 1 << 20
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s *Service) UploadCustom(c *fiber.Ctx) error {
|
|
||||||
accountId, ok := mw.GetAccountId(c)
|
accountId, ok := mw.GetAccountId(c)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
@ -57,7 +46,7 @@ func (s *Service) UploadCustom(c *fiber.Ctx) error {
|
|||||||
return c.Status(fiber.StatusBadRequest).SendString("not valid quiz id provided " + err.Error())
|
return c.Status(fiber.StatusBadRequest).SendString("not valid quiz id provided " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
quiz, err := s.dal.QuizRepo.GetQuizById(c.Context(), accountId, uint64(squizId))
|
quiz, err := r.pgDal.QuizRepo.GetQuizById(c.Context(), accountId, uint64(squizId))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Status(fiber.StatusNotAcceptable).SendString("not exists quiz id provided " + err.Error())
|
return c.Status(fiber.StatusNotAcceptable).SendString("not exists quiz id provided " + err.Error())
|
||||||
}
|
}
|
||||||
@ -82,7 +71,7 @@ func (s *Service) UploadCustom(c *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
if err := s.store.UploadScript(c.Context(), quiz.Qid, file, fileHeader.Size); err != nil {
|
if err := r.stDal.UploadScript(c.Context(), quiz.Qid, file, fileHeader.Size); err != nil {
|
||||||
errm.Lock()
|
errm.Lock()
|
||||||
defer errm.Unlock()
|
defer errm.Unlock()
|
||||||
errs = append(errs, errors.New(err.Error()+" => script upload"))
|
errs = append(errs, errors.New(err.Error()+" => script upload"))
|
||||||
@ -104,7 +93,7 @@ func (s *Service) UploadCustom(c *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
if err := s.store.UploadStyle(c.Context(), quiz.Qid, file, fileHeader.Size); err != nil {
|
if err := r.stDal.UploadStyle(c.Context(), quiz.Qid, file, fileHeader.Size); err != nil {
|
||||||
errm.Lock()
|
errm.Lock()
|
||||||
defer errm.Unlock()
|
defer errm.Unlock()
|
||||||
errs = append(errs, errors.New(err.Error()+" => style upload"))
|
errs = append(errs, errors.New(err.Error()+" => style upload"))
|
||||||
@ -128,7 +117,7 @@ func (s *Service) UploadCustom(c *fiber.Ctx) error {
|
|||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
if errorsFontUploading := s.store.UploadFonts(c.Context(), quiz.Qid, files, sizes); err != nil {
|
if errorsFontUploading := r.stDal.UploadFonts(c.Context(), quiz.Qid, files, sizes); err != nil {
|
||||||
errm.Lock()
|
errm.Lock()
|
||||||
defer errm.Unlock()
|
defer errm.Unlock()
|
||||||
errs = append(errs, errorsFontUploading...)
|
errs = append(errs, errorsFontUploading...)
|
||||||
@ -144,7 +133,7 @@ func (s *Service) UploadCustom(c *fiber.Ctx) error {
|
|||||||
return c.SendStatus(fiber.StatusOK)
|
return c.SendStatus(fiber.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) UploadImages(c *fiber.Ctx) error {
|
func (r *QuizFiles) UploadImages(c *fiber.Ctx) error {
|
||||||
accountId, ok := mw.GetAccountId(c)
|
accountId, ok := mw.GetAccountId(c)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
@ -166,7 +155,7 @@ func (s *Service) UploadImages(c *fiber.Ctx) error {
|
|||||||
return c.Status(fiber.StatusBadRequest).SendString("not valid quiz id provided " + err.Error())
|
return c.Status(fiber.StatusBadRequest).SendString("not valid quiz id provided " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
quiz, err := s.dal.QuizRepo.GetQuizById(c.Context(), accountId, uint64(squizId))
|
quiz, err := r.pgDal.QuizRepo.GetQuizById(c.Context(), accountId, uint64(squizId))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Status(fiber.StatusNotAcceptable).SendString("not exists quiz id provided " + err.Error())
|
return c.Status(fiber.StatusNotAcceptable).SendString("not exists quiz id provided " + err.Error())
|
||||||
}
|
}
|
||||||
@ -189,7 +178,7 @@ func (s *Service) UploadImages(c *fiber.Ctx) error {
|
|||||||
defer f.Close()
|
defer f.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.store.UploadImages(c.Context(), quiz.Qid, files, sizes); err != nil {
|
if err := r.stDal.UploadImages(c.Context(), quiz.Qid, files, sizes); err != nil {
|
||||||
errs = append(errs, err...)
|
errs = append(errs, err...)
|
||||||
}
|
}
|
||||||
}
|
}
|
12
internal/controllers/http_controllers/quiz_files/route.go
Normal file
12
internal/controllers/http_controllers/quiz_files/route.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package quiz_files
|
||||||
|
|
||||||
|
import "github.com/gofiber/fiber/v2"
|
||||||
|
|
||||||
|
func (r *QuizFiles) Register(router fiber.Router) {
|
||||||
|
router.Put("/customization", r.UploadCustom)
|
||||||
|
router.Put("/putImages", r.UploadImages)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *QuizFiles) Name() string {
|
||||||
|
return "quiz"
|
||||||
|
}
|
30
internal/initialize/config.go
Normal file
30
internal/initialize/config.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package initialize
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/caarlos0/env/v8"
|
||||||
|
"github.com/joho/godotenv"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
LoggerProdMode bool `env:"IS_PROD_LOG" default:"false"`
|
||||||
|
IsProd bool `env:"IS_PROD" default:"false"`
|
||||||
|
S3Endpoint string `env:"S3_ENDPOINT" envDefault:"localhost:9001"`
|
||||||
|
S3AccessKey string `env:"S3_ACCESS_KEY" envDefault:"admin"`
|
||||||
|
S3SecretKey string `env:"S3_SECRET_KEY" envDefault:"admin123"`
|
||||||
|
ClientHttpURL string `env:"CLIENT_HTTP_URL" envDefault:"0.0.0.0:1489"`
|
||||||
|
CrtFile string `env:"CRT" default:"server.crt"`
|
||||||
|
KeyFile string `env:"KEY" default:"server.key"`
|
||||||
|
PostgresURL string `env:"POSTGRES_URL" envDefault:"host=localhost port=35432 user=squiz password=Redalert2 dbname=squiz sslmode=disable"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadConfig() (*Config, error) {
|
||||||
|
if err := godotenv.Load(); err != nil {
|
||||||
|
log.Print("No .env file found")
|
||||||
|
}
|
||||||
|
var config Config
|
||||||
|
if err := env.Parse(&config); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &config, nil
|
||||||
|
}
|
25
internal/initialize/controllers.go
Normal file
25
internal/initialize/controllers.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package initialize
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitea.pena/SQuiz/storer/internal/controllers/http_controllers/quiz_files"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ControllerDeps struct {
|
||||||
|
DALs *DALs
|
||||||
|
}
|
||||||
|
|
||||||
|
type Controller struct {
|
||||||
|
HttpControllers HttpControllers
|
||||||
|
}
|
||||||
|
|
||||||
|
type HttpControllers struct {
|
||||||
|
QuizFiles *quiz_files.QuizFiles
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewControllers(deps ControllerDeps) *Controller {
|
||||||
|
return &Controller{
|
||||||
|
HttpControllers: HttpControllers{
|
||||||
|
QuizFiles: quiz_files.New(deps.DALs.StDal, deps.DALs.PgDAL),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
30
internal/initialize/dals.go
Normal file
30
internal/initialize/dals.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package initialize
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"gitea.pena/SQuiz/common/dal"
|
||||||
|
"gitea.pena/SQuiz/storer/internal/repository"
|
||||||
|
"github.com/minio/minio-go/v7"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DALs struct {
|
||||||
|
PgDAL *dal.DAL
|
||||||
|
StDal *repository.S3
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDALs(ctx context.Context, cfg Config, minioClient *minio.Client) (*DALs, error) {
|
||||||
|
pgDal, err := dal.New(ctx, cfg.PostgresURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
stDal, err := repository.New(ctx, minioClient)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &DALs{
|
||||||
|
PgDAL: pgDal,
|
||||||
|
StDal: stDal,
|
||||||
|
}, nil
|
||||||
|
}
|
17
internal/initialize/minio.go
Normal file
17
internal/initialize/minio.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package initialize
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/minio/minio-go/v7"
|
||||||
|
"github.com/minio/minio-go/v7/pkg/credentials"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewMinio(cfg Config) (*minio.Client, error) {
|
||||||
|
minioClient, err := minio.New(cfg.S3Endpoint, &minio.Options{
|
||||||
|
Creds: credentials.NewStaticV4(cfg.S3AccessKey, cfg.S3SecretKey, ""),
|
||||||
|
Secure: cfg.IsProd,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return minioClient, nil
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package dal
|
package repository
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -9,25 +9,25 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
bucket = "3c580be9-cf31f296-d055-49cf-b39e-30c7959dc17b"
|
bucket = "3c580be9-cf31f296-d055-49cf-b39e-30c7959dc17b"
|
||||||
folderImages = "squizimages"
|
folderImages = "squizimages"
|
||||||
bucketFonts = "squizfonts"
|
bucketFonts = "squizfonts"
|
||||||
bucketScripts = "squizscript"
|
bucketScripts = "squizscript"
|
||||||
bucketStyle = "squizstyle"
|
bucketStyle = "squizstyle"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Storer struct {
|
type S3 struct {
|
||||||
client *minio.Client
|
client *minio.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(ctx context.Context, minioClient *minio.Client) (*Storer, error) {
|
func New(ctx context.Context, minioClient *minio.Client) (*S3, error) {
|
||||||
|
|
||||||
return &Storer{
|
return &S3{
|
||||||
client: minioClient,
|
client: minioClient,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Storer) UploadImages(ctx context.Context, quid string, files map[string]io.Reader, sizes map[string]int64) []error {
|
func (s *S3) UploadImages(ctx context.Context, quid string, files map[string]io.Reader, sizes map[string]int64) []error {
|
||||||
var (
|
var (
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
m sync.Mutex
|
m sync.Mutex
|
||||||
@ -57,7 +57,7 @@ func (s *Storer) UploadImages(ctx context.Context, quid string, files map[string
|
|||||||
return errs
|
return errs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Storer) UploadFonts(ctx context.Context, quid string, files map[string]io.Reader, sizes map[string]int64) []error {
|
func (s *S3) UploadFonts(ctx context.Context, quid string, files map[string]io.Reader, sizes map[string]int64) []error {
|
||||||
var (
|
var (
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
m sync.Mutex
|
m sync.Mutex
|
||||||
@ -71,7 +71,7 @@ func (s *Storer) UploadFonts(ctx context.Context, quid string, files map[string]
|
|||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
if _, err := s.client.PutObject(ctx,
|
if _, err := s.client.PutObject(ctx,
|
||||||
bucket,
|
bucket,
|
||||||
bucketFonts + "/" +fmt.Sprintf("%s/%s", quid, fname),
|
bucketFonts+"/"+fmt.Sprintf("%s/%s", quid, fname),
|
||||||
reader,
|
reader,
|
||||||
sizes[fname],
|
sizes[fname],
|
||||||
minio.PutObjectOptions{}); err != nil {
|
minio.PutObjectOptions{}); err != nil {
|
||||||
@ -87,10 +87,10 @@ func (s *Storer) UploadFonts(ctx context.Context, quid string, files map[string]
|
|||||||
return errs
|
return errs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Storer) UploadScript(ctx context.Context, quid string, file io.Reader, size int64) error {
|
func (s *S3) UploadScript(ctx context.Context, quid string, file io.Reader, size int64) error {
|
||||||
if _, err := s.client.PutObject(ctx,
|
if _, err := s.client.PutObject(ctx,
|
||||||
bucket,
|
bucket,
|
||||||
bucketScripts + "/" + fmt.Sprintf("%s.js", quid),
|
bucketScripts+"/"+fmt.Sprintf("%s.js", quid),
|
||||||
file,
|
file,
|
||||||
size,
|
size,
|
||||||
minio.PutObjectOptions{}); err != nil {
|
minio.PutObjectOptions{}); err != nil {
|
||||||
@ -100,10 +100,10 @@ func (s *Storer) UploadScript(ctx context.Context, quid string, file io.Reader,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Storer) UploadStyle(ctx context.Context, quid string, file io.Reader, size int64) error {
|
func (s *S3) UploadStyle(ctx context.Context, quid string, file io.Reader, size int64) error {
|
||||||
if _, err := s.client.PutObject(ctx,
|
if _, err := s.client.PutObject(ctx,
|
||||||
bucket,
|
bucket,
|
||||||
bucketStyle + "/" + fmt.Sprintf("%s.css", quid),
|
bucketStyle+"/"+fmt.Sprintf("%s.css", quid),
|
||||||
file,
|
file,
|
||||||
size,
|
size,
|
||||||
minio.PutObjectOptions{}); err != nil {
|
minio.PutObjectOptions{}); err != nil {
|
69
internal/server/http/http_server.go
Normal file
69
internal/server/http/http_server.go
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"gitea.pena/SQuiz/common/middleware"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServerConfig struct {
|
||||||
|
Logger *zap.Logger
|
||||||
|
Controllers []Controller
|
||||||
|
}
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
Logger *zap.Logger
|
||||||
|
Controllers []Controller
|
||||||
|
app *fiber.App
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServer(config ServerConfig) *Server {
|
||||||
|
app := fiber.New(fiber.Config{BodyLimit: 70 * 1024 * 1024})
|
||||||
|
app.Use(middleware.JWTAuth())
|
||||||
|
//app.Get("/liveness", healthchecks.Liveness)
|
||||||
|
//app.Get("/readiness", healthchecks.Readiness(&workerErr)) //todo parametrized readiness. should discuss ready reason
|
||||||
|
s := &Server{
|
||||||
|
Logger: config.Logger,
|
||||||
|
Controllers: config.Controllers,
|
||||||
|
app: app,
|
||||||
|
}
|
||||||
|
|
||||||
|
s.registerRoutes()
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Start(addr string) error {
|
||||||
|
if err := s.app.Listen(addr); err != nil {
|
||||||
|
s.Logger.Error("Failed to start server", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Shutdown(ctx context.Context) error {
|
||||||
|
return s.app.Shutdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) registerRoutes() {
|
||||||
|
for _, c := range s.Controllers {
|
||||||
|
router := s.app.Group(c.Name())
|
||||||
|
c.Register(router)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Controller interface {
|
||||||
|
Register(router fiber.Router)
|
||||||
|
Name() string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) ListRoutes() {
|
||||||
|
fmt.Println("Registered routes:")
|
||||||
|
for _, stack := range s.app.Stack() {
|
||||||
|
for _, route := range stack {
|
||||||
|
fmt.Printf("%s %s\n", route.Method, route.Path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
main.go
11
main.go
@ -1,11 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/skeris/appInit"
|
|
||||||
"gitea.pena/SQuiz/storer/app"
|
|
||||||
_ "gitea.pena/PenaSide/linters-golang/pkg/dummy"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
appInit.Initialize(app.New, app.Options{})
|
|
||||||
}
|
|
37
pkg/closer/closer.go
Normal file
37
pkg/closer/closer.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package closer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Closer interface {
|
||||||
|
Close(ctx context.Context) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type CloserFunc func(ctx context.Context) error
|
||||||
|
|
||||||
|
func (cf CloserFunc) Close(ctx context.Context) error {
|
||||||
|
return cf(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
type CloserGroup struct {
|
||||||
|
closers []Closer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCloserGroup() *CloserGroup {
|
||||||
|
return &CloserGroup{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cg *CloserGroup) Add(c Closer) {
|
||||||
|
cg.closers = append(cg.closers, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cg *CloserGroup) Call(ctx context.Context) error {
|
||||||
|
var closeErr error
|
||||||
|
for i := len(cg.closers) - 1; i >= 0; i-- {
|
||||||
|
if err := cg.closers[i].Close(ctx); err != nil && closeErr == nil {
|
||||||
|
closeErr = err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return closeErr
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user