@@ -12,7 +12,9 @@ import (
12
12
"bullet-cloud-api/internal/products"
13
13
"bullet-cloud-api/internal/users"
14
14
"context"
15
+ "fmt"
15
16
"log"
17
+ "net"
16
18
"net/http"
17
19
"os"
18
20
"os/signal"
@@ -23,7 +25,7 @@ import (
23
25
"github.com/gorilla/mux"
24
26
)
25
27
26
- const defaultPort = "4444"
28
+ const defaultPortStart = 4445
27
29
const defaultJWTExpiry = 24 * time .Hour
28
30
29
31
func main () {
@@ -60,20 +62,30 @@ func main() {
60
62
r := setupRoutes (authHandler , userHandler , productHandler , categoryHandler , cartHandler , orderHandler , authMiddleware )
61
63
62
64
// --- Determine Port ---
63
- port := os .Getenv ("PORT" ) // 1. Check Render's/Environment PORT variable
65
+ port := os .Getenv ("PORT" )
64
66
if port == "" {
65
- port = defaultPort // 2. Use default if PORT is not set
66
- }
67
- // Basic validation (optional but recommended)
68
- if _ , err := strconv .Atoi (port ); err != nil {
69
- log .Fatalf ("Invalid port number: %s" , port )
67
+ for p := defaultPortStart ; p < defaultPortStart + 100 ; p ++ {
68
+ addr := fmt .Sprintf (":%d" , p )
69
+ ln , err := net .Listen ("tcp" , addr )
70
+ if err == nil {
71
+ ln .Close ()
72
+ port = strconv .Itoa (p )
73
+ log .Printf ("PORT not set. Using first available port: %s" , port )
74
+ break
75
+ }
76
+ }
77
+ if port == "" {
78
+ log .Fatal ("No available ports found from 4445 to 4545" )
79
+ }
80
+ } else {
81
+ log .Printf ("Using PORT from environment: %s" , port )
70
82
}
71
83
listenAddr := ":" + port
72
84
// --- End Determine Port ---
73
85
74
86
// Configure HTTP server
75
87
srv := & http.Server {
76
- Addr : listenAddr , // Use the determined address
88
+ Addr : listenAddr ,
77
89
Handler : r ,
78
90
ReadTimeout : 5 * time .Second ,
79
91
WriteTimeout : 10 * time .Second ,
@@ -84,19 +96,16 @@ func main() {
84
96
done := make (chan os.Signal , 1 )
85
97
signal .Notify (done , os .Interrupt , syscall .SIGINT , syscall .SIGTERM )
86
98
87
- // Start server in a goroutine
88
99
go func () {
89
100
log .Printf ("Server starting on port %s" , port )
90
101
if err := srv .ListenAndServe (); err != nil && err != http .ErrServerClosed {
91
102
log .Fatalf ("listen: %s\n " , err )
92
103
}
93
104
}()
94
105
95
- // Wait for shutdown signal
96
106
<- done
97
107
log .Println ("Server shutting down gracefully..." )
98
108
99
- // Create context for shutdown
100
109
ctx , cancel := context .WithTimeout (context .Background (), 30 * time .Second )
101
110
defer cancel ()
102
111
@@ -108,9 +117,16 @@ func main() {
108
117
}
109
118
110
119
// setupRoutes configures the API routes using mux router.
111
- func setupRoutes (ah * handlers.AuthHandler , uh * handlers.UserHandler , ph * handlers.ProductHandler , ch * handlers.CategoryHandler , cartH * handlers.CartHandler , oh * handlers.OrderHandler , mw * auth.Middleware ) * mux.Router {
120
+ func setupRoutes (
121
+ ah * handlers.AuthHandler ,
122
+ uh * handlers.UserHandler ,
123
+ ph * handlers.ProductHandler ,
124
+ ch * handlers.CategoryHandler ,
125
+ cartH * handlers.CartHandler ,
126
+ oh * handlers.OrderHandler ,
127
+ mw * auth.Middleware ,
128
+ ) * mux.Router {
112
129
r := mux .NewRouter ()
113
-
114
130
apiV1 := r .PathPrefix ("/api" ).Subrouter ()
115
131
116
132
// Public routes
@@ -122,7 +138,7 @@ func setupRoutes(ah *handlers.AuthHandler, uh *handlers.UserHandler, ph *handler
122
138
apiV1 .HandleFunc ("/categories" , ch .GetAllCategories ).Methods ("GET" )
123
139
apiV1 .HandleFunc ("/categories/{id:[0-9a-fA-F-]+}" , ch .GetCategory ).Methods ("GET" )
124
140
125
- // Protected routes (grouped by resource)
141
+ // Protected routes
126
142
protectedUserRoutes := apiV1 .PathPrefix ("/users" ).Subrouter ()
127
143
protectedUserRoutes .Use (mw .Authenticate )
128
144
protectedUserRoutes .HandleFunc ("/me" , uh .GetMe ).Methods ("GET" )
0 commit comments