raw_item.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package setting
  4. import (
  5. "fmt"
  6. "reflect"
  7. jsonv2 "github.com/go-json-experiment/json"
  8. "github.com/go-json-experiment/json/jsontext"
  9. "tailscale.com/types/opt"
  10. "tailscale.com/types/structs"
  11. "tailscale.com/util/syspolicy/pkey"
  12. )
  13. // RawItem contains a raw policy setting value as read from a policy store, or an
  14. // error if the requested setting could not be read from the store. As a special
  15. // case, it may also hold a value of the [Visibility], [PreferenceOption],
  16. // or [time.Duration] types. While the policy store interface does not support
  17. // these types natively, and the values of these types have to be unmarshalled
  18. // or converted from strings, these setting types predate the typed policy
  19. // hierarchies, and must be supported at this layer.
  20. type RawItem struct {
  21. _ structs.Incomparable
  22. data rawItemJSON
  23. }
  24. // rawItemJSON holds JSON-marshallable data for [RawItem].
  25. type rawItemJSON struct {
  26. Value RawValue `json:",omitzero"`
  27. Error *ErrorText `json:",omitzero"` // or nil
  28. Origin *Origin `json:",omitzero"` // or nil
  29. }
  30. // RawItemOf returns a [RawItem] with the specified value.
  31. func RawItemOf(value any) RawItem {
  32. return RawItemWith(value, nil, nil)
  33. }
  34. // RawItemWith returns a [RawItem] with the specified value, error and origin.
  35. func RawItemWith(value any, err *ErrorText, origin *Origin) RawItem {
  36. return RawItem{data: rawItemJSON{Value: RawValue{opt.ValueOf(value)}, Error: err, Origin: origin}}
  37. }
  38. // Value returns the value of the policy setting, or nil if the policy setting
  39. // is not configured, or an error occurred while reading it.
  40. func (i RawItem) Value() any {
  41. return i.data.Value.Get()
  42. }
  43. // Error returns the error that occurred when reading the policy setting,
  44. // or nil if no error occurred.
  45. func (i RawItem) Error() error {
  46. if i.data.Error != nil {
  47. return i.data.Error
  48. }
  49. return nil
  50. }
  51. // Origin returns an optional [Origin] indicating where the policy setting is
  52. // configured.
  53. func (i RawItem) Origin() *Origin {
  54. return i.data.Origin
  55. }
  56. // String implements [fmt.Stringer].
  57. func (i RawItem) String() string {
  58. var suffix string
  59. if i.data.Origin != nil {
  60. suffix = fmt.Sprintf(" - {%v}", i.data.Origin)
  61. }
  62. if i.data.Error != nil {
  63. return fmt.Sprintf("Error{%q}%s", i.data.Error.Error(), suffix)
  64. }
  65. return fmt.Sprintf("%v%s", i.data.Value.Value, suffix)
  66. }
  67. var (
  68. _ jsonv2.MarshalerTo = (*RawItem)(nil)
  69. _ jsonv2.UnmarshalerFrom = (*RawItem)(nil)
  70. )
  71. // MarshalJSONTo implements [jsonv2.MarshalerTo].
  72. func (i RawItem) MarshalJSONTo(out *jsontext.Encoder) error {
  73. return jsonv2.MarshalEncode(out, &i.data)
  74. }
  75. // UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom].
  76. func (i *RawItem) UnmarshalJSONFrom(in *jsontext.Decoder) error {
  77. return jsonv2.UnmarshalDecode(in, &i.data)
  78. }
  79. // MarshalJSON implements [json.Marshaler].
  80. func (i RawItem) MarshalJSON() ([]byte, error) {
  81. return jsonv2.Marshal(i) // uses MarshalJSONTo
  82. }
  83. // UnmarshalJSON implements [json.Unmarshaler].
  84. func (i *RawItem) UnmarshalJSON(b []byte) error {
  85. return jsonv2.Unmarshal(b, i) // uses UnmarshalJSONFrom
  86. }
  87. // RawValue represents a raw policy setting value read from a policy store.
  88. // It is JSON-marshallable and facilitates unmarshalling of JSON values
  89. // into corresponding policy setting types, with special handling for JSON numbers
  90. // (unmarshalled as float64) and JSON string arrays (unmarshalled as []string).
  91. // See also [RawValue.UnmarshalJSONFrom].
  92. type RawValue struct {
  93. opt.Value[any]
  94. }
  95. // RawValueType is a constraint that permits raw setting value types.
  96. type RawValueType interface {
  97. bool | uint64 | string | []string
  98. }
  99. // RawValueOf returns a new [RawValue] holding the specified value.
  100. func RawValueOf[T RawValueType](v T) RawValue {
  101. return RawValue{opt.ValueOf[any](v)}
  102. }
  103. var (
  104. _ jsonv2.MarshalerTo = (*RawValue)(nil)
  105. _ jsonv2.UnmarshalerFrom = (*RawValue)(nil)
  106. )
  107. // MarshalJSONTo implements [jsonv2.MarshalerTo].
  108. func (v RawValue) MarshalJSONTo(out *jsontext.Encoder) error {
  109. return jsonv2.MarshalEncode(out, v.Value)
  110. }
  111. // UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom] by attempting to unmarshal
  112. // a JSON value as one of the supported policy setting value types (bool, string, uint64, or []string),
  113. // based on the JSON value type. It fails if the JSON value is an object, if it's a JSON number that
  114. // cannot be represented as a uint64, or if a JSON array contains anything other than strings.
  115. func (v *RawValue) UnmarshalJSONFrom(in *jsontext.Decoder) error {
  116. var valPtr any
  117. switch k := in.PeekKind(); k {
  118. case 't', 'f':
  119. valPtr = new(bool)
  120. case '"':
  121. valPtr = new(string)
  122. case '0':
  123. valPtr = new(uint64) // unmarshal JSON numbers as uint64
  124. case '[', 'n':
  125. valPtr = new([]string) // unmarshal arrays as string slices
  126. case '{':
  127. return fmt.Errorf("unexpected token: %v", k)
  128. default:
  129. panic("unreachable")
  130. }
  131. if err := jsonv2.UnmarshalDecode(in, valPtr); err != nil {
  132. v.Value.Clear()
  133. return err
  134. }
  135. value := reflect.ValueOf(valPtr).Elem().Interface()
  136. v.Value = opt.ValueOf(value)
  137. return nil
  138. }
  139. // MarshalJSON implements [json.Marshaler].
  140. func (v RawValue) MarshalJSON() ([]byte, error) {
  141. return jsonv2.Marshal(v) // uses MarshalJSONTo
  142. }
  143. // UnmarshalJSON implements [json.Unmarshaler].
  144. func (v *RawValue) UnmarshalJSON(b []byte) error {
  145. return jsonv2.Unmarshal(b, v) // uses UnmarshalJSONFrom
  146. }
  147. // RawValues is a map of keyed setting values that can be read from a JSON.
  148. type RawValues map[pkey.Key]RawValue