refac: rethought the complete workflow and deployement flow ; docs etc.
This commit is contained in:
1 parent
4a6209a8db
commit
09bd5afa4a
26 files changed
+800
-334
No files matched your search
+109
-37
@@ -3,67 +3,139 @@ package main
|
||||
import (
|
||||
"RenewCMS/api"
|
||||
validator "RenewCMS/api/pkg/validator"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
var version = "dev"
|
||||
|
||||
const (
|
||||
readHeaderTimeout = 10 * time.Second
|
||||
readTimeout = 30 * time.Second
|
||||
writeTimeout = 60 * time.Second
|
||||
idleTimeout = 120 * time.Second
|
||||
shutdownTimeout = 10 * time.Second
|
||||
)
|
||||
|
||||
var possibleEnvFileLocations = []string{".env", "../.env"}
|
||||
var envVarsToLoad = []string{
|
||||
"HOST",
|
||||
"PORT",
|
||||
|
||||
var requiredEnvVars = []string{
|
||||
"PUBLIC_URL",
|
||||
"JWT_SECRET",
|
||||
"ENVIRONMENT",
|
||||
"CORS_ALLOWED_ORIGINS",
|
||||
"DB_FILE",
|
||||
"UPLOAD_DIR",
|
||||
"SMTP_EMAIL",
|
||||
"SMTP_PASSWORD",
|
||||
"SMTP_HOST",
|
||||
"SMTP_PORT",
|
||||
}
|
||||
|
||||
var envDefaults = map[string]string{
|
||||
"ENVIRONMENT": "production",
|
||||
"PORT": "8080",
|
||||
"DB_FILE": "./data/renewcms.db",
|
||||
"UPLOAD_DIR": "./data/uploads",
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := run(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func run() error {
|
||||
initEnvVariables()
|
||||
|
||||
container, closeDb := api.InitContainer()
|
||||
defer closeDatabase(closeDb)
|
||||
validator.InitValidator()
|
||||
|
||||
server := newServer(api.InitRoutes(container))
|
||||
return serveUntilStopped(server)
|
||||
}
|
||||
|
||||
func initEnvVariables() {
|
||||
var err error
|
||||
loadEnvFile()
|
||||
applyEnvDefaults()
|
||||
ensureRequiredEnvVars()
|
||||
}
|
||||
|
||||
func loadEnvFile() {
|
||||
for _, envLocation := range possibleEnvFileLocations {
|
||||
err = godotenv.Load(envLocation)
|
||||
if err == nil {
|
||||
break
|
||||
if godotenv.Load(envLocation) == nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Println("WARNING: Could not load any .env file")
|
||||
}
|
||||
log.Println("WARNING: Could not load any .env file")
|
||||
}
|
||||
|
||||
for _, envVar := range envVarsToLoad {
|
||||
if _, ok := os.LookupEnv(envVar); !ok {
|
||||
func applyEnvDefaults() {
|
||||
for envVar, value := range envDefaults {
|
||||
if _, isSet := os.LookupEnv(envVar); !isSet {
|
||||
_ = os.Setenv(envVar, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ensureRequiredEnvVars() {
|
||||
for _, envVar := range requiredEnvVars {
|
||||
if _, isSet := os.LookupEnv(envVar); !isSet {
|
||||
panic(fmt.Sprintf("Environment variable %s is not set", envVar))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func initServer() *chi.Mux {
|
||||
initEnvVariables()
|
||||
|
||||
container := api.InitContainer()
|
||||
validator.InitValidator()
|
||||
|
||||
return api.InitRoutes(container)
|
||||
}
|
||||
|
||||
func startServer(router *chi.Mux) error {
|
||||
fmt.Println("Server starting on http://" + os.Getenv("HOST"))
|
||||
err := http.ListenAndServe(":"+os.Getenv("PORT"), router)
|
||||
return err
|
||||
}
|
||||
|
||||
func main() {
|
||||
router := initServer()
|
||||
err := startServer(router)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
func closeDatabase(closeDb func() error) {
|
||||
if err := closeDb(); err != nil {
|
||||
log.Println("error closing database:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func newServer(handler http.Handler) *http.Server {
|
||||
return &http.Server{
|
||||
Addr: ":" + os.Getenv("PORT"),
|
||||
Handler: handler,
|
||||
ReadHeaderTimeout: readHeaderTimeout,
|
||||
ReadTimeout: readTimeout,
|
||||
WriteTimeout: writeTimeout,
|
||||
IdleTimeout: idleTimeout,
|
||||
}
|
||||
}
|
||||
|
||||
func serveUntilStopped(server *http.Server) error {
|
||||
stopSignal, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||
defer stop()
|
||||
|
||||
serverErr := make(chan error, 1)
|
||||
go listen(server, serverErr)
|
||||
|
||||
select {
|
||||
case err := <-serverErr:
|
||||
return err
|
||||
case <-stopSignal.Done():
|
||||
return shutdown(server)
|
||||
}
|
||||
}
|
||||
|
||||
func listen(server *http.Server, serverErr chan<- error) {
|
||||
log.Printf("RenewCMS %s (%s) listening on %s, public URL %s", version, os.Getenv("ENVIRONMENT"), server.Addr, os.Getenv("PUBLIC_URL"))
|
||||
err := server.ListenAndServe()
|
||||
if errors.Is(err, http.ErrServerClosed) {
|
||||
err = nil
|
||||
}
|
||||
serverErr <- err
|
||||
}
|
||||
|
||||
func shutdown(server *http.Server) error {
|
||||
log.Println("shutting down...")
|
||||
ctx, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
|
||||
defer cancel()
|
||||
return server.Shutdown(ctx)
|
||||
}
|
||||
Reference in new issue
Block a user