Skip to content

Commit

Permalink
Merge pull request #1 from MowlCoder/staging
Browse files Browse the repository at this point in the history
complete http part of gophermart
  • Loading branch information
MowlCoder committed Oct 22, 2023
2 parents 0b3fee4 + 8ec37e5 commit 04415f7
Show file tree
Hide file tree
Showing 77 changed files with 7,736 additions and 9 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
*.so
*.dylib

.env

# Test binary, built with `go test -c`
*.test

Expand Down
3 changes: 0 additions & 3 deletions cmd/accrual/README.md

This file was deleted.

136 changes: 135 additions & 1 deletion cmd/accrual/main.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,137 @@
package main

func main() {}
import (
"context"
"fmt"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"

"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/joho/godotenv"
httpSwagger "github.com/swaggo/http-swagger/v2"

"github.com/MowlCoder/accumulative-loyalty-system/internal/config"
"github.com/MowlCoder/accumulative-loyalty-system/internal/handlers"
"github.com/MowlCoder/accumulative-loyalty-system/internal/middlewares"
"github.com/MowlCoder/accumulative-loyalty-system/internal/repositories"
"github.com/MowlCoder/accumulative-loyalty-system/internal/services"
"github.com/MowlCoder/accumulative-loyalty-system/internal/storage/postgresql"
"github.com/MowlCoder/accumulative-loyalty-system/internal/workers"

_ "github.com/MowlCoder/accumulative-loyalty-system/docs/accrual"
)

func main() {
err := godotenv.Load(".env")

if err != nil {
log.Println("No .env provided")
}

appConfig := &config.AccrualConfig{}
appConfig.Parse()

dbPool, err := postgresql.InitPool(appConfig.DatabaseURI)
if err != nil {
log.Panic(err)
}
defer dbPool.Close()

err = postgresql.RunMigrations(appConfig.DatabaseURI)
if err != nil {
log.Panic(err)
}

goodRewardRepository := repositories.NewGoodRewardRepository(dbPool)
registeredOrdersRepository := repositories.NewRegisteredOrdersRepository(dbPool)

goodRewardsService := services.NewGoodRewardsService(goodRewardRepository)
accrualOrdersService := services.NewAccrualOrdersService(registeredOrdersRepository)

goodsHandler := handlers.NewGoodsHandler(goodRewardsService)
accrualOrdersHandler := handlers.NewAccrualOrdersHandler(accrualOrdersService)

workersCtx, workersStopCtx := context.WithCancel(context.Background())

calculateOrderAccrualWorker := workers.NewCalculateOrderAccrualWorker(
registeredOrdersRepository,
goodRewardRepository,
)
go calculateOrderAccrualWorker.Start(workersCtx)

server := &http.Server{
Addr: appConfig.RunAddress,
Handler: makeRouter(appConfig, goodsHandler, accrualOrdersHandler),
}

log.Println("Accrual server is running on", appConfig.RunAddress)

go func() {
err = server.ListenAndServe()

if err != nil && err != http.ErrServerClosed {
log.Fatal(err)
}
}()

sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)

<-sig

log.Println("start graceful shutdown...")

shutdownCtx, shutdownCtxCancel := context.WithTimeout(context.Background(), 30*time.Second)
defer shutdownCtxCancel()

go func() {
<-shutdownCtx.Done()
if shutdownCtx.Err() == context.DeadlineExceeded {
log.Fatal("graceful shutdown timed out... forcing exit")
}
}()

err = server.Shutdown(shutdownCtx)
if err != nil {
log.Fatal(err)
}

workersStopCtx()

log.Println("graceful shutdown server successfully")
}

// @title Gophermart Accrual Service
// @version 1.0
// @description Accrual service responsible for calculating accrual for registered orders
// @BasePath /api
func makeRouter(
appConfig *config.AccrualConfig,
goodsHandler *handlers.GoodsHandler,
accrualOrdersHandler *handlers.AccrualOrdersHandler,
) http.Handler {
router := chi.NewRouter()

router.Use(middleware.Recoverer)
router.Use(middleware.Logger)

router.Route("/api/goods", func(r chi.Router) {
r.Post("/", goodsHandler.SaveNewGoodReward)
})

router.Route("/api/orders", func(r chi.Router) {
r.Get("/{orderID}", middlewares.NewRateLimit(2000, time.Minute*1)(http.HandlerFunc(accrualOrdersHandler.GetRegisteredOrderInfo)))
r.Post("/", accrualOrdersHandler.RegisterOrderForAccrual)
})

router.Get("/swagger/*", httpSwagger.Handler(
httpSwagger.URL(fmt.Sprintf("http://%s/swagger/doc.json", appConfig.RunAddress)),
))

return router
}
4 changes: 0 additions & 4 deletions cmd/gophermart/README.md

This file was deleted.

156 changes: 155 additions & 1 deletion cmd/gophermart/main.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,157 @@
package main

func main() {}
import (
"context"
"fmt"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"

"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/joho/godotenv"
httpSwagger "github.com/swaggo/http-swagger/v2"

"github.com/MowlCoder/accumulative-loyalty-system/internal/config"
"github.com/MowlCoder/accumulative-loyalty-system/internal/handlers"
"github.com/MowlCoder/accumulative-loyalty-system/internal/middlewares"
"github.com/MowlCoder/accumulative-loyalty-system/internal/repositories"
"github.com/MowlCoder/accumulative-loyalty-system/internal/services"
"github.com/MowlCoder/accumulative-loyalty-system/internal/storage/postgresql"
"github.com/MowlCoder/accumulative-loyalty-system/internal/workers"

_ "github.com/MowlCoder/accumulative-loyalty-system/docs/gophermart"
)

func main() {
err := godotenv.Load(".env")

if err != nil {
log.Println("No .env provided")
}

appConfig := &config.GophermartConfig{}
appConfig.Parse()

dbPool, err := postgresql.InitPool(appConfig.DatabaseURI)
if err != nil {
log.Panic(err)
}
defer dbPool.Close()

err = postgresql.RunMigrations(appConfig.DatabaseURI)
if err != nil {
log.Panic(err)
}

userRepository := repositories.NewUserRepository(dbPool)
balanceActionsRepository := repositories.NewBalanceActionsRepository(dbPool)
userOrderRepository := repositories.NewUserOrderRepository(dbPool)

userService := services.NewUserService(userRepository, balanceActionsRepository)
ordersService := services.NewOrdersService(userOrderRepository)
withdrawalService := services.NewWithdrawalsService(balanceActionsRepository)

authHandler := handlers.NewAuthHandler(userService)
balanceHandler := handlers.NewBalanceHandler(userService, withdrawalService)
ordersHandler := handlers.NewOrdersHandler(ordersService)

workersCtx, workersStopCtx := context.WithCancel(context.Background())

orderAccrualCheckingWorker := workers.NewOrderAccrualCheckingWorker(
userOrderRepository,
appConfig.AccrualSystemAddress,
)
go orderAccrualCheckingWorker.Start(workersCtx)

server := &http.Server{
Addr: appConfig.RunAddress,
Handler: makeRouter(appConfig, authHandler, balanceHandler, ordersHandler),
}

log.Println("Gophermart server is running on", appConfig.RunAddress)

go func() {
err = server.ListenAndServe()

if err != nil && err != http.ErrServerClosed {
log.Fatal(err)
}
}()

sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)

<-sig

log.Println("start graceful shutdown...")

shutdownCtx, shutdownCtxCancel := context.WithTimeout(context.Background(), 30*time.Second)
defer shutdownCtxCancel()

go func() {
<-shutdownCtx.Done()
if shutdownCtx.Err() == context.DeadlineExceeded {
log.Fatal("graceful shutdown timed out... forcing exit")
}
}()

err = server.Shutdown(shutdownCtx)
if err != nil {
log.Fatal(err)
}

workersStopCtx()

log.Println("graceful shutdown server successfully")
}

// @title Gophermart Loyalty Service
// @version 1.0
// @description Gophermart Loyalty Service responsible for saving user orders, saving user balance and withdraw balance
// @BasePath /api/user
// @securityDefinitions.apikey BearerAuth
// @in header
// @name Authorization
func makeRouter(
appConfig *config.GophermartConfig,
authHandler *handlers.AuthHandler,
balanceHandler *handlers.BalanceHandler,
ordersHandler *handlers.OrdersHandler,
) http.Handler {
router := chi.NewRouter()

router.Use(middleware.Recoverer)

router.Group(func(publicRouter chi.Router) {
publicRouter.Use(middleware.Logger)
publicRouter.Use(middleware.Compress(5, "gzip"))

publicRouter.Post("/register", authHandler.Register)
publicRouter.Post("/login", authHandler.Login)
})

router.Group(func(authRouter chi.Router) {
authRouter.Use(middlewares.AuthMiddleware)
authRouter.Use(middleware.Logger)
authRouter.Use(middleware.Compress(5, "gzip"))

authRouter.Get("/orders", ordersHandler.GetOrders)
authRouter.Post("/orders", ordersHandler.RegisterOrder)

authRouter.Get("/balance", balanceHandler.GetUserBalance)
authRouter.Post("/balance/withdraw", balanceHandler.WithdrawBalance)
authRouter.Get("/withdrawals", balanceHandler.GetWithdrawalHistory)
})

router.Mount("/api/user", router)

router.Get("/swagger/*", httpSwagger.Handler(
httpSwagger.URL(fmt.Sprintf("http://%s/swagger/doc.json", appConfig.RunAddress)),
))

return router
}

0 comments on commit 04415f7

Please sign in to comment.