feat: made it standard openapi and removed comments
This commit is contained in:
85
main.go
85
main.go
@@ -1,24 +1,8 @@
|
|||||||
// main.go — auth-gate entry point
|
|
||||||
//
|
|
||||||
// This file wires together configuration loading, the HTTP server, and the
|
|
||||||
// background processes (permanent-whitelist file watcher, temporary-whitelist
|
|
||||||
// cleanup).
|
|
||||||
//
|
|
||||||
// Why this structure?
|
|
||||||
//
|
|
||||||
// - Main keeps the wiring thin. Each component (config, auth, cleanup, watcher)
|
|
||||||
// owns its own logic so we can test and reason about them independently.
|
|
||||||
// - We don't embed the HTTP server logic inside main; instead main calls
|
|
||||||
// createAuthHandler(config) and server.Serve(). This makes the handler
|
|
||||||
// functionally pure (aside from config reads) and easier to mock.
|
|
||||||
// - The background goroutines are started explicitly so we can stop them on
|
|
||||||
// SIGTERM without leaking resources.
|
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"log"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
@@ -28,48 +12,59 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
cfg := loadConfig()
|
cfg := loadConfig()
|
||||||
|
slog.SetDefault(slog.New(slog.NewTextHandler(os.Stdout, nil)))
|
||||||
|
|
||||||
// Load the permanent whitelist from disk once at startup.
|
db, err := initDB(cfg.DBPath)
|
||||||
// We reload it periodically via watcher (see watcher.go).
|
if err != nil {
|
||||||
loadPermanentWhitelist(cfg.PermanentWhitelistFile)
|
slog.Error("failed to init database", "error", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
// Start the background watcher that reloads the permanent whitelist file.
|
perm := newPermanentWhitelist()
|
||||||
// It only reloads when the file actually changes (mtime comparison), so
|
tw := newTempWhitelist()
|
||||||
// frequent touch-operations don't cause unnecessary restarts.
|
|
||||||
w := newPermanentWhitelistWatcher(cfg.PermanentWhitelistFile, cfg.WatchInterval, cfg.PermanentWhitelist)
|
|
||||||
w.start()
|
|
||||||
|
|
||||||
// Start the cleanup goroutine that expires temporary whitelisted IPs
|
watcher := newPermanentWhitelistWatcher(cfg.PermanentWhitelistFile, cfg.WatchInterval, perm)
|
||||||
// whose TTL has elapsed. It runs every cfg.CleanupInterval.
|
watcher.start()
|
||||||
go cleanupLoop(cfg.TemporaryWhitelist, cfg.CleanupInterval)
|
|
||||||
|
go cleanupLoop(tw, cfg.CleanupInterval)
|
||||||
|
|
||||||
|
server := newAuthServer(cfg, tw, perm, db)
|
||||||
|
|
||||||
// Build the HTTP server.
|
|
||||||
addr := ":" + cfg.Port
|
addr := ":" + cfg.Port
|
||||||
server := newAuthServer(cfg, addr)
|
|
||||||
|
|
||||||
// Start serving in a goroutine so we can do graceful shutdown.
|
|
||||||
go func() {
|
go func() {
|
||||||
log.Printf("auth-gate listening on %s", addr)
|
slog.Info("starting server", "addr", addr)
|
||||||
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||||
log.Fatalf("server error: %v", err)
|
slog.Error("server error", "error", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Graceful shutdown on SIGTERM / SIGINT.
|
|
||||||
//
|
|
||||||
// We wait for a signal, then call server.Shutdown(ctx) which:
|
|
||||||
// 1. Stops accepting new connections
|
|
||||||
// 2. Closes idle connections
|
|
||||||
// 3. Waits for in-flight requests to complete (up to 30s)
|
|
||||||
//
|
|
||||||
// This is important for Docker deployments: without it the container
|
|
||||||
// would be killed mid-request and clients would see connection errors.
|
|
||||||
quit := make(chan os.Signal, 1)
|
quit := make(chan os.Signal, 1)
|
||||||
signal.Notify(quit, syscall.SIGTERM, syscall.SIGINT)
|
signal.Notify(quit, syscall.SIGTERM, syscall.SIGINT)
|
||||||
<-quit
|
<-quit
|
||||||
|
|
||||||
log.Println("shutting down...")
|
slog.Info("shutting down...")
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
server.Shutdown(ctx)
|
if err := server.Shutdown(ctx); err != nil {
|
||||||
|
slog.Error("shutdown error", "error", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAuthServer(cfg Config, tw *tempWhitelist, perm *PermanentWhitelist, db *sql.DB) *http.Server {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/auth", authHandler(cfg, tw, perm))
|
||||||
|
mux.HandleFunc("/api/whitelist/temp", tw.whitelistTempHandler(cfg, db))
|
||||||
|
mux.HandleFunc("/api/whitelist", tw.whitelistListHandler(cfg))
|
||||||
|
mux.HandleFunc("/api/whitelist/{ip}", tw.whitelistDeleteHandler(cfg, db))
|
||||||
|
mux.HandleFunc("/api/logs", logsHandler(cfg, db))
|
||||||
|
mux.HandleFunc("/status", statusHandler)
|
||||||
|
|
||||||
|
return &http.Server{
|
||||||
|
Addr: ":" + cfg.Port,
|
||||||
|
Handler: mux,
|
||||||
|
ReadTimeout: 10 * time.Second,
|
||||||
|
WriteTimeout: 30 * time.Second,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user