2
0

server.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. package httpserver
  2. import (
  3. "context"
  4. "fmt"
  5. "log"
  6. "net/http"
  7. "time"
  8. "github.com/danfragoso/pizzasql-next/pkg/executor"
  9. "github.com/danfragoso/pizzasql-next/pkg/storage"
  10. )
  11. // Config holds HTTP server configuration.
  12. type Config struct {
  13. Host string
  14. Port int
  15. ReadTimeout time.Duration
  16. WriteTimeout time.Duration
  17. MaxConnections int
  18. EnableCORS bool
  19. EnableAuth bool
  20. EnableCompression bool
  21. APIKeys []string
  22. TLSCertFile string
  23. TLSKeyFile string
  24. }
  25. // DefaultConfig returns default server configuration.
  26. func DefaultConfig() *Config {
  27. return &Config{
  28. Host: "localhost",
  29. Port: 8080,
  30. ReadTimeout: 30 * time.Second,
  31. WriteTimeout: 30 * time.Second,
  32. MaxConnections: 1000,
  33. EnableCORS: true,
  34. EnableAuth: false,
  35. EnableCompression: true,
  36. APIKeys: []string{},
  37. }
  38. }
  39. // Server represents the HTTP API server.
  40. type Server struct {
  41. config *Config
  42. executor *executor.Executor
  43. schema *storage.SchemaManager
  44. server *http.Server
  45. stats *Stats
  46. }
  47. // Stats tracks server statistics.
  48. type Stats struct {
  49. QueriesExecuted int64
  50. QueriesSuccess int64
  51. QueriesError int64
  52. StartTime time.Time
  53. }
  54. // New creates a new HTTP server.
  55. func New(config *Config, exec *executor.Executor, schema *storage.SchemaManager) *Server {
  56. if config == nil {
  57. config = DefaultConfig()
  58. }
  59. s := &Server{
  60. config: config,
  61. executor: exec,
  62. schema: schema,
  63. stats: &Stats{
  64. StartTime: time.Now(),
  65. },
  66. }
  67. mux := http.NewServeMux()
  68. // Apply middleware (order matters: logging -> auth -> cors -> compression -> handler)
  69. var handler http.Handler = mux
  70. if config.EnableCompression {
  71. handler = s.compressionMiddleware(handler)
  72. }
  73. if config.EnableCORS {
  74. handler = s.corsMiddleware(handler)
  75. }
  76. if config.EnableAuth {
  77. handler = s.authMiddleware(handler)
  78. }
  79. handler = s.loggingMiddleware(handler)
  80. // Register routes
  81. mux.HandleFunc("/query", s.handleQuery)
  82. mux.HandleFunc("/execute", s.handleExecute)
  83. mux.HandleFunc("/schema/tables", s.handleSchemaTables)
  84. mux.HandleFunc("/schema/tables/", s.handleSchemaTable)
  85. mux.HandleFunc("/health", s.handleHealth)
  86. mux.HandleFunc("/stats", s.handleStats)
  87. mux.HandleFunc("/metrics", s.handleMetrics)
  88. mux.HandleFunc("/transaction/begin", s.handleTransactionBegin)
  89. mux.HandleFunc("/transaction/commit", s.handleTransactionCommit)
  90. mux.HandleFunc("/transaction/rollback", s.handleTransactionRollback)
  91. s.server = &http.Server{
  92. Addr: fmt.Sprintf("%s:%d", config.Host, config.Port),
  93. Handler: handler,
  94. ReadTimeout: config.ReadTimeout,
  95. WriteTimeout: config.WriteTimeout,
  96. }
  97. return s
  98. }
  99. // Start starts the HTTP server.
  100. func (s *Server) Start() error {
  101. addr := s.server.Addr
  102. log.Printf("Starting HTTP server on http://%s", addr)
  103. if s.config.TLSCertFile != "" && s.config.TLSKeyFile != "" {
  104. return s.server.ListenAndServeTLS(s.config.TLSCertFile, s.config.TLSKeyFile)
  105. }
  106. return s.server.ListenAndServe()
  107. }
  108. // Shutdown gracefully shuts down the server.
  109. func (s *Server) Shutdown(ctx context.Context) error {
  110. log.Println("Shutting down HTTP server...")
  111. return s.server.Shutdown(ctx)
  112. }
  113. // Addr returns the server address.
  114. func (s *Server) Addr() string {
  115. return s.server.Addr
  116. }