mood/inspo boards
at main 1.8 kB view raw
1package server 2 3import ( 4 "context" 5 "database/sql" 6 "fmt" 7 "net/http" 8 "time" 9 10 "github.com/charmbracelet/log" 11 "github.com/gorilla/mux" 12) 13 14type Server struct { 15 addr string 16 db *sql.DB 17 logger *log.Logger 18} 19 20type statusRecorder struct { 21 http.ResponseWriter 22 status int 23} 24 25func NewServer(addr string, db *sql.DB, logger *log.Logger) *Server { 26 return &Server{ 27 addr, 28 db, 29 logger, 30 } 31} 32 33func (s *Server) Start() error { 34 router := mux.NewRouter() 35 router.Use(s.requestLoggerMiddleware) 36 router.Use(s.contextWithTimeoutMiddleware) 37 server := &http.Server{ 38 Addr: s.addr, 39 WriteTimeout: 5 * time.Second, 40 ReadTimeout: 10 * time.Second, 41 IdleTimeout: 30 * time.Second, 42 Handler: router, 43 } 44 45 router.HandleFunc("/healthcheck", s.handleHomeRoute) 46 router.HandleFunc("/", s.handleHealthCheckRoute) 47 48 s.logger.Info(fmt.Sprintf("app server started at 0.0.0.0%s", s.addr)) 49 return server.ListenAndServe() 50} 51 52func (s *Server) contextWithTimeoutMiddleware(next http.Handler) http.Handler { 53 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 54 ctx, cancel := context.WithTimeout(r.Context(), time.Second*30) 55 defer cancel() 56 r = r.WithContext(ctx) 57 next.ServeHTTP(w, r) 58 }) 59} 60 61func (s *Server) requestLoggerMiddleware(next http.Handler) http.Handler { 62 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 63 recorder := statusRecorder{ 64 ResponseWriter: w, 65 status: http.StatusOK, 66 } 67 68 next.ServeHTTP(recorder, r) 69 var ( 70 ip = r.RemoteAddr 71 method = r.Method 72 url = r.URL.String() 73 proto = r.Proto 74 timestamp = time.Now().Format(time.RFC850) 75 ) 76 77 s.logger.Info(fmt.Sprintf("%s [%s] %s %s %s %d", ip, timestamp, method, url, proto, recorder.status)) 78 }) 79}