mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
313 lines
7.9 KiB
Go
313 lines
7.9 KiB
Go
package object
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"fmt"
|
|
"unsafe"
|
|
|
|
jsoniter "github.com/json-iterator/go"
|
|
)
|
|
|
|
func init() { //nolint:gochecknoinits
|
|
jsoniter.RegisterTypeEncoder("object.ObjectSearchResult", &searchResultCodec{})
|
|
jsoniter.RegisterTypeEncoder("object.WriteObjectResponse", &writeResponseCodec{})
|
|
jsoniter.RegisterTypeEncoder("object.ReadObjectResponse", &readResponseCodec{})
|
|
|
|
jsoniter.RegisterTypeEncoder("object.RawObject", &rawObjectCodec{})
|
|
jsoniter.RegisterTypeDecoder("object.RawObject", &rawObjectCodec{})
|
|
}
|
|
|
|
func writeRawJson(stream *jsoniter.Stream, val []byte) {
|
|
if json.Valid(val) {
|
|
_, _ = stream.Write(val)
|
|
} else {
|
|
stream.WriteString(string(val))
|
|
}
|
|
}
|
|
|
|
// Unlike the standard JSON marshal, this will write bytes as JSON when it can
|
|
type rawObjectCodec struct{}
|
|
|
|
func (obj *RawObject) MarshalJSON() ([]byte, error) {
|
|
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
|
return json.Marshal(obj)
|
|
}
|
|
|
|
// UnmarshalJSON will read JSON into a RawObject
|
|
func (obj *RawObject) UnmarshalJSON(b []byte) error {
|
|
if obj == nil {
|
|
return fmt.Errorf("unexpected nil for raw objcet")
|
|
}
|
|
iter := jsoniter.ParseBytes(jsoniter.ConfigDefault, b)
|
|
readRawObject(iter, obj)
|
|
return iter.Error
|
|
}
|
|
|
|
func (codec *rawObjectCodec) IsEmpty(ptr unsafe.Pointer) bool {
|
|
f := (*RawObject)(ptr)
|
|
return f.UID == "" && f.Body == nil
|
|
}
|
|
|
|
func (codec *rawObjectCodec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
|
|
obj := (*RawObject)(ptr)
|
|
stream.WriteObjectStart()
|
|
stream.WriteObjectField("UID")
|
|
stream.WriteString(obj.UID)
|
|
|
|
if obj.Kind != "" {
|
|
stream.WriteMore()
|
|
stream.WriteObjectField("kind")
|
|
stream.WriteString(obj.Kind)
|
|
}
|
|
if obj.Version != "" {
|
|
stream.WriteMore()
|
|
stream.WriteObjectField("version")
|
|
stream.WriteString(obj.Version)
|
|
}
|
|
if obj.Created > 0 {
|
|
stream.WriteMore()
|
|
stream.WriteObjectField("created")
|
|
stream.WriteInt64(obj.Created)
|
|
}
|
|
if obj.Updated > 0 {
|
|
stream.WriteMore()
|
|
stream.WriteObjectField("updated")
|
|
stream.WriteInt64(obj.Updated)
|
|
}
|
|
if obj.CreatedBy != "" {
|
|
stream.WriteMore()
|
|
stream.WriteObjectField("createdBy")
|
|
stream.WriteString(obj.CreatedBy)
|
|
}
|
|
if obj.UpdatedBy != "" {
|
|
stream.WriteMore()
|
|
stream.WriteObjectField("updatedBy")
|
|
stream.WriteString(obj.UpdatedBy)
|
|
}
|
|
if obj.Body != nil {
|
|
stream.WriteMore()
|
|
if json.Valid(obj.Body) {
|
|
stream.WriteObjectField("body")
|
|
stream.WriteRaw(string(obj.Body)) // works for strings
|
|
} else {
|
|
sEnc := base64.StdEncoding.EncodeToString(obj.Body)
|
|
stream.WriteObjectField("body_base64")
|
|
stream.WriteString(sEnc) // works for strings
|
|
}
|
|
}
|
|
if obj.ETag != "" {
|
|
stream.WriteMore()
|
|
stream.WriteObjectField("etag")
|
|
stream.WriteString(obj.ETag)
|
|
}
|
|
if obj.Size > 0 {
|
|
stream.WriteMore()
|
|
stream.WriteObjectField("size")
|
|
stream.WriteInt64(obj.Size)
|
|
}
|
|
|
|
if obj.Sync != nil {
|
|
stream.WriteMore()
|
|
stream.WriteObjectField("sync")
|
|
stream.WriteVal(obj.Sync)
|
|
}
|
|
|
|
stream.WriteObjectEnd()
|
|
}
|
|
|
|
func (codec *rawObjectCodec) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
|
|
*(*RawObject)(ptr) = RawObject{}
|
|
raw := (*RawObject)(ptr)
|
|
readRawObject(iter, raw)
|
|
}
|
|
|
|
func readRawObject(iter *jsoniter.Iterator, raw *RawObject) {
|
|
for l1Field := iter.ReadObject(); l1Field != ""; l1Field = iter.ReadObject() {
|
|
switch l1Field {
|
|
case "UID":
|
|
raw.UID = iter.ReadString()
|
|
case "kind":
|
|
raw.Kind = iter.ReadString()
|
|
case "updated":
|
|
raw.Updated = iter.ReadInt64()
|
|
case "updatedBy":
|
|
raw.UpdatedBy = iter.ReadString()
|
|
case "created":
|
|
raw.Created = iter.ReadInt64()
|
|
case "createdBy":
|
|
raw.CreatedBy = iter.ReadString()
|
|
case "size":
|
|
raw.Size = iter.ReadInt64()
|
|
case "etag":
|
|
raw.ETag = iter.ReadString()
|
|
case "version":
|
|
raw.Version = iter.ReadString()
|
|
case "sync":
|
|
raw.Sync = &RawObjectSyncInfo{}
|
|
iter.ReadVal(raw.Sync)
|
|
|
|
case "body":
|
|
var val interface{}
|
|
iter.ReadVal(&val) // ??? is there a smarter way to just keep the underlying bytes without read+marshal
|
|
body, err := json.Marshal(val)
|
|
if err != nil {
|
|
iter.ReportError("raw object", "error creating json from body")
|
|
return
|
|
}
|
|
raw.Body = body
|
|
|
|
case "body_base64":
|
|
val := iter.ReadString()
|
|
body, err := base64.StdEncoding.DecodeString(val)
|
|
if err != nil {
|
|
iter.ReportError("raw object", "error decoding base64 body")
|
|
return
|
|
}
|
|
raw.Body = body
|
|
|
|
default:
|
|
iter.ReportError("raw object", "unexpected field: "+l1Field)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// Unlike the standard JSON marshal, this will write bytes as JSON when it can
|
|
type readResponseCodec struct{}
|
|
|
|
func (obj *ReadObjectResponse) MarshalJSON() ([]byte, error) {
|
|
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
|
return json.Marshal(obj)
|
|
}
|
|
|
|
func (codec *readResponseCodec) IsEmpty(ptr unsafe.Pointer) bool {
|
|
f := (*ReadObjectResponse)(ptr)
|
|
return f == nil
|
|
}
|
|
|
|
func (codec *readResponseCodec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
|
|
obj := (*ReadObjectResponse)(ptr)
|
|
stream.WriteObjectStart()
|
|
stream.WriteObjectField("object")
|
|
stream.WriteVal(obj.Object)
|
|
|
|
if len(obj.SummaryJson) > 0 {
|
|
stream.WriteMore()
|
|
stream.WriteObjectField("summary")
|
|
writeRawJson(stream, obj.SummaryJson)
|
|
}
|
|
|
|
stream.WriteObjectEnd()
|
|
}
|
|
|
|
// Unlike the standard JSON marshal, this will write bytes as JSON when it can
|
|
type searchResultCodec struct{}
|
|
|
|
func (obj *ObjectSearchResult) MarshalJSON() ([]byte, error) {
|
|
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
|
return json.Marshal(obj)
|
|
}
|
|
|
|
func (codec *searchResultCodec) IsEmpty(ptr unsafe.Pointer) bool {
|
|
f := (*ObjectSearchResult)(ptr)
|
|
return f.UID == "" && f.Body == nil
|
|
}
|
|
|
|
func (codec *searchResultCodec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
|
|
obj := (*ObjectSearchResult)(ptr)
|
|
stream.WriteObjectStart()
|
|
stream.WriteObjectField("UID")
|
|
stream.WriteString(obj.UID)
|
|
|
|
if obj.Kind != "" {
|
|
stream.WriteMore()
|
|
stream.WriteObjectField("kind")
|
|
stream.WriteString(obj.Kind)
|
|
}
|
|
if obj.Name != "" {
|
|
stream.WriteMore()
|
|
stream.WriteObjectField("name")
|
|
stream.WriteString(obj.Name)
|
|
}
|
|
if obj.Description != "" {
|
|
stream.WriteMore()
|
|
stream.WriteObjectField("description")
|
|
stream.WriteString(obj.Description)
|
|
}
|
|
if obj.Updated > 0 {
|
|
stream.WriteMore()
|
|
stream.WriteObjectField("updated")
|
|
stream.WriteInt64(obj.Updated)
|
|
}
|
|
if obj.UpdatedBy != "" {
|
|
stream.WriteMore()
|
|
stream.WriteObjectField("updatedBy")
|
|
stream.WriteVal(obj.UpdatedBy)
|
|
}
|
|
if obj.Body != nil {
|
|
stream.WriteMore()
|
|
if json.Valid(obj.Body) {
|
|
stream.WriteObjectField("body")
|
|
_, _ = stream.Write(obj.Body) // works for strings
|
|
} else {
|
|
stream.WriteObjectField("body_base64")
|
|
stream.WriteVal(obj.Body) // works for strings
|
|
}
|
|
}
|
|
if obj.Labels != nil {
|
|
stream.WriteMore()
|
|
stream.WriteObjectField("labels")
|
|
stream.WriteVal(obj.Labels)
|
|
}
|
|
if obj.ErrorJson != nil {
|
|
stream.WriteMore()
|
|
stream.WriteObjectField("error")
|
|
writeRawJson(stream, obj.ErrorJson)
|
|
}
|
|
if obj.FieldsJson != nil {
|
|
stream.WriteMore()
|
|
stream.WriteObjectField("fields")
|
|
writeRawJson(stream, obj.FieldsJson)
|
|
}
|
|
|
|
stream.WriteObjectEnd()
|
|
}
|
|
|
|
// Unlike the standard JSON marshal, this will write bytes as JSON when it can
|
|
type writeResponseCodec struct{}
|
|
|
|
func (obj *WriteObjectResponse) MarshalJSON() ([]byte, error) {
|
|
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
|
return json.Marshal(obj)
|
|
}
|
|
|
|
func (codec *writeResponseCodec) IsEmpty(ptr unsafe.Pointer) bool {
|
|
f := (*WriteObjectResponse)(ptr)
|
|
return f == nil
|
|
}
|
|
|
|
func (codec *writeResponseCodec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
|
|
obj := (*WriteObjectResponse)(ptr)
|
|
stream.WriteObjectStart()
|
|
stream.WriteObjectField("status")
|
|
stream.WriteString(obj.Status.String())
|
|
|
|
if obj.Error != nil {
|
|
stream.WriteMore()
|
|
stream.WriteObjectField("error")
|
|
stream.WriteVal(obj.Error)
|
|
}
|
|
if obj.Object != nil {
|
|
stream.WriteMore()
|
|
stream.WriteObjectField("object")
|
|
stream.WriteVal(obj.Object)
|
|
}
|
|
if len(obj.SummaryJson) > 0 {
|
|
stream.WriteMore()
|
|
stream.WriteObjectField("summary")
|
|
writeRawJson(stream, obj.SummaryJson)
|
|
}
|
|
stream.WriteObjectEnd()
|
|
}
|