(Feat): Initial Commit
Some checks failed
Build & Test / build-test (push) Has been cancelled
Build & Test / swagger-codegen-cli (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled

This commit is contained in:
2026-07-03 19:41:31 +05:30
commit 7e940c83a7
461 changed files with 45002 additions and 0 deletions

154
internal/api/server.go Normal file
View File

@@ -0,0 +1,154 @@
package api
import (
"context"
"database/sql"
"errors"
"fmt"
"net/http"
"allaboutapps.dev/aw/go-starter/internal/config"
"allaboutapps.dev/aw/go-starter/internal/data/dto"
"allaboutapps.dev/aw/go-starter/internal/data/local"
"allaboutapps.dev/aw/go-starter/internal/i18n"
"allaboutapps.dev/aw/go-starter/internal/mailer"
"allaboutapps.dev/aw/go-starter/internal/metrics"
"allaboutapps.dev/aw/go-starter/internal/push"
"allaboutapps.dev/aw/go-starter/internal/util"
"github.com/dropbox/godropbox/time2"
"github.com/labstack/echo/v4"
"github.com/rs/zerolog/log"
// Import postgres driver for database/sql package
_ "github.com/lib/pq"
)
type Router struct {
Routes []*echo.Route
Root *echo.Group
Management *echo.Group
APIV1Auth *echo.Group
APIV1Push *echo.Group
WellKnown *echo.Group
}
// Server is a central struct keeping all the dependencies.
// It is initialized with wire, which handles making the new instances of the components
// in the right order. To add a new component, 3 steps are required:
// - declaring it in this struct
// - adding a provider function in providers.go
// - adding the provider's function name to the arguments of wire.Build() in wire.go
//
// Components labeled as `wire:"-"` will be skipped and have to be initialized after the InitNewServer* call.
// For more information about wire refer to https://pkg.go.dev/github.com/google/wire
type Server struct {
// skip wire:
// -> initialized with router.Init(s) function
Echo *echo.Echo `wire:"-"`
Router *Router `wire:"-"`
Config config.Server
DB *sql.DB
Mailer *mailer.Mailer
Push *push.Service
I18n *i18n.Service
Clock time2.Clock
Auth AuthService
Local *local.Service
Metrics *metrics.Service
}
// newServerWithComponents is used by wire to initialize the server components.
// Components not listed here won't be handled by wire and should be initialized separately.
// Components which shouldn't be handled must be labeled `wire:"-"` in Server struct.
func newServerWithComponents(
cfg config.Server,
db *sql.DB,
mail *mailer.Mailer,
pusher *push.Service,
i18n *i18n.Service,
clock time2.Clock,
auth AuthService,
local *local.Service,
metrics *metrics.Service,
) *Server {
return &Server{
Config: cfg,
DB: db,
Mailer: mail,
Push: pusher,
I18n: i18n,
Clock: clock,
Auth: auth,
Local: local,
Metrics: metrics,
}
}
type AuthService interface {
GetAppUserProfile(ctx context.Context, id string) (*dto.AppUserProfile, error)
InitPasswordReset(ctx context.Context, request dto.InitPasswordResetRequest) (dto.InitPasswordResetResult, error)
Login(ctx context.Context, request dto.LoginRequest) (dto.LoginResult, error)
Logout(ctx context.Context, request dto.LogoutRequest) error
Refresh(ctx context.Context, request dto.RefreshRequest) (dto.LoginResult, error)
Register(ctx context.Context, request dto.RegisterRequest) (dto.RegisterResult, error)
CompleteRegister(ctx context.Context, request dto.CompleteRegisterRequest) (dto.LoginResult, error)
DeleteUserAccount(ctx context.Context, request dto.DeleteUserAccountRequest) error
ResetPassword(ctx context.Context, request dto.ResetPasswordRequest) (dto.LoginResult, error)
UpdatePassword(ctx context.Context, request dto.UpdatePasswordRequest) (dto.LoginResult, error)
}
func NewServer(config config.Server) *Server {
s := &Server{
Config: config,
}
return s
}
func (s *Server) Ready() bool {
if err := util.IsStructInitialized(s); err != nil {
log.Debug().Err(err).Msg("Server is not fully initialized")
return false
}
return true
}
func (s *Server) Start() error {
if !s.Ready() {
return errors.New("server is not ready")
}
if err := s.Echo.Start(s.Config.Echo.ListenAddress); err != nil {
return fmt.Errorf("failed to start echo server: %w", err)
}
return nil
}
func (s *Server) Shutdown(ctx context.Context) []error {
log.Warn().Msg("Shutting down server")
var errs []error
if s.DB != nil {
log.Debug().Msg("Closing database connection")
if err := s.DB.Close(); err != nil && !errors.Is(err, sql.ErrConnDone) {
log.Error().Err(err).Msg("Failed to close database connection")
errs = append(errs, err)
}
}
if s.Echo != nil {
log.Debug().Msg("Shutting down echo server")
if err := s.Echo.Shutdown(ctx); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Error().Err(err).Msg("Failed to shutdown echo server")
errs = append(errs, err)
}
}
return errs
}