package contracts import ( "bytes" "encoding/json" "fmt" "io" "time" ) const MaxPayloadBytes = 16 * 1024 // Decode bounds input, rejects unknown fields, requires exactly one JSON value, // and validates the decoded MQTT contract against its parsed topic. func Decode[T MQTTMessage](payload []byte, topic Topic, now time.Time) (T, error) { var value T if len(payload) > MaxPayloadBytes { return value, fmt.Errorf("payload exceeds %d bytes", MaxPayloadBytes) } decoder := json.NewDecoder(bytes.NewReader(payload)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, fmt.Errorf("decode JSON: %w", err) } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, fmt.Errorf("payload contains more than one JSON value") } return value, fmt.Errorf("trailing data after JSON value: %w", err) } if err := value.Validate(topic, now); err != nil { return value, fmt.Errorf("validate message: %w", err) } return value, nil }