* feat(server): moved an http server object into a pkg subdir to be reusable for http, spots, and integrations * feat(web): isolated web module (server, router, middleware, utils) used in spots and new integrations * feat(web): removed possible panic * feat(web): split all handlers from http service into different packages for better management. * feat(web): changed router's method signature * feat(web): added missing handlers interface * feat(web): added health middleware to remove unnecessary checks * feat(web): customizable middleware set for web servers * feat(web): simplified the handler's structure * feat(web): created an unified server.Run method for all web services (http, spot, integrations) * feat(web): fixed a json size limit issue * feat(web): removed Keys and PG connection from router * feat(web): simplified integration's main file * feat(web): simplified spot's main file * feat(web): simplified http's main file (builder) * feat(web): refactored audit trail functionality * feat(web): added ee version of audit trail * feat(web): added ee version of conditions module * feat(web): moved ee version of some web session structs * feat(web): new format of web metrics * feat(web): added new web metrics to all handlers * feat(web): added justExpired feature to web ingest handler * feat(web): added small integrations improvements
96 lines
2.7 KiB
Go
96 lines
2.7 KiB
Go
package tracer
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"io"
|
|
"net/http"
|
|
|
|
"github.com/gorilla/mux"
|
|
|
|
"openreplay/backend/pkg/server/user"
|
|
)
|
|
|
|
type statusWriter struct {
|
|
http.ResponseWriter
|
|
statusCode int
|
|
}
|
|
|
|
func (w *statusWriter) WriteHeader(statusCode int) {
|
|
w.statusCode = statusCode
|
|
w.ResponseWriter.WriteHeader(statusCode)
|
|
}
|
|
|
|
func (w *statusWriter) Write(b []byte) (int, error) {
|
|
if w.statusCode == 0 {
|
|
w.statusCode = http.StatusOK
|
|
}
|
|
return w.ResponseWriter.Write(b)
|
|
}
|
|
|
|
func (t *tracerImpl) Middleware(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
// Read body and restore the io.ReadCloser to its original state
|
|
bodyBytes, err := io.ReadAll(r.Body)
|
|
if err != nil {
|
|
http.Error(w, "can't read body", http.StatusBadRequest)
|
|
return
|
|
}
|
|
r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
|
|
// Use custom response writer to get the status code
|
|
sw := &statusWriter{ResponseWriter: w}
|
|
// Serve the request
|
|
next.ServeHTTP(sw, r)
|
|
t.logRequest(r, bodyBytes, sw.statusCode)
|
|
})
|
|
}
|
|
|
|
var routeMatch = map[string]string{
|
|
"POST" + "/spot/v1/spots": "createSpot",
|
|
"GET" + "/spot/v1/spots/{id}": "getSpot",
|
|
"PATCH" + "/spot/v1/spots/{id}": "updateSpot",
|
|
"GET" + "/spot/v1/spots": "getSpots",
|
|
"DELETE" + "/spot/v1/spots": "deleteSpots",
|
|
"POST" + "/spot/v1/spots/{id}/comment": "addComment",
|
|
"GET" + "/spot/v1/spots/{id}/video": "getSpotVideo",
|
|
"PATCH" + "/spot/v1/spots/{id}/public-key": "updatePublicKey",
|
|
}
|
|
|
|
func (t *tracerImpl) logRequest(r *http.Request, bodyBytes []byte, statusCode int) {
|
|
pathTemplate, err := mux.CurrentRoute(r).GetPathTemplate()
|
|
if err != nil {
|
|
t.log.Error(r.Context(), "failed to get path template: %s", err)
|
|
}
|
|
t.log.Debug(r.Context(), "path template: %s", pathTemplate)
|
|
if _, ok := routeMatch[r.Method+pathTemplate]; !ok {
|
|
t.log.Debug(r.Context(), "no match for route: %s %s", r.Method, pathTemplate)
|
|
return
|
|
}
|
|
// Convert the parameters to json
|
|
query := r.URL.Query()
|
|
params := make(map[string]interface{})
|
|
for key, values := range query {
|
|
if len(values) > 1 {
|
|
params[key] = values
|
|
} else {
|
|
params[key] = values[0]
|
|
}
|
|
}
|
|
jsonData, err := json.Marshal(params)
|
|
if err != nil {
|
|
t.log.Error(r.Context(), "failed to marshal query parameters: %s", err)
|
|
}
|
|
requestData := &RequestData{
|
|
Action: routeMatch[r.Method+pathTemplate],
|
|
Method: r.Method,
|
|
PathFormat: pathTemplate,
|
|
Endpoint: r.URL.Path,
|
|
Payload: bodyBytes,
|
|
Parameters: jsonData,
|
|
Status: statusCode,
|
|
}
|
|
userData := r.Context().Value("userData").(*user.User)
|
|
t.trace(userData, requestData)
|
|
// DEBUG
|
|
t.log.Debug(r.Context(), "request data: %v", requestData)
|
|
}
|