ipapi/internal/http/server.go
sneak 2a1710cca8 Implement IP API daemon with GeoIP database support
- Create modular architecture with separate packages for config, database, HTTP, logging, and state management
- Implement Cobra CLI with daemon command
- Set up Uber FX dependency injection
- Add Chi router with health check and IP lookup endpoints
- Implement GeoIP database downloader with automatic updates
- Add state persistence for tracking database download times
- Include comprehensive test coverage for all components
- Configure structured logging with slog
- Add Makefile with test, lint, and build targets
- Support both IPv4 and IPv6 lookups
- Return country, city, ASN, and location data in JSON format
2025-07-27 18:15:38 +02:00

67 lines
1.4 KiB
Go

package http
import (
"context"
"fmt"
"log/slog"
"net/http"
"time"
"git.eeqj.de/sneak/ipapi/internal/config"
"github.com/go-chi/chi/v5"
)
// Server manages the HTTP server lifecycle.
type Server struct {
config *config.Config
logger *slog.Logger
router chi.Router
httpServer *http.Server
}
// NewServer creates a new HTTP server instance.
func NewServer(cfg *config.Config, logger *slog.Logger, router chi.Router) (*Server, error) {
return &Server{
config: cfg,
logger: logger,
router: router,
}, nil
}
// Start begins listening for HTTP requests.
func (s *Server) Start(_ context.Context) error {
addr := fmt.Sprintf(":%d", s.config.Port)
s.httpServer = &http.Server{
Addr: addr,
Handler: s.router,
ReadTimeout: 15 * time.Second, //nolint:mnd
WriteTimeout: 15 * time.Second, //nolint:mnd
IdleTimeout: 60 * time.Second, //nolint:mnd
}
s.logger.Info("Starting HTTP server", "addr", addr)
go func() {
if err := s.httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
s.logger.Error("HTTP server error", "error", err)
}
}()
return nil
}
// Stop gracefully shuts down the HTTP server.
func (s *Server) Stop(ctx context.Context) error {
if s.httpServer == nil {
return nil
}
s.logger.Info("Stopping HTTP server")
const shutdownTimeout = 30 * time.Second
shutdownCtx, cancel := context.WithTimeout(ctx, shutdownTimeout)
defer cancel()
return s.httpServer.Shutdown(shutdownCtx)
}