HTTP server with WebSockets.
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				Linting and tests / Linting (push) Successful in 5s
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	Linting and tests / Linting (push) Successful in 5s
				
			This commit is contained in:
		| @@ -2,6 +2,7 @@ package core | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"net/http" | ||||
| ) | ||||
|  | ||||
| // ServiceNameHTTPServer is a name for HTTP server service. | ||||
| @@ -11,6 +12,12 @@ const ServiceNameHTTPServer = "core/http_server" | ||||
| var ErrHTTPServerIsInvalid = errors.New("HTTP server service implementation is invalid") | ||||
|  | ||||
| // HTTPServer is an interface for HTTP server service. | ||||
| // | ||||
| //nolint:iface | ||||
| type HTTPServer interface{} | ||||
| type HTTPServer interface { | ||||
| 	// RegisterHandler registers HTTP handler. | ||||
| 	RegisterHandler(method, path string, handler http.HandlerFunc) | ||||
| 	// RegisterMiddleware registers HTTP server middlewares. | ||||
| 	RegisterMiddleware(middleware HTTPMiddlewareFunc) | ||||
| } | ||||
|  | ||||
| // HTTPMiddlewareFunc is a function that acts as middleware for HTTP requests. | ||||
| type HTTPMiddlewareFunc func(fn http.HandlerFunc) http.HandlerFunc | ||||
|   | ||||
| @@ -0,0 +1,8 @@ | ||||
| package httpserver | ||||
|  | ||||
| import "net/http" | ||||
|  | ||||
| func (h *httpServer) defaultHandler(w http.ResponseWriter, _ *http.Request) { | ||||
| 	w.WriteHeader(http.StatusNotFound) | ||||
| 	_, _ = w.Write([]byte("Unknown path.")) | ||||
| } | ||||
| @@ -21,6 +21,9 @@ type httpServer struct { | ||||
| 	logger  *slog.Logger | ||||
| 	db      core.Database | ||||
| 	httpSrv *http.Server | ||||
| 	httpMux *http.ServeMux | ||||
|  | ||||
| 	middlewares []core.HTTPMiddlewareFunc | ||||
| } | ||||
|  | ||||
| // Initialize initializes service. | ||||
| @@ -67,6 +70,10 @@ func (h *httpServer) Initialize() error { | ||||
|  | ||||
| 	h.logger.Info("Initializing...") | ||||
|  | ||||
| 	h.middlewares = make([]core.HTTPMiddlewareFunc, 0) | ||||
|  | ||||
| 	h.RegisterMiddleware(h.requestLoggingMiddleware) | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										24
									
								
								server/internal/services/core/httpserver/request_logger.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								server/internal/services/core/httpserver/request_logger.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| package httpserver | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| func (h *httpServer) requestLoggingMiddleware(fn http.HandlerFunc) http.HandlerFunc { | ||||
| 	return func(w http.ResponseWriter, r *http.Request) { | ||||
| 		startTime := time.Now() | ||||
|  | ||||
| 		fn(w, r) | ||||
|  | ||||
| 		h.logger.Info( | ||||
| 			"HTTP request.", | ||||
| 			"remote_addr", r.RemoteAddr, | ||||
| 			"user_agent", r.UserAgent(), | ||||
| 			"host", r.Host, | ||||
| 			"path", fmt.Sprintf("%s %s", r.Method, r.RequestURI), | ||||
| 			"duration", time.Since(startTime), | ||||
| 		) | ||||
| 	} | ||||
| } | ||||
| @@ -9,6 +9,8 @@ import ( | ||||
| 	"os" | ||||
| 	"time" | ||||
|  | ||||
| 	"bunker/server/internal/services/core" | ||||
|  | ||||
| 	"github.com/coder/websocket" | ||||
| ) | ||||
|  | ||||
| @@ -35,12 +37,15 @@ func (h *httpServer) configureHTTPServer() error { | ||||
| 		return fmt.Errorf("configure HTTP server: validate HTTP server address: %w", errHTTPServerAddrInvalid) | ||||
| 	} | ||||
|  | ||||
| 	mux := new(http.ServeMux) | ||||
| 	mux.HandleFunc("GET /api/v1/socket", h.handleWebsocketRequest) | ||||
| 	h.httpMux = new(http.ServeMux) | ||||
|  | ||||
| 	// Default catch-all handler. | ||||
| 	h.RegisterHandler("", "/", h.defaultHandler) | ||||
| 	h.RegisterHandler(http.MethodGet, "/api/v1/socket", h.handleWebsocketRequest) | ||||
|  | ||||
| 	h.httpSrv = &http.Server{ | ||||
| 		Addr:              httpSrvAddr, | ||||
| 		Handler:           mux, | ||||
| 		Handler:           h.httpMux, | ||||
| 		ReadHeaderTimeout: time.Second * 3, | ||||
| 	} | ||||
|  | ||||
| @@ -66,6 +71,20 @@ func (h *httpServer) handleWebsocketRequest(w http.ResponseWriter, r *http.Reque | ||||
| 	}() | ||||
| } | ||||
|  | ||||
| func (h *httpServer) RegisterHandler(method, path string, handler http.HandlerFunc) { | ||||
| 	h.httpMux.HandleFunc(fmt.Sprintf("%s %s", method, path), func(w http.ResponseWriter, r *http.Request) { | ||||
| 		for i := len(h.middlewares) - 1; i >= 0; i-- { | ||||
| 			handler = h.middlewares[i](handler) | ||||
| 		} | ||||
|  | ||||
| 		handler(w, r) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func (h *httpServer) RegisterMiddleware(middleware core.HTTPMiddlewareFunc) { | ||||
| 	h.middlewares = append(h.middlewares, middleware) | ||||
| } | ||||
|  | ||||
| func (h *httpServer) startHTTPServer() { | ||||
| 	h.logger.Info("Starting listening for HTTP requests.", "address", h.httpSrv.Addr) | ||||
|  | ||||
|   | ||||
| @@ -11,6 +11,4 @@ const ServiceNameOptions = "core/options" | ||||
| var ErrOptionsIsInvalid = errors.New("options service implementation is invalid") | ||||
|  | ||||
| // Options is an interface for options service. | ||||
| // | ||||
| //nolint:iface | ||||
| type Options interface{} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user