package api import ( "context" "encoding/json" "errors" "fmt" "net/http" "time" "openreplay/backend/pkg/featureflags" "openreplay/backend/pkg/logger" "openreplay/backend/pkg/server/api" "openreplay/backend/pkg/sessions" "openreplay/backend/pkg/token" ) type handlersImpl struct { log logger.Logger responser *api.Responser jsonSizeLimit int64 tokenizer *token.Tokenizer sessions sessions.Sessions featureFlags featureflags.FeatureFlags } func NewHandlers(log logger.Logger, responser *api.Responser, jsonSizeLimit int64, tokenizer *token.Tokenizer, sessions sessions.Sessions, featureFlags featureflags.FeatureFlags) (api.Handlers, error) { return &handlersImpl{ log: log, responser: responser, jsonSizeLimit: jsonSizeLimit, tokenizer: tokenizer, sessions: sessions, featureFlags: featureFlags, }, nil } func (e *handlersImpl) GetAll() []*api.Description { return []*api.Description{ {"/v1/web/feature-flags", e.featureFlagsHandlerWeb, "POST"}, } } func (e *handlersImpl) featureFlagsHandlerWeb(w http.ResponseWriter, r *http.Request) { startTime := time.Now() bodySize := 0 // Check authorization sessionData, err := e.tokenizer.ParseFromHTTPRequest(r) if sessionData != nil { r = r.WithContext(context.WithValue(r.Context(), "sessionID", fmt.Sprintf("%d", sessionData.ID))) } if err != nil { e.responser.ResponseWithError(e.log, r.Context(), w, http.StatusUnauthorized, err, startTime, r.URL.Path, bodySize) return } // Add sessionID and projectID to context if info, err := e.sessions.Get(sessionData.ID); err == nil { r = r.WithContext(context.WithValue(r.Context(), "projectID", fmt.Sprintf("%d", info.ProjectID))) } if r.Body == nil { e.responser.ResponseWithError(e.log, r.Context(), w, http.StatusBadRequest, errors.New("request body is empty"), startTime, r.URL.Path, bodySize) return } bodyBytes, err := api.ReadCompressedBody(e.log, w, r, e.jsonSizeLimit) if err != nil { e.responser.ResponseWithError(e.log, r.Context(), w, http.StatusRequestEntityTooLarge, err, startTime, r.URL.Path, bodySize) return } bodySize = len(bodyBytes) // Parse request body req := &featureflags.FeatureFlagsRequest{} if err := json.Unmarshal(bodyBytes, req); err != nil { e.responser.ResponseWithError(e.log, r.Context(), w, http.StatusBadRequest, err, startTime, r.URL.Path, bodySize) return } computedFlags, err := e.featureFlags.ComputeFlagsForSession(req) if err != nil { e.responser.ResponseWithError(e.log, r.Context(), w, http.StatusInternalServerError, err, startTime, r.URL.Path, bodySize) return } resp := &featureflags.FeatureFlagsResponse{ Flags: computedFlags, } e.responser.ResponseWithJSON(e.log, r.Context(), w, resp, startTime, r.URL.Path, bodySize) }