feat(go): add post raw frame query
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -83,6 +84,31 @@ type LocationRow struct {
|
||||
VIN string `json:"vin"`
|
||||
}
|
||||
|
||||
type rawFrameQueryRequest struct {
|
||||
Protocol string `json:"protocol"`
|
||||
VehicleKey string `json:"vehicleKey"`
|
||||
VehicleKeyAlt string `json:"vehicle_key"`
|
||||
VIN string `json:"vin"`
|
||||
Phone string `json:"phone"`
|
||||
DeviceID string `json:"deviceId"`
|
||||
DeviceIDAlt string `json:"device_id"`
|
||||
MessageID string `json:"messageId"`
|
||||
MessageIDAlt string `json:"message_id"`
|
||||
OrderBy string `json:"orderBy"`
|
||||
OrderByAlt string `json:"order_by"`
|
||||
IncludeFields bool `json:"includeFields"`
|
||||
IncludePayload bool `json:"includePayload"`
|
||||
IncludeTotal bool `json:"includeTotal"`
|
||||
Fields []string `json:"fields"`
|
||||
ParsedFields []string `json:"parsedFields"`
|
||||
DateFrom string `json:"dateFrom"`
|
||||
DateFromAlt string `json:"date_from"`
|
||||
DateTo string `json:"dateTo"`
|
||||
DateToAlt string `json:"date_to"`
|
||||
Limit int `json:"limit"`
|
||||
Offset int `json:"offset"`
|
||||
}
|
||||
|
||||
type RawFrameRepository struct {
|
||||
db Queryer
|
||||
database string
|
||||
@@ -647,15 +673,16 @@ func NewLocationHandler(repository *LocationRepository) *LocationHandler {
|
||||
}
|
||||
|
||||
func (h *RawFrameHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
if r.Method != http.MethodGet && r.Method != http.MethodPost {
|
||||
writeHistoryError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||
return
|
||||
}
|
||||
if strings.Trim(r.URL.Path, "/") != "api/history/raw-frames" {
|
||||
path := strings.Trim(r.URL.Path, "/")
|
||||
if path != "api/history/raw-frames" && path != "api/history/raw-frames/query" {
|
||||
writeHistoryError(w, http.StatusNotFound, "route not found")
|
||||
return
|
||||
}
|
||||
query, err := parseRawFrameQuery(r)
|
||||
query, err := rawFrameQueryFromRequest(r)
|
||||
if err != nil {
|
||||
writeHistoryError(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
@@ -735,6 +762,13 @@ func writeHistoryJSON(w http.ResponseWriter, r *http.Request, value any) {
|
||||
_ = json.NewEncoder(w).Encode(value)
|
||||
}
|
||||
|
||||
func rawFrameQueryFromRequest(r *http.Request) (RawFrameQuery, error) {
|
||||
if r.Method == http.MethodPost {
|
||||
return parseRawFrameQueryBody(r)
|
||||
}
|
||||
return parseRawFrameQuery(r)
|
||||
}
|
||||
|
||||
func parseRawFrameQuery(r *http.Request) (RawFrameQuery, error) {
|
||||
values := r.URL.Query()
|
||||
limit, err := parseBoundedInt(values.Get("limit"), 20, 1, 500, "limit")
|
||||
@@ -773,6 +807,72 @@ func parseRawFrameQuery(r *http.Request) (RawFrameQuery, error) {
|
||||
return normalizeRawFrameQuery(query), nil
|
||||
}
|
||||
|
||||
func parseRawFrameQueryBody(r *http.Request) (RawFrameQuery, error) {
|
||||
defer r.Body.Close()
|
||||
decoder := json.NewDecoder(http.MaxBytesReader(nil, r.Body, 1<<20))
|
||||
decoder.DisallowUnknownFields()
|
||||
var body rawFrameQueryRequest
|
||||
if err := decoder.Decode(&body); err != nil {
|
||||
return RawFrameQuery{}, fmt.Errorf("invalid JSON body: %w", err)
|
||||
}
|
||||
var extra any
|
||||
if err := decoder.Decode(&extra); err != io.EOF {
|
||||
return RawFrameQuery{}, errors.New("invalid JSON body")
|
||||
}
|
||||
if body.VehicleKey == "" {
|
||||
body.VehicleKey = body.VehicleKeyAlt
|
||||
}
|
||||
if body.DeviceID == "" {
|
||||
body.DeviceID = body.DeviceIDAlt
|
||||
}
|
||||
if body.MessageID == "" {
|
||||
body.MessageID = body.MessageIDAlt
|
||||
}
|
||||
if body.OrderBy == "" {
|
||||
body.OrderBy = body.OrderByAlt
|
||||
}
|
||||
if body.DateFrom == "" {
|
||||
body.DateFrom = body.DateFromAlt
|
||||
}
|
||||
if body.DateTo == "" {
|
||||
body.DateTo = body.DateToAlt
|
||||
}
|
||||
limit, err := boundedInt(body.Limit, 20, 1, 500, "limit")
|
||||
if err != nil {
|
||||
return RawFrameQuery{}, err
|
||||
}
|
||||
offset, err := boundedInt(body.Offset, 0, 0, 1_000_000, "offset")
|
||||
if err != nil {
|
||||
return RawFrameQuery{}, err
|
||||
}
|
||||
query := RawFrameQuery{
|
||||
Protocol: body.Protocol,
|
||||
VehicleKey: body.VehicleKey,
|
||||
VIN: body.VIN,
|
||||
Phone: body.Phone,
|
||||
DeviceID: body.DeviceID,
|
||||
MessageID: body.MessageID,
|
||||
OrderBy: body.OrderBy,
|
||||
IncludeFields: body.IncludeFields,
|
||||
IncludePayload: body.IncludePayload,
|
||||
IncludeTotal: body.IncludeTotal,
|
||||
ParsedFields: append(body.Fields, body.ParsedFields...),
|
||||
DateFrom: body.DateFrom,
|
||||
DateTo: body.DateTo,
|
||||
Limit: limit,
|
||||
Offset: offset,
|
||||
}
|
||||
if !validDateTime(query.DateFrom) || !validDateTime(query.DateTo) {
|
||||
return RawFrameQuery{}, errors.New("dateFrom/dateTo must use YYYY-MM-DD or YYYY-MM-DD HH:mm:ss")
|
||||
}
|
||||
if strings.TrimSpace(query.MessageID) != "" {
|
||||
if _, ok := parseMessageID(query.MessageID); !ok {
|
||||
return RawFrameQuery{}, errors.New("messageId must be decimal or hex like 0x0200")
|
||||
}
|
||||
}
|
||||
return normalizeRawFrameQuery(query), nil
|
||||
}
|
||||
|
||||
func parseLocationQuery(r *http.Request) (LocationQuery, error) {
|
||||
values := r.URL.Query()
|
||||
limit, err := parseBoundedInt(values.Get("limit"), 20, 1, 500, "limit")
|
||||
@@ -798,6 +898,16 @@ func parseLocationQuery(r *http.Request) (LocationQuery, error) {
|
||||
return normalizeLocationQuery(query), nil
|
||||
}
|
||||
|
||||
func boundedInt(value int, fallback int, min int, max int, name string) (int, error) {
|
||||
if value == 0 {
|
||||
return fallback, nil
|
||||
}
|
||||
if value < min || value > max {
|
||||
return 0, fmt.Errorf("%s must be between %d and %d", name, min, max)
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func parseBoundedInt(raw string, fallback int, min int, max int, name string) (int, error) {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if raw == "" {
|
||||
|
||||
Reference in New Issue
Block a user