Files
AnthoLume/server/server.go
2026-03-22 17:21:32 -04:00

127 lines
2.8 KiB
Go

package server
import (
"context"
"io/fs"
"net/http"
"sync"
"time"
log "github.com/sirupsen/logrus"
"reichard.io/antholume/api"
"reichard.io/antholume/config"
"reichard.io/antholume/database"
v1 "reichard.io/antholume/api/v1"
)
type server struct {
db *database.DBManager
ginAPI *api.API
v1API *v1.Server
httpServer *http.Server
done chan int
wg sync.WaitGroup
}
// Create new server with both Gin and v1 API running in parallel
func New(c *config.Config, assets fs.FS) *server {
db := database.NewMgr(c)
ginAPI := api.NewApi(db, c, assets)
v1API := v1.NewServer(db, c)
// Create combined mux that handles both Gin and v1 API
mux := http.NewServeMux()
// Register v1 API routes first (they take precedence)
mux.Handle("/api/v1/", v1API)
// Register Gin API routes (handles all other routes including /)
// Gin's router implements http.Handler
mux.Handle("/", ginAPI.Handler())
// Create HTTP server with combined mux
httpServer := &http.Server{
Handler: mux,
Addr: ":" + c.ListenPort,
}
return &server{
db: db,
ginAPI: ginAPI,
v1API: v1API,
httpServer: httpServer,
done: make(chan int),
}
}
// Start server - runs both Gin and v1 API concurrently
func (s *server) Start() {
log.Info("Starting server with both Gin (templates) and v1 (API)...")
log.Info("v1 API endpoints available at /api/v1/*")
log.Info("Gin template endpoints available at /")
s.wg.Add(2)
go func() {
defer s.wg.Done()
log.Infof("HTTP server listening on %s", s.httpServer.Addr)
err := s.httpServer.ListenAndServe()
if err != nil && err != http.ErrServerClosed {
log.Error("Starting server failed: ", err)
}
}()
go func() {
defer s.wg.Done()
ticker := time.NewTicker(15 * time.Minute)
defer ticker.Stop()
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Minute))
for {
select {
case <-ticker.C:
s.runScheduledTasks(ctx)
case <-s.done:
log.Info("Stopping task runner...")
cancel()
return
}
}
}()
log.Info("Server started - running both Gin and v1 API concurrently")
}
// Stop server - gracefully shuts down both APIs
func (s *server) Stop() {
log.Info("Stopping server...")
// Shutdown HTTP server (both Gin and v1)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := s.httpServer.Shutdown(ctx); err != nil {
log.Error("HTTP server shutdown failed: ", err)
}
close(s.done)
s.wg.Wait()
// Close DB
if err := s.db.DB.Close(); err != nil {
log.Error("DB close failed: ", err)
}
log.Info("Server stopped")
}
// Run normal scheduled tasks
func (s *server) runScheduledTasks(ctx context.Context) {
start := time.Now()
if err := s.db.CacheTempTables(ctx); err != nil {
log.Warn("Refreshing temp table cache failed: ", err)
}
log.Debug("Completed in: ", time.Since(start))
}