Skip to content

Commit c8e1a73

Browse files
authored
refactor(server): Move handler and middleware packages to new server package (#60)
Signed-off-by: Mert Şişmanoğlu <[email protected]>
1 parent 23c32ee commit c8e1a73

File tree

6 files changed

+115
-74
lines changed

6 files changed

+115
-74
lines changed

cmd/capture/main.go

+5-74
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,20 @@
11
package main
22

33
import (
4-
"context"
54
"flag"
65
"fmt"
76
"log"
8-
"net"
9-
"net/http"
107
"os"
11-
"os/signal"
12-
"syscall"
138
"time"
149

1510
"github.com/bluewave-labs/capture/internal/config"
16-
"github.com/bluewave-labs/capture/internal/handler"
17-
"github.com/bluewave-labs/capture/internal/middleware"
18-
"github.com/gin-gonic/gin"
11+
"github.com/bluewave-labs/capture/internal/server"
1912
)
2013

2114
var appConfig *config.Config
2215

2316
var Version = "develop" // This will be set during compile time using go build ldflags
2417

25-
// getLocalIP retrieves the local IP address of the machine.
26-
// It returns the first non-loopback IPv4 address found.
27-
// If no valid address is found, it returns "<ip-address>" as a placeholder.
28-
// This function is used to display the local IP address in the log message.
29-
func getLocalIP() string {
30-
addrs, err := net.InterfaceAddrs()
31-
if err != nil {
32-
return "<ip-address>"
33-
}
34-
for _, addr := range addrs {
35-
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
36-
if ipnet.IP.To4() != nil {
37-
return ipnet.IP.String()
38-
}
39-
}
40-
}
41-
return "<ip-address>"
42-
}
43-
4418
func main() {
4519
showVersion := flag.Bool("version", false, "Display the version of the capture")
4620
flag.Parse()
@@ -56,53 +30,10 @@ func main() {
5630
os.Getenv("API_SECRET"),
5731
)
5832

59-
// Initialize the Gin with default middlewares
60-
r := gin.Default()
61-
apiV1 := r.Group("/api/v1")
62-
apiV1.Use(middleware.AuthRequired(appConfig.APISecret))
63-
64-
// Health Check
65-
apiV1.GET("/health", handler.Health)
66-
67-
// Metrics
68-
apiV1.GET("/metrics", handler.Metrics)
69-
apiV1.GET("/metrics/cpu", handler.MetricsCPU)
70-
apiV1.GET("/metrics/memory", handler.MetricsMemory)
71-
apiV1.GET("/metrics/disk", handler.MetricsDisk)
72-
apiV1.GET("/metrics/host", handler.MetricsHost)
73-
apiV1.GET("/metrics/smart", handler.SmartMetrics)
74-
75-
log.Println("WARNING: Remember to add http://" + getLocalIP() + ":" + appConfig.Port + "/api/v1/metrics to your Checkmate Infrastructure Dashboard. Without this endpoint, system metrics will not be displayed.")
76-
77-
server := &http.Server{
78-
Addr: ":" + appConfig.Port,
79-
Handler: r.Handler(),
80-
ReadHeaderTimeout: 5 * time.Second,
81-
}
82-
83-
go serve(server)
84-
85-
if err := gracefulShutdown(server, 5*time.Second); err != nil {
86-
log.Fatalln("graceful shutdown error", err)
87-
}
88-
}
89-
90-
func serve(srv *http.Server) {
91-
srvErr := srv.ListenAndServe()
92-
if srvErr != nil && srvErr != http.ErrServerClosed {
93-
log.Fatalf("listen error: %s\n", srvErr)
94-
}
95-
}
96-
97-
func gracefulShutdown(srv *http.Server, timeout time.Duration) error {
98-
quit := make(chan os.Signal, 1)
99-
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
100-
101-
sig := <-quit
102-
log.Printf("signal received: %v", sig)
33+
srv := server.NewServer(appConfig, nil)
34+
log.Println("WARNING: Remember to add http://" + server.GetLocalIP() + ":" + appConfig.Port + "/api/v1/metrics to your Checkmate Infrastructure Dashboard. Without this endpoint, system metrics will not be displayed.")
10335

104-
ctx, cancel := context.WithTimeout(context.Background(), timeout)
105-
defer cancel()
36+
srv.Serve()
10637

107-
return srv.Shutdown(ctx)
38+
srv.GracefulShutdown(5 * time.Second)
10839
}
File renamed without changes.
File renamed without changes.
File renamed without changes.

