decoder.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. package exporter
  2. import (
  3. "bytes"
  4. "compress/gzip"
  5. "encoding"
  6. "fmt"
  7. "io"
  8. "github.com/opencost/opencost/core/pkg/util/json"
  9. "google.golang.org/protobuf/proto"
  10. )
  11. type Decoder[T any] func([]byte) (*T, error)
  12. type StreamingDecoder[T any] func(io.Reader) (*T, error)
  13. // BinaryMarshalerPtr[T] is a generic constraint to ensure types passed to the decoder implement
  14. // encoding.BinaryUnmarshaler and are pointers to T.
  15. type BinaryUnmarshalerPtr[T any] interface {
  16. encoding.BinaryUnmarshaler
  17. *T
  18. }
  19. // BinaryUnmarshalWithReaderPtr[T] is a generic constraint to ensure types passed to the decoder
  20. // implement an unmarshal from io.Reader method.
  21. type BinaryUnmarshalWithReaderPtr[T any] interface {
  22. UnmarshalBinaryFromReader(reader io.Reader) error
  23. *T
  24. }
  25. func BingenDecoder[T any, U BinaryUnmarshalerPtr[T]](data []byte) (*T, error) {
  26. var set U = new(T)
  27. err := set.UnmarshalBinary(data)
  28. if err != nil {
  29. return nil, fmt.Errorf("failed to decode bingen: %w", err)
  30. }
  31. return set, nil
  32. }
  33. func StreamingBingenDecoder[T any, U BinaryUnmarshalWithReaderPtr[T]](reader io.Reader) (*T, error) {
  34. var set U = new(T)
  35. err := set.UnmarshalBinaryFromReader(reader)
  36. if err != nil {
  37. return nil, fmt.Errorf("failed to decode bingen: %w", err)
  38. }
  39. return set, nil
  40. }
  41. func JSONDecoder[T any](data []byte) (*T, error) {
  42. var instance = new(T)
  43. err := json.Unmarshal(data, instance)
  44. if err != nil {
  45. return nil, fmt.Errorf("failed to decode json: %w", err)
  46. }
  47. return instance, nil
  48. }
  49. func ProtobufDecoder[T any, U ProtoMessagePtr[T]](data []byte) (*T, error) {
  50. var message U = new(T)
  51. err := proto.Unmarshal(data, message)
  52. if err != nil {
  53. return nil, fmt.Errorf("failed to decode protobuf message: %w", err)
  54. }
  55. return message, nil
  56. }
  57. func GetGzipDecoder[T any](decoder Decoder[T]) Decoder[T] {
  58. return func(data []byte) (*T, error) {
  59. // Check for gzip compression. Ref: https://www.ietf.org/rfc/rfc1952.txt Page 5
  60. if len(data) > 2 && data[0] == 0x1F && data[1] == 0x8B {
  61. buf := bytes.NewBuffer(data)
  62. reader, err := gzip.NewReader(buf)
  63. if err != nil {
  64. return nil, fmt.Errorf("failed to decompress gzip: %w", err)
  65. }
  66. defer reader.Close()
  67. decompressed, err := io.ReadAll(reader)
  68. if err != nil {
  69. return nil, fmt.Errorf("failed to read decompressed gzip: %w", err)
  70. }
  71. data = decompressed
  72. }
  73. instance, err := decoder(data)
  74. if err != nil {
  75. return nil, fmt.Errorf("failed to decode decompress gzip data: %w", err)
  76. }
  77. return instance, nil
  78. }
  79. }