converters.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. package redriver
  2. import (
  3. "encoding/base64"
  4. "errors"
  5. "fmt"
  6. "net/url"
  7. "strconv"
  8. "strings"
  9. "github.com/aws/aws-sdk-go-v2/aws/arn"
  10. "github.com/aws/aws-sdk-go-v2/service/sqs/types"
  11. )
  12. func ARNFromURL(qURL string) (arn.ARN, error) {
  13. a := arn.ARN{}
  14. u, err := url.Parse(qURL)
  15. if err != nil {
  16. return a, fmt.Errorf("queue URL %q is not a valid URL: %w", qURL, err)
  17. }
  18. path := u.EscapedPath()
  19. pathParts := strings.Split(strings.Trim(path, "/"), "/")
  20. if len(pathParts) != 2 {
  21. return a, fmt.Errorf("queue path %q does not have exactly 2 parts", path)
  22. }
  23. hostParts := strings.Split(u.Host, ".")
  24. if len(hostParts) != 4 { // <service>.<region>.amazonaws.com
  25. return a, fmt.Errorf("queue host %q does not have exactly 4 parts", u.Host)
  26. }
  27. a = arn.ARN{
  28. Partition: "aws",
  29. Service: hostParts[0],
  30. Region: hostParts[1],
  31. AccountID: pathParts[0],
  32. Resource: pathParts[1],
  33. }
  34. return a, nil
  35. }
  36. func NameFromURL(qURL string) (name string, err error) {
  37. u, err := url.Parse(qURL)
  38. if err != nil {
  39. return "", fmt.Errorf("queue URL %q is not a valid URL: %w", qURL, err)
  40. }
  41. path := u.EscapedPath()
  42. parts := strings.Split(strings.Trim(path, "/"), "/")
  43. if len(parts) != 2 {
  44. return "", fmt.Errorf("queue path %q does not have exactly 2 parts", path)
  45. }
  46. return parts[1], nil
  47. }
  48. func NameFromARN(qARN arn.ARN) string {
  49. return qARN.Resource
  50. }
  51. func NameFromARNString(qARN string) (name string, err error) {
  52. a, err := arn.Parse(qARN)
  53. if err != nil {
  54. return "", fmt.Errorf("queue \"ARN\" %q is not an valid ARN", qARN)
  55. }
  56. return NameFromARN(a), nil
  57. }
  58. func URLFromARNString(qARN string) (name string, err error) {
  59. a, err := arn.Parse(qARN)
  60. if err != nil {
  61. return "", fmt.Errorf("queue \"ARN\" %q is not an valid ARN", qARN)
  62. }
  63. return URLFromARN(a)
  64. }
  65. func URLFromARN(qARN arn.ARN) (name string, err error) {
  66. path, err := url.JoinPath("/", qARN.AccountID, qARN.Resource)
  67. if err != nil {
  68. return "", fmt.Errorf("incorrect queue ARN: %w", err)
  69. }
  70. u := url.URL{
  71. Scheme: "https",
  72. Host: fmt.Sprintf("%s.%s.%s", qARN.Service, qARN.Region, "amazonaws.com"),
  73. Path: path,
  74. }
  75. return u.String(), nil
  76. }
  77. func JSONableFromMessageAttributeValues(m map[string]types.MessageAttributeValue) (map[string]any, error) {
  78. j := make(map[string]any)
  79. for name, attr := range m {
  80. if attr.DataType == nil {
  81. return nil, errors.New("empty DataType on message attribute value")
  82. }
  83. switch t := *attr.DataType; t {
  84. case "String":
  85. if attr.StringValue == nil {
  86. return nil, fmt.Errorf("nil string value on string field %q", name)
  87. }
  88. j[name] = *attr.StringValue
  89. case "Number":
  90. if attr.StringValue == nil {
  91. return nil, fmt.Errorf("nil string value on number field %q", name)
  92. }
  93. n, err := strconv.Atoi(*attr.StringValue)
  94. if err != nil {
  95. return nil, fmt.Errorf("invalid numeric string on number field %q", name)
  96. }
  97. j[name] = n
  98. case "Binary":
  99. if attr.BinaryValue == nil {
  100. j[name] = nil
  101. continue
  102. }
  103. in := attr.BinaryValue
  104. out := make([]byte, base64.StdEncoding.DecodedLen(len(in)))
  105. _, err := base64.StdEncoding.Decode(out, in)
  106. if err != nil {
  107. return nil, fmt.Errorf("failed decoding binary field %q: %w", name, err)
  108. }
  109. j[name] = out
  110. default:
  111. return nil, fmt.Errorf("unimplemented DataType %q", t)
  112. }
  113. }
  114. return j, nil
  115. }