Skip to content

Commit

Permalink
Refactor config setup and add background tasks support
Browse files Browse the repository at this point in the history
  • Loading branch information
jessicatarra committed Dec 5, 2023
1 parent c17f715 commit 6ca0596
Show file tree
Hide file tree
Showing 13 changed files with 175 additions and 177 deletions.
5 changes: 3 additions & 2 deletions cmd/api/healthcheck.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"github.com/jessicatarra/greenlight/internal/config"
"net/http"
)

Expand All @@ -9,8 +10,8 @@ func (app *application) healthcheckHandler(writer http.ResponseWriter, request *
"status": "available",
"system_info": map[string]string{
"status": "available",
"environment": app.config.env,
"version": version,
"environment": app.config.Env,
"version": config.Version,
},
}
err := app.writeJSON(writer, http.StatusOK, env, nil)
Expand Down
15 changes: 0 additions & 15 deletions cmd/api/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,18 +123,3 @@ func (app *application) readInt(qs url.Values, key string, defaultValue int, v *

return i
}

func (app *application) background(fn func()) {
app.wg.Add(1)

go func() {
defer app.wg.Done()
defer func() {
if err := recover(); err != nil {
app.logger.PrintError(fmt.Errorf("%s", err), nil)
}
}()

fn()
}()
}
80 changes: 9 additions & 71 deletions cmd/api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,18 @@ package main

import (
"expvar"
"flag"
"fmt"
"github.com/jessicatarra/greenlight/internal/config"
"github.com/jessicatarra/greenlight/internal/database"
"github.com/jessicatarra/greenlight/internal/jsonlog"
"github.com/jessicatarra/greenlight/internal/mailer"
"os"
"runtime"
"strconv"
"strings"
"sync"
"time"
)

var (
version string
port string
env string
)

type config struct {
port int
env string
db struct {
dsn string
maxOpenConns int
maxIdleConns int
maxIdleTime string
}
smtp struct {
host string
port int
username string
password string
sender string
}
cors struct {
trustedOrigins []string
}
jwt struct {
secret string
}
}

type application struct {
config config
config config.Config
logger *jsonlog.Logger
models database.Models
mailer mailer.Mailer
Expand All @@ -63,50 +30,21 @@ type application struct {
// @in header
// @name Authorization
func main() {
var cfg config

intPort, _ := strconv.Atoi(port)
flag.IntVar(&cfg.port, "port", intPort, "API server port")
flag.StringVar(&cfg.env, "env", env, "Environment (development|staging|production)")
flag.StringVar(&cfg.db.dsn, "db-dsn", os.Getenv(
"DATABASE_URL"), "PostgreSQL DSN")
flag.IntVar(&cfg.db.maxOpenConns, "db-max-open-conns", 25, "PostgreSQL max open connections")
flag.IntVar(&cfg.db.maxIdleConns, "db-max-idle-conns", 25, "PostgreSQL max idle connections")
flag.StringVar(&cfg.db.maxIdleTime, "db-max-idle-time", "15m", "PostgreSQL max connection idle time")

smtpPort, _ := strconv.Atoi(os.Getenv("SMTP_PORT"))

flag.StringVar(&cfg.smtp.host, "smtp-host", os.Getenv("SMTP_HOST"), "SMTP host")
flag.IntVar(&cfg.smtp.port, "smtp-port", smtpPort, "SMTP port")
flag.StringVar(&cfg.smtp.username, "smtp-username", os.Getenv("SMTP_USERNAME"), "SMTP username")
flag.StringVar(&cfg.smtp.password, "smtp-password", os.Getenv("SMTP_PASSWORD"), "SMTP password")
flag.StringVar(&cfg.smtp.sender, "smtp-sender", os.Getenv("SMTP_SENDER"), "SMTP sender")

flag.Func("cors-trusted-origins", "Trusted CORS origins (space separated)", func(val string) error {
cfg.cors.trustedOrigins = strings.Fields(val)
return nil
})

flag.StringVar(&cfg.jwt.secret, "jwt-secret", os.Getenv("JWT_SECRET"), "JWT secret")

displayVersion := flag.Bool("version", false, "Display version and exit")

flag.Parse()
logger := jsonlog.New(os.Stdout, jsonlog.LevelInfo)

if *displayVersion {
fmt.Printf("Version:\t%s\n", version)
cfg, err := config.Init()
if err != nil {
logger.PrintFatal(err, nil)
}

logger := jsonlog.New(os.Stdout, jsonlog.LevelInfo)

db, err := database.New(cfg.db.dsn, cfg.db.maxOpenConns, cfg.db.maxIdleConns, cfg.db.maxIdleTime, true)
db, err := database.New(cfg.DB.Dsn, cfg.DB.MaxOpenConns, cfg.DB.MaxIdleConns, cfg.DB.MaxIdleTime, true)
if err != nil {
logger.PrintFatal(err, nil)
}
defer db.Close()
logger.PrintInfo("database connection pool established", nil)

expvar.NewString("version").Set(version)
expvar.NewString("version").Set(config.Version)

expvar.Publish("goroutines", expvar.Func(func() interface{} {
return runtime.NumGoroutine()
Expand All @@ -124,7 +62,7 @@ func main() {
config: cfg,
logger: logger,
models: database.NewModels(db),
mailer: mailer.New(cfg.smtp.host, cfg.smtp.port, cfg.smtp.username, cfg.smtp.password, cfg.smtp.sender),
mailer: mailer.New(cfg.Smtp.Host, cfg.Smtp.Port, cfg.Smtp.Username, cfg.Smtp.Password, cfg.Smtp.Sender),
}

err = app.serve(db)
Expand Down
8 changes: 4 additions & 4 deletions cmd/api/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func (app *application) authenticate(next http.Handler) http.Handler {
}
token := headerParts[1]

claims, err := jwt.HMACCheck([]byte(token), []byte(app.config.jwt.secret))
claims, err := jwt.HMACCheck([]byte(token), []byte(app.config.Jwt.Secret))
if err != nil {
app.invalidAuthenticationTokenResponse(writer, request)
return
Expand Down Expand Up @@ -157,9 +157,9 @@ func (app *application) enableCORS(next http.Handler) http.Handler {

origin := request.Header.Get("Origin")

if origin != "" && len(app.config.cors.trustedOrigins) != 0 {
for i := range app.config.cors.trustedOrigins {
if origin == app.config.cors.trustedOrigins[i] {
if origin != "" && len(app.config.Cors.TrustedOrigins) != 0 {
for i := range app.config.Cors.TrustedOrigins {
if origin == app.config.Cors.TrustedOrigins[i] {
writer.Header().Set("Access-Control-Allow-Origin", origin)

if request.Method == http.MethodOptions && request.Header.Get("Access-Control-Request-Method") != "" {
Expand Down
2 changes: 1 addition & 1 deletion cmd/api/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func (app *application) routes(db *sql.DB) http.Handler {
router.HandlerFunc(http.MethodPatch, "/v1/movies/:id", app.requirePermission("movies:write", app.updateMovieHandler))
router.HandlerFunc(http.MethodDelete, "/v1/movies/:id", app.requirePermission("movies:write", app.deleteMovieHandler))

_authService.RegisterHandlers(_authApp.NewApp(_authRepo.NewUserRepo(db), _authRepo.NewTokenRepo(db)), router)
_authService.RegisterHandlers(_authApp.NewApp(_authRepo.NewUserRepo(db), _authRepo.NewTokenRepo(db), app.logger, &app.wg, app.config), router)
router.HandlerFunc(http.MethodPut, "/v1/users/activated", app.activateUserHandler)
router.HandlerFunc(http.MethodPost, "/v1/tokens/authentication", app.createAuthenticationTokenHandler)

Expand Down
4 changes: 2 additions & 2 deletions cmd/api/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (

func (app *application) serve(db *sql.DB) error {
srv := &http.Server{
Addr: fmt.Sprintf(":%d", app.config.port),
Addr: fmt.Sprintf(":%d", app.config.Port),
Handler: app.routes(db),
IdleTimeout: time.Minute,
ReadTimeout: 10 * time.Second,
Expand Down Expand Up @@ -50,7 +50,7 @@ func (app *application) serve(db *sql.DB) error {

app.logger.PrintInfo("starting server", map[string]string{
"addr": srv.Addr,
"env": app.config.env,
"env": app.config.Env,
})

err := srv.ListenAndServe()
Expand Down
2 changes: 1 addition & 1 deletion cmd/api/tokens.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func (app *application) createAuthenticationTokenHandler(writer http.ResponseWri
claims.Audiences = []string{"greenlight.tarralva.com"}
claims.Audiences = []string{"greenlight.tarralva.com"}

jwtBytes, err := claims.HMACSign(jwt.HS256, []byte(app.config.jwt.secret))
jwtBytes, err := claims.HMACSign(jwt.HS256, []byte(app.config.Jwt.Secret))
if err != nil {
app.serverErrorResponse(writer, request, err)
return
Expand Down
6 changes: 0 additions & 6 deletions cmd/api/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,6 @@ import (
"net/http"
)

type createUserRequest struct {
Name string `json:"name"`
Email string `json:"email"`
Password string `json:"password"`
}

// @Summary Activate User
// @Description Activates a user account using a token that was previously sent when successfully register a new user
// @Tags Users
Expand Down
68 changes: 33 additions & 35 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,68 +9,66 @@ import (
)

var (
version string
Version string
port string
env string
)

type Config struct {
port int
env string
db struct {
dsn string
maxOpenConns int
maxIdleConns int
maxIdleTime string
Port int
Env string
DB struct {
Dsn string
MaxOpenConns int
MaxIdleConns int
MaxIdleTime string
}
smtp struct {
host string
port int
username string
password string
sender string
Smtp struct {
Host string
Port int
Username string
Password string
Sender string
}
cors struct {
trustedOrigins []string
Cors struct {
TrustedOrigins []string
}
jwt struct {
secret string
Jwt struct {
Secret string
}
}

func Init() (cfg *Config, err error) {
cfg = &Config{}

func Init() (cfg Config, err error) {
intPort, _ := strconv.Atoi(port)
flag.IntVar(&cfg.port, "port", intPort, "API server port")
flag.StringVar(&cfg.env, "env", env, "Environment (development|staging|production)")
flag.StringVar(&cfg.db.dsn, "db-dsn", os.Getenv(
flag.IntVar(&cfg.Port, "port", intPort, "API server port")
flag.StringVar(&cfg.Env, "env", env, "Environment (development|staging|production)")
flag.StringVar(&cfg.DB.Dsn, "db-dsn", os.Getenv(
"DATABASE_URL"), "PostgreSQL DSN")
flag.IntVar(&cfg.db.maxOpenConns, "db-max-open-conns", 25, "PostgreSQL max open connections")
flag.IntVar(&cfg.db.maxIdleConns, "db-max-idle-conns", 25, "PostgreSQL max idle connections")
flag.StringVar(&cfg.db.maxIdleTime, "db-max-idle-time", "15m", "PostgreSQL max connection idle time")
flag.IntVar(&cfg.DB.MaxOpenConns, "db-max-open-conns", 25, "PostgreSQL max open connections")
flag.IntVar(&cfg.DB.MaxIdleConns, "db-max-idle-conns", 25, "PostgreSQL max idle connections")
flag.StringVar(&cfg.DB.MaxIdleTime, "db-max-idle-time", "15m", "PostgreSQL max connection idle time")

smtpPort, _ := strconv.Atoi(os.Getenv("SMTP_PORT"))

flag.StringVar(&cfg.smtp.host, "smtp-host", os.Getenv("SMTP_HOST"), "SMTP host")
flag.IntVar(&cfg.smtp.port, "smtp-port", smtpPort, "SMTP port")
flag.StringVar(&cfg.smtp.username, "smtp-username", os.Getenv("SMTP_USERNAME"), "SMTP username")
flag.StringVar(&cfg.smtp.password, "smtp-password", os.Getenv("SMTP_PASSWORD"), "SMTP password")
flag.StringVar(&cfg.smtp.sender, "smtp-sender", os.Getenv("SMTP_SENDER"), "SMTP sender")
flag.StringVar(&cfg.Smtp.Host, "smtp-host", os.Getenv("SMTP_HOST"), "SMTP host")
flag.IntVar(&cfg.Smtp.Port, "smtp-port", smtpPort, "SMTP port")
flag.StringVar(&cfg.Smtp.Username, "smtp-username", os.Getenv("SMTP_USERNAME"), "SMTP username")
flag.StringVar(&cfg.Smtp.Password, "smtp-password", os.Getenv("SMTP_PASSWORD"), "SMTP password")
flag.StringVar(&cfg.Smtp.Sender, "smtp-sender", os.Getenv("SMTP_SENDER"), "SMTP sender")

flag.Func("cors-trusted-origins", "Trusted CORS origins (space separated)", func(val string) error {
cfg.cors.trustedOrigins = strings.Fields(val)
cfg.Cors.TrustedOrigins = strings.Fields(val)
return nil
})

flag.StringVar(&cfg.jwt.secret, "jwt-secret", os.Getenv("JWT_SECRET"), "JWT secret")
flag.StringVar(&cfg.Jwt.Secret, "jwt-secret", os.Getenv("JWT_SECRET"), "JWT secret")

displayVersion := flag.Bool("version", false, "Display version and exit")

flag.Parse()

if *displayVersion {
fmt.Printf("Version:\t%s\n", version)
fmt.Printf("Version:\t%s\n", Version)
}

return cfg, nil
Expand Down
Loading

0 comments on commit 6ca0596

Please sign in to comment.