Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aos
GitHub Repository: aos/grafana-agent
Path: blob/main/pkg/river/encoding/encoding.go
4095 views
1
package encoding
2
3
import (
4
"encoding/json"
5
"fmt"
6
7
"github.com/grafana/agent/pkg/river/token/builder"
8
9
"github.com/grafana/agent/pkg/river/internal/value"
10
)
11
12
const attrType = "attr"
13
const objectType = "object"
14
15
// riverField is an interface that wraps the various concrete options for a river value.
16
type riverField interface {
17
hasValue() bool
18
}
19
20
// ConvertRiverBodyToJSON is used to convert a River body value to a JSON representation.
21
func ConvertRiverBodyToJSON(input interface{}) ([]byte, error) {
22
if input == nil {
23
return nil, nil
24
}
25
fields, err := getFieldsForBlockStruct(nil, input)
26
if err != nil {
27
return nil, err
28
}
29
if fields == nil {
30
// Make sure that the list of fields is never null.
31
fields = make([]interface{}, 0)
32
}
33
bb, err := json.Marshal(fields)
34
if err != nil {
35
return nil, err
36
}
37
return bb, nil
38
}
39
40
func isFieldValue(val value.Value) bool {
41
switch val.Type() {
42
case value.TypeNull, value.TypeNumber, value.TypeString, value.TypeBool, value.TypeFunction, value.TypeCapsule:
43
return true
44
}
45
return false
46
}
47
48
// convertValue is used to transform the underlying value of a river tag to a field
49
func convertValue(val value.Value) (*valueField, error) {
50
// Handle items that explicitly use tokenizer, these are always considered capsule values.
51
if tkn, ok := val.Interface().(builder.Tokenizer); ok {
52
tokens := tkn.RiverTokenize()
53
return &valueField{
54
Type: "capsule",
55
Value: tokens[0].Lit,
56
}, nil
57
}
58
switch val.Type() {
59
case value.TypeNull:
60
return &valueField{
61
Type: "null",
62
}, nil
63
case value.TypeNumber:
64
return &valueField{
65
Type: "number",
66
Value: val.Interface(),
67
}, nil
68
case value.TypeString:
69
return &valueField{
70
Type: "string",
71
Value: val.Text(),
72
}, nil
73
case value.TypeBool:
74
return &valueField{
75
Type: "bool",
76
Value: val.Bool(),
77
}, nil
78
case value.TypeArray:
79
return nil, fmt.Errorf("convertValue does not allow array types")
80
case value.TypeObject:
81
return nil, fmt.Errorf("convertValue does not allow object types")
82
case value.TypeFunction:
83
return &valueField{
84
Type: "function",
85
Value: val.Describe(),
86
}, nil
87
case value.TypeCapsule:
88
return &valueField{
89
Type: "capsule",
90
Value: val.Describe(),
91
}, nil
92
default:
93
return nil, fmt.Errorf("unable to convert %T", val.Interface())
94
}
95
}
96
97
func convertRiverValue(val value.Value) (riverField, error) {
98
switch {
99
case isFieldValue(val):
100
return convertValue(val)
101
case isRiverArray(val):
102
return newRiverArray(val)
103
case isRiverMapOrStruct(val):
104
return newRiverMap(val)
105
default:
106
return nil, fmt.Errorf("unknown value %T", val.Interface())
107
}
108
}
109
110
func isRiverArray(val value.Value) bool {
111
return val.Type() == value.TypeArray
112
}
113
114
func isRiverMapOrStruct(val value.Value) bool {
115
return val.Type() == value.TypeObject
116
}
117
118