package api import ( "net/http" "strconv" "time" "browser.local/platform/domain" "browser.local/platform/dto" ) func (h *coreHandlers) serverSCUMUsers(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { writeMethodNotAllowed(w, http.MethodGet) return } filter, ok := scumUserFilterFromRequest(w, r, r.PathValue("id")) if !ok { return } items, err := h.core.ListSCUMUsersForSession(bearerToken(r), filter) if err != nil { writeServiceError(w, err) return } writeJSON(w, http.StatusOK, dto.SCUMUserListFromDomain(items)) } func (h *coreHandlers) serverSCUMUserTrajectories(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { writeMethodNotAllowed(w, http.MethodGet) return } filter, ok := scumUserTrajectoryFilterFromRequest(w, r, r.PathValue("id")) if !ok { return } items, err := h.core.ListSCUMUserTrajectoriesForSession(bearerToken(r), filter) if err != nil { writeServiceError(w, err) return } writeJSON(w, http.StatusOK, dto.SCUMUserTrajectoryListFromDomain(items)) } func (h *coreHandlers) serverSCUMVehicles(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { writeMethodNotAllowed(w, http.MethodGet) return } filter, ok := scumVehicleFilterFromRequest(w, r, r.PathValue("id")) if !ok { return } items, err := h.core.ListSCUMVehiclesForSession(bearerToken(r), filter) if err != nil { writeServiceError(w, err) return } writeJSON(w, http.StatusOK, dto.SCUMVehicleListFromDomain(items)) } func (h *coreHandlers) serverSCUMVehicleTrajectories(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { writeMethodNotAllowed(w, http.MethodGet) return } filter, ok := scumVehicleTrajectoryFilterFromRequest(w, r, r.PathValue("id")) if !ok { return } items, err := h.core.ListSCUMVehicleTrajectoriesForSession(bearerToken(r), filter) if err != nil { writeServiceError(w, err) return } writeJSON(w, http.StatusOK, dto.SCUMVehicleTrajectoryListFromDomain(items)) } func (h *coreHandlers) serverSCUMVehicleLocks(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { writeMethodNotAllowed(w, http.MethodGet) return } filter, ok := scumVehicleLockFilterFromRequest(w, r, r.PathValue("id")) if !ok { return } items, err := h.core.ListSCUMVehicleLocksForSession(bearerToken(r), filter) if err != nil { writeServiceError(w, err) return } writeJSON(w, http.StatusOK, dto.SCUMVehicleLockListFromDomain(items)) } func (h *coreHandlers) runSCUMFacts(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { writeMethodNotAllowed(w, http.MethodPost) return } request, err := decodeJSON[dto.SCUMFactIngestRequest](r) if err != nil { writeDecodeError(w, err) return } result, err := h.core.IngestSCUMFacts(request.ToDomain()) if err != nil { writeServiceError(w, err) return } writeJSON(w, http.StatusAccepted, dto.SCUMFactIngestFromDomain(result)) } func scumUserFilterFromRequest(w http.ResponseWriter, r *http.Request, serverID string) (domain.SCUMUserFilter, bool) { limit, ok := optionalLimitFromRequest(w, r) if !ok { return domain.SCUMUserFilter{}, false } online, ok := optionalBoolFromRequest(w, r, "online") if !ok { return domain.SCUMUserFilter{}, false } changedAfter, ok := optionalTimeFromRequest(w, r, "changedAfter") if !ok { return domain.SCUMUserFilter{}, false } return domain.SCUMUserFilter{ServerInstanceID: serverID, SteamID: r.URL.Query().Get("steamId"), Online: online, ChangedAfter: changedAfter, Limit: limit}, true } func scumUserTrajectoryFilterFromRequest(w http.ResponseWriter, r *http.Request, serverID string) (domain.SCUMUserTrajectoryFilter, bool) { limit, ok := optionalLimitFromRequest(w, r) if !ok { return domain.SCUMUserTrajectoryFilter{}, false } after, ok := optionalTimeFromRequest(w, r, "after") if !ok { return domain.SCUMUserTrajectoryFilter{}, false } return domain.SCUMUserTrajectoryFilter{ServerInstanceID: serverID, SCUMUserID: r.URL.Query().Get("scumUserId"), SteamID: r.URL.Query().Get("steamId"), After: after, Limit: limit}, true } func scumVehicleFilterFromRequest(w http.ResponseWriter, r *http.Request, serverID string) (domain.SCUMVehicleFilter, bool) { limit, ok := optionalLimitFromRequest(w, r) if !ok { return domain.SCUMVehicleFilter{}, false } exists, ok := optionalBoolFromRequest(w, r, "exists") if !ok { return domain.SCUMVehicleFilter{}, false } changedAfter, ok := optionalTimeFromRequest(w, r, "changedAfter") if !ok { return domain.SCUMVehicleFilter{}, false } return domain.SCUMVehicleFilter{ServerInstanceID: serverID, GameVehicleID: r.URL.Query().Get("gameVehicleId"), Exists: exists, ChangedAfter: changedAfter, Limit: limit}, true } func scumVehicleTrajectoryFilterFromRequest(w http.ResponseWriter, r *http.Request, serverID string) (domain.SCUMVehicleTrajectoryFilter, bool) { limit, ok := optionalLimitFromRequest(w, r) if !ok { return domain.SCUMVehicleTrajectoryFilter{}, false } after, ok := optionalTimeFromRequest(w, r, "after") if !ok { return domain.SCUMVehicleTrajectoryFilter{}, false } return domain.SCUMVehicleTrajectoryFilter{ServerInstanceID: serverID, SCUMVehicleID: r.URL.Query().Get("scumVehicleId"), GameVehicleID: r.URL.Query().Get("gameVehicleId"), After: after, Limit: limit}, true } func scumVehicleLockFilterFromRequest(w http.ResponseWriter, r *http.Request, serverID string) (domain.SCUMVehicleLockFilter, bool) { limit, ok := optionalLimitFromRequest(w, r) if !ok { return domain.SCUMVehicleLockFilter{}, false } after, ok := optionalTimeFromRequest(w, r, "after") if !ok { return domain.SCUMVehicleLockFilter{}, false } query := r.URL.Query() return domain.SCUMVehicleLockFilter{ServerInstanceID: serverID, SCUMVehicleID: query.Get("scumVehicleId"), GameVehicleID: query.Get("gameVehicleId"), SCUMUserID: query.Get("scumUserId"), SteamID: query.Get("steamId"), After: after, Limit: limit}, true } func optionalLimitFromRequest(w http.ResponseWriter, r *http.Request) (int, bool) { limit, err := optionalPositiveInt(r.URL.Query().Get("limit")) if err != nil || limit < 0 { writeAPIError(w, http.StatusBadRequest, errorCodeBadRequest, "invalid limit", nil) return 0, false } return limit, true } func optionalBoolFromRequest(w http.ResponseWriter, r *http.Request, key string) (*bool, bool) { value := r.URL.Query().Get(key) if value == "" { return nil, true } parsed, err := strconv.ParseBool(value) if err != nil { writeAPIError(w, http.StatusBadRequest, errorCodeBadRequest, "invalid "+key, nil) return nil, false } return &parsed, true } func optionalTimeFromRequest(w http.ResponseWriter, r *http.Request, key string) (time.Time, bool) { value := r.URL.Query().Get(key) if value == "" { return time.Time{}, true } parsed, err := time.Parse(time.RFC3339, value) if err != nil { writeAPIError(w, http.StatusBadRequest, errorCodeBadRequest, "invalid "+key, nil) return time.Time{}, false } return parsed, true }