From bb21743fc89236834e586d5edc2d9c2806de85c0 Mon Sep 17 00:00:00 2001 From: lafetz Date: Thu, 27 Mar 2025 23:55:30 +0300 Subject: [PATCH] set up structure --- cmd/main.go | 28 +++++++- go.mod | 20 +++++- go.sum | 37 ++++++++-- internal/config/config.go | 42 ++++++++++++ internal/logger/logger.go | 36 ++++++++++ internal/web_server/app.go | 27 ++++++++ internal/web_server/app_routes.go | 5 ++ internal/web_server/server.go | 76 --------------------- internal/web_server/validator/validatord.go | 1 + 9 files changed, 189 insertions(+), 83 deletions(-) create mode 100644 internal/config/config.go create mode 100644 internal/logger/logger.go create mode 100644 internal/web_server/app.go create mode 100644 internal/web_server/app_routes.go delete mode 100644 internal/web_server/server.go create mode 100644 internal/web_server/validator/validatord.go diff --git a/cmd/main.go b/cmd/main.go index 7905807..7899d54 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -1,5 +1,31 @@ package main -func main() { +import ( + "fmt" + "log/slog" + "os" + "github.com/SamuelTariku/FortuneBet-Backend/internal/config" + "github.com/SamuelTariku/FortuneBet-Backend/internal/repository" + "github.com/joho/godotenv" +) + +func main() { + err := godotenv.Load() + if err != nil { + slog.Error(err.Error()) + os.Exit(1) + } + cfg, err := config.NewConfig() + if err != nil { + slog.Error(err.Error()) + os.Exit(1) + } + db, _, err := repository.OpenDB(cfg.DbUrl) + if err != nil { + fmt.Print(err) + os.Exit(1) + } + store := repository.NewStore(db) + fmt.Println(store) } diff --git a/go.mod b/go.mod index 70aa95d..dc1b2fc 100644 --- a/go.mod +++ b/go.mod @@ -2,13 +2,29 @@ module github.com/SamuelTariku/FortuneBet-Backend go 1.24.1 -require github.com/jackc/pgx/v5 v5.7.4 +require ( + github.com/gofiber/fiber/v2 v2.52.6 + github.com/jackc/pgx/v5 v5.7.4 + github.com/joho/godotenv v1.5.1 +) require ( + github.com/andybalholm/brotli v1.1.0 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect - golang.org/x/crypto v0.31.0 // indirect + github.com/klauspost/compress v1.17.9 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/stretchr/testify v1.8.4 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.51.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + golang.org/x/crypto v0.32.0 // indirect golang.org/x/sync v0.10.0 // indirect + golang.org/x/sys v0.29.0 // indirect golang.org/x/text v0.21.0 // indirect ) diff --git a/go.sum b/go.sum index fa0f7db..7910e91 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,12 @@ +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gofiber/fiber/v2 v2.52.6 h1:Rfp+ILPiYSvvVuIPvxrBns+HJp8qGLDnLJawAu27XVI= +github.com/gofiber/fiber/v2 v2.52.6/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= +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/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= @@ -9,17 +15,40 @@ github.com/jackc/pgx/v5 v5.7.4 h1:9wKznZrhWa2QiHL+NjTSPP6yjl3451BX3imWDnokYlg= github.com/jackc/pgx/v5 v5.7.4/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= +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= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100644 index 0000000..0d53448 --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,42 @@ +package config + +import ( + "errors" + "os" + "strconv" +) + +var ( + ErrInvalidDbUrl = errors.New("db url is invalid") + ErrInvalidPort = errors.New("port number is invalid") +) + +type Config struct { + Port int + DbUrl string +} + +func NewConfig() (*Config, error) { + config := &Config{} + if err := config.loadEnv(); err != nil { + return nil, err + } + return config, nil +} +func (c *Config) loadEnv() error { + + portStr := os.Getenv("PORT") + port, err := strconv.Atoi(portStr) + if err != nil { + return ErrInvalidPort + } + c.Port = port + + dbUrl := os.Getenv("DB_URL") + if dbUrl == "" { + return ErrInvalidDbUrl + } + c.DbUrl = dbUrl + + return nil +} diff --git a/internal/logger/logger.go b/internal/logger/logger.go new file mode 100644 index 0000000..2c7035f --- /dev/null +++ b/internal/logger/logger.go @@ -0,0 +1,36 @@ +package customlogger + +import ( + "log/slog" + "os" +) + +var LogLevels = map[string]slog.Level{ + "debug": slog.LevelDebug, + "info": slog.LevelInfo, + "warn": slog.LevelWarn, + "error": slog.LevelError, +} + +func NewLogger(env string, lvl slog.Level, version string) *slog.Logger { + var logHandler slog.Handler + switch env { + case "development": + logHandler = slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ + Level: lvl, + }) + default: + logHandler = slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: lvl, + }) + } + + logger := slog.New(logHandler).With(slog.Group( + "service_info", + slog.String("env", env), + slog.String("version", version), + ), + ) + + return logger +} diff --git a/internal/web_server/app.go b/internal/web_server/app.go new file mode 100644 index 0000000..36a543c --- /dev/null +++ b/internal/web_server/app.go @@ -0,0 +1,27 @@ +package httpserver + +import ( + "fmt" + + "github.com/gofiber/fiber/v2" +) + +type App struct { + fiber *fiber.App + port int +} + +func NewApp(port int) *App { + s := &App{ + + port: port, + } + + s.initAppRoutes() + + return s +} + +func (a *App) Run() error { + return a.fiber.Listen(fmt.Sprintf(":%d", a.port)) +} diff --git a/internal/web_server/app_routes.go b/internal/web_server/app_routes.go new file mode 100644 index 0000000..8388c84 --- /dev/null +++ b/internal/web_server/app_routes.go @@ -0,0 +1,5 @@ +package httpserver + +func (a *App) initAppRoutes() { + // a.fiber.Group("/users", users.CreateAccount(a.userAPI)) +} diff --git a/internal/web_server/server.go b/internal/web_server/server.go deleted file mode 100644 index 944f397..0000000 --- a/internal/web_server/server.go +++ /dev/null @@ -1,76 +0,0 @@ -package httpserver - -import ( - "context" - "errors" - "fmt" - "log/slog" - "net/http" - "os" - "os/signal" - "strconv" - "syscall" - "time" -) - -type App struct { - port int - Router *http.ServeMux - logger *slog.Logger - notificationSecret string -} - -func NewApp( - port int, logger *slog.Logger, - notificationSecret string, - -) *App { - a := &App{ - Router: http.NewServeMux(), - logger: logger, - port: port, - notificationSecret: notificationSecret, - } - a.initAppRoutes() - return a -} -func (a *App) Run() error { - - srv := &http.Server{ - Addr: fmt.Sprintf(":%s", strconv.Itoa(a.port)), - Handler: a.Router, - IdleTimeout: time.Minute, - ReadTimeout: 10 * time.Second, - WriteTimeout: 30 * time.Second, - } - - shutdownError := make(chan error) - go func() { - quit := make(chan os.Signal, 1) - signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) - - <-quit - - a.logger.Info("shutting down server") - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - - shutdownError <- srv.Shutdown(ctx) - }() - err := srv.ListenAndServe() - - if !errors.Is(err, http.ErrServerClosed) { - return err - } - - err = <-shutdownError - if err != nil { - return err - } - a.logger.Info("server stopped") - return nil -} - -func (a *App) initAppRoutes() { - // a.Router.HandleFunc("/users",) -} diff --git a/internal/web_server/validator/validatord.go b/internal/web_server/validator/validatord.go new file mode 100644 index 0000000..47f2da9 --- /dev/null +++ b/internal/web_server/validator/validatord.go @@ -0,0 +1 @@ +package validator