internal/server/net.go

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package server
2+
3+
import "net"
4+
5+
// GetLocalIP retrieves the local IP address of the machine.
6+
// It returns the first non-loopback IPv4 address found.
7+
// If no valid address is found, it returns "<ip-address>" as a placeholder.
8+
// This function is used to display the local IP address in the log message.
9+
func GetLocalIP() string {
10+
addrs, err := net.InterfaceAddrs()
11+
if err != nil {
12+
return "<ip-address>"
13+
}
14+
for _, addr := range addrs {
15+
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
16+
if ipnet.IP.To4() != nil {
17+
return ipnet.IP.String()
18+
}
19+
}
20+
}
21+
return "<ip-address>"
22+
}

internal/server/server.go

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package server
2+
3+
import (
4+
"context"
5+
"log"
6+
"net/http"
7+
"os"
8+
"os/signal"
9+
"syscall"
10+
"time"
11+
12+
"github.com/bluewave-labs/capture/internal/config"
13+
"github.com/bluewave-labs/capture/internal/server/handler"
14+
"github.com/bluewave-labs/capture/internal/server/middleware"
15+
"github.com/gin-gonic/gin"
16+
)
17+
18+
type Server struct {
19+
*http.Server
20+
}
21+
22+
// Serve function starts the HTTP server and listens for incoming requests concurrently.
23+
// It uses a goroutine to handle the server's ListenAndServe method, allowing the main thread to continue executing.
24+
func (s *Server) Serve() {
25+
go func() {
26+
if err := s.Server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
27+
log.Fatalf("server error: %v", err)
28+
}
29+
}()
30+
log.Printf("server started on %s", s.Server.Addr)
31+
}
32+
33+
// Shutdown gracefully shuts down the server with a timeout.
34+
func (s *Server) GracefulShutdown(timeout time.Duration) {
35+
quit := make(chan os.Signal, 1)
36+
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
37+
38+
sig := <-quit
39+
log.Printf("signal received: %v", sig)
40+
41+
ctx, cancel := context.WithTimeout(context.Background(), timeout)
42+
defer cancel()
43+
44+
log.Println("shutting down server...")
45+
if err := s.Server.Shutdown(ctx); err != nil {
46+
log.Printf("server shutdown error: %v", err)
47+
} else {
48+
log.Println("server shutdown gracefully")
49+
}
50+
}
51+
52+
func InitializeHandler(config *config.Config) http.Handler {
53+
// Initialize the Gin with default middlewares
54+
r := gin.Default()
55+
if gin.Mode() == gin.ReleaseMode {
56+
println("running in Release Mode")
57+
} else {
58+
println("running in Debug Mode")
59+
}
60+
apiV1 := r.Group("/api/v1")
61+
apiV1.Use(middleware.AuthRequired(config.APISecret))
62+
63+
// Health Check
64+
apiV1.GET("/health", handler.Health)
65+
66+
// Metrics
67+
apiV1.GET("/metrics", handler.Metrics)
68+
apiV1.GET("/metrics/cpu", handler.MetricsCPU)
69+
apiV1.GET("/metrics/memory", handler.MetricsMemory)
70+
apiV1.GET("/metrics/disk", handler.MetricsDisk)
71+
apiV1.GET("/metrics/host", handler.MetricsHost)
72+
apiV1.GET("/metrics/smart", handler.SmartMetrics)
73+
74+
return r.Handler()
75+
}
76+
77+
func NewServer(config *config.Config, handler http.Handler) *Server {
78+
if handler == nil {
79+
handler = InitializeHandler(config)
80+
}
81+
return &Server{
82+
Server: &http.Server{
83+
Addr: ":" + config.Port,
84+
Handler: handler,
85+
ReadHeaderTimeout: 5 * time.Second,
86+
},
87+
}
88+
}

0 commit comments

Comments
 (0)