diff --git a/go.mod b/go.mod index 6ad8ba5..e2d7bde 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,9 @@ require ( github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.51.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect + go.mongodb.org/mongo-driver v1.15.0 // indirect go.uber.org/multierr v1.10.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/sys v0.15.0 // indirect + penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240527160654-bd1c2126bc6c // indirect ) diff --git a/go.sum b/go.sum index 45bc0d6..53e10b3 100644 --- a/go.sum +++ b/go.sum @@ -25,6 +25,8 @@ github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1S github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +go.mongodb.org/mongo-driver v1.15.0 h1:rJCKC8eEliewXjZGf0ddURtl7tTVy1TK3bfl0gkUSLc= +go.mongodb.org/mongo-driver v1.15.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= @@ -33,3 +35,5 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240527160654-bd1c2126bc6c h1:jxnyIeC2CNDNmfdFx2qnLS4Qd0v5ocYrY9X+OL9qsvc= +penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240527160654-bd1c2126bc6c/go.mod h1:lTmpjry+8evVkXWbEC+WMOELcFkRD1lFMc7J09mOndM= diff --git a/internal/app/app.go b/internal/app/app.go index e5ee8be..b86da51 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -2,8 +2,12 @@ package app import ( "context" + "errors" "go.uber.org/zap" "hub_admin_backend_service/internal/initialize" + "hub_admin_backend_service/internal/server/http" + "hub_admin_backend_service/pkg/closer" + "time" ) func Run(ctx context.Context, cfg initialize.Config, logger *zap.Logger) error { @@ -14,6 +18,70 @@ func Run(ctx context.Context, cfg initialize.Config, logger *zap.Logger) error { }() logger.Info("Starting application", zap.String("AppName", cfg.AppName)) + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + shutdownGroup := closer.NewCloserGroup() + + mdb, err := initialize.MongoDB(ctx, cfg) + if err != nil { + logger.Error("Failed to initialize MongoDB", zap.Error(err)) + return err + } + + repositories := initialize.NewRepository(initialize.RepositoryDeps{ + Logger: logger, + Mdb: mdb, + }) + + controllers := initialize.NewControllers(initialize.ControllerDeps{ + Logger: logger, + Repos: repositories, + }) + + internalSrv := http.NewServer(http.ServerConfig{ + Logger: logger, + Controllers: []http.Controller{controllers.PrivilegeInternal}, + }) + + externalSrv := http.NewServer(http.ServerConfig{ + Logger: logger, + Controllers: []http.Controller{controllers.PrivilegeExternal}, + }) + + go func() { + if err := internalSrv.Start(cfg.InternalHttpAddress); err != nil { + logger.Error("Server startup error", zap.Error(err)) + cancel() + } + }() + + go func() { + if err := externalSrv.Start(cfg.ExternalHttpAddress); err != nil { + logger.Error("Server startup error", zap.Error(err)) + cancel() + } + }() + + internalSrv.ListRoutes() + externalSrv.ListRoutes() + + shutdownGroup.Add(closer.CloserFunc(internalSrv.Shutdown)) + shutdownGroup.Add(closer.CloserFunc(externalSrv.Shutdown)) + shutdownGroup.Add(closer.CloserFunc(mdb.Client().Disconnect)) + + <-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) { + logger.Error("Shutdown timed out", zap.Error(err)) + } else { + logger.Error("Failed to shutdown services gracefully", zap.Error(err)) + } + return err + } logger.Info("Application has stopped") return nil diff --git a/internal/controller/privilege_external/controller.go b/internal/controller/privilege_external/controller.go index b0b7d22..20a5a01 100644 --- a/internal/controller/privilege_external/controller.go +++ b/internal/controller/privilege_external/controller.go @@ -1,11 +1,29 @@ package privilege_external +import ( + "github.com/gofiber/fiber/v2" + "go.uber.org/zap" + "hub_admin_backend_service/internal/repository/privilege" + "net/http" +) + type Deps struct { + Repo *privilege.Privilege + Logger *zap.Logger } type PrivilegeExternal struct { + repo *privilege.Privilege + logger *zap.Logger } func NewPrivilegeExternal(deps Deps) *PrivilegeExternal { - return &PrivilegeExternal{} + return &PrivilegeExternal{ + repo: deps.Repo, + logger: deps.Logger, + } +} + +func (p *PrivilegeExternal) GetAllService(c *fiber.Ctx) error { + return c.SendStatus(http.StatusOK) } diff --git a/internal/controller/privilege_external/route.go b/internal/controller/privilege_external/route.go index 39f708b..1827ea9 100644 --- a/internal/controller/privilege_external/route.go +++ b/internal/controller/privilege_external/route.go @@ -2,7 +2,6 @@ package privilege_external import ( "github.com/gofiber/fiber/v2" - "net/http" ) func (p *PrivilegeExternal) Register(router fiber.Router) { @@ -12,7 +11,3 @@ func (p *PrivilegeExternal) Register(router fiber.Router) { func (p *PrivilegeExternal) Name() string { return "" } - -func (p *PrivilegeExternal) GetAllService(c *fiber.Ctx) error { - return c.SendStatus(http.StatusOK) -} diff --git a/internal/controller/privilege_internal/controller.go b/internal/controller/privilege_internal/controller.go index 0638d2e..a3fdc9f 100644 --- a/internal/controller/privilege_internal/controller.go +++ b/internal/controller/privilege_internal/controller.go @@ -2,17 +2,26 @@ package privilege_internal import ( "github.com/gofiber/fiber/v2" + "go.uber.org/zap" + "hub_admin_backend_service/internal/repository/privilege" "net/http" ) type Deps struct { + Repo *privilege.Privilege + Logger *zap.Logger } type PrivilegeInternal struct { + repo *privilege.Privilege + logger *zap.Logger } func NewPrivilegeInternal(deps Deps) *PrivilegeInternal { - return &PrivilegeInternal{} + return &PrivilegeInternal{ + repo: deps.Repo, + logger: deps.Logger, + } } func (p *PrivilegeInternal) Get(c *fiber.Ctx) error { diff --git a/internal/initialize/config.go b/internal/initialize/config.go index aad4038..2540c6f 100644 --- a/internal/initialize/config.go +++ b/internal/initialize/config.go @@ -7,15 +7,15 @@ import ( ) type Config struct { - AppName string `env:"APP_NAME" envDefault:"hub-admin-backend-service"` - HTTPHost string `env:"HTTP_HOST" envDefault:"localhost"` - HTTPPort string `env:"HTTP_PORT" envDefault:"3000"` - MongoHost string `env:"MONGO_HOST" envDefault:"127.0.0.1"` - MongoPort string `env:"MONGO_PORT" envDefault:"27020"` - MongoUser string `env:"MONGO_USER" envDefault:"test"` - MongoPassword string `env:"MONGO_PASSWORD" envDefault:"test"` - MongoDatabase string `env:"MONGO_DB" envDefault:"admin"` - MongoAuth string `env:"MONGO_AUTH" envDefault:"admin"` + AppName string `env:"APP_NAME" envDefault:"hub-admin-backend-service"` + InternalHttpAddress string `env:"INTERNAL_HTTP_ADDRESS" envDefault:"localhost:8000"` + ExternalHttpAddress string `env:"EXTERNAL_HTTP_ADDRESS" envDefault:"localhost:8001"` + MongoHost string `env:"MONGO_HOST" envDefault:"127.0.0.1"` + MongoPort string `env:"MONGO_PORT" envDefault:"27020"` + MongoUser string `env:"MONGO_USER" envDefault:"test"` + MongoPassword string `env:"MONGO_PASSWORD" envDefault:"test"` + MongoDatabase string `env:"MONGO_DB" envDefault:"admin"` + MongoAuth string `env:"MONGO_AUTH" envDefault:"admin"` } func LoadConfig() (*Config, error) { diff --git a/internal/initialize/controller.go b/internal/initialize/controller.go new file mode 100644 index 0000000..581f22d --- /dev/null +++ b/internal/initialize/controller.go @@ -0,0 +1,30 @@ +package initialize + +import ( + "go.uber.org/zap" + "hub_admin_backend_service/internal/controller/privilege_external" + "hub_admin_backend_service/internal/controller/privilege_internal" +) + +type ControllerDeps struct { + Logger *zap.Logger + Repos *Repository +} + +type Controller struct { + PrivilegeInternal *privilege_internal.PrivilegeInternal + PrivilegeExternal *privilege_external.PrivilegeExternal +} + +func NewControllers(deps ControllerDeps) *Controller { + return &Controller{ + PrivilegeInternal: privilege_internal.NewPrivilegeInternal(privilege_internal.Deps{ + Repo: deps.Repos.PrivilegeRepo, + Logger: deps.Logger, + }), + PrivilegeExternal: privilege_external.NewPrivilegeExternal(privilege_external.Deps{ + Repo: deps.Repos.PrivilegeRepo, + Logger: deps.Logger, + }), + } +} diff --git a/internal/initialize/mongo.go b/internal/initialize/mongo.go new file mode 100644 index 0000000..76df7b6 --- /dev/null +++ b/internal/initialize/mongo.go @@ -0,0 +1,39 @@ +package initialize + +import ( + "context" + "go.mongodb.org/mongo-driver/mongo" + mdb "penahub.gitlab.yandexcloud.net/backend/penahub_common/mongo" + "time" +) + +func MongoDB(ctx context.Context, cfg Config) (*mongo.Database, error) { + dbConfig := &mdb.Configuration{ + Host: cfg.MongoHost, + Port: cfg.MongoPort, + User: cfg.MongoUser, + Password: cfg.MongoPassword, + DatabaseName: cfg.MongoDatabase, + Auth: cfg.MongoAuth, + } + + newCtx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + + mongoDeps := &mdb.ConnectDeps{ + Configuration: dbConfig, + Timeout: 10 * time.Second, + } + + db, err := mdb.Connect(newCtx, mongoDeps) + if err != nil { + return nil, err + } + + err = db.Client().Ping(newCtx, nil) + if err != nil { + return nil, err + } + + return db, nil +} diff --git a/internal/initialize/repository.go b/internal/initialize/repository.go new file mode 100644 index 0000000..8f6654d --- /dev/null +++ b/internal/initialize/repository.go @@ -0,0 +1,25 @@ +package initialize + +import ( + "go.mongodb.org/mongo-driver/mongo" + "go.uber.org/zap" + "hub_admin_backend_service/internal/repository/privilege" +) + +type RepositoryDeps struct { + Logger *zap.Logger + Mdb *mongo.Database +} + +type Repository struct { + PrivilegeRepo *privilege.Privilege +} + +func NewRepository(deps RepositoryDeps) *Repository { + return &Repository{ + PrivilegeRepo: privilege.NewPrivilegeRepo(privilege.Deps{ + Mdb: deps.Mdb.Collection(""), + Logger: deps.Logger, + }), + } +} diff --git a/internal/models/privilege.go b/internal/models/privilege.go new file mode 100644 index 0000000..999cfc6 --- /dev/null +++ b/internal/models/privilege.go @@ -0,0 +1,22 @@ +package models + +import ( + "go.mongodb.org/mongo-driver/bson/primitive" + "time" +) + +type Privilege struct { + ID primitive.ObjectID `bson:"_id"` + Name string `bson:"name"` + PrivilegeID string `bson:"privilegeId"` + Amount int `bson:"amount"` + ServiceKey string `bson:"serviceKey"` + Description string `bson:"description"` + Type string `bson:"type"` + Value string `bson:"value"` + Price float64 `bson:"price"` + CreatedAt time.Time `bson:"createdAt"` + UpdatedAt time.Time `bson:"updatedAt"` + IsDeleted bool `bson:"isDeleted"` + DeletedAt *time.Time `bson:"deletedAt"` +} diff --git a/internal/repository/privilege/privilege.go b/internal/repository/privilege/privilege.go new file mode 100644 index 0000000..7758eab --- /dev/null +++ b/internal/repository/privilege/privilege.go @@ -0,0 +1,23 @@ +package privilege + +import ( + "go.mongodb.org/mongo-driver/mongo" + "go.uber.org/zap" +) + +type Deps struct { + Mdb *mongo.Collection + Logger *zap.Logger +} + +type Privilege struct { + mdb *mongo.Collection + logger *zap.Logger +} + +func NewPrivilegeRepo(deps Deps) *Privilege { + return &Privilege{ + mdb: deps.Mdb, + logger: deps.Logger, + } +} diff --git a/pkg/closer/closer.go b/pkg/closer/closer.go new file mode 100644 index 0000000..fdfbaf1 --- /dev/null +++ b/pkg/closer/closer.go @@ -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 +}