123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- package redriver
- import (
- "encoding/base64"
- "errors"
- "fmt"
- "net/url"
- "strconv"
- "strings"
- "github.com/aws/aws-sdk-go-v2/aws"
- "github.com/aws/aws-sdk-go-v2/aws/arn"
- "github.com/aws/aws-sdk-go-v2/service/sqs/types"
- )
- func ARNFromURL(qURL string) (arn.ARN, error) {
- a := arn.ARN{}
- u, err := url.Parse(qURL)
- if err != nil {
- return a, fmt.Errorf("queue URL %q is not a valid URL: %w", qURL, err)
- }
- path := u.EscapedPath()
- pathParts := strings.Split(strings.Trim(path, "/"), "/")
- if len(pathParts) != 2 {
- return a, fmt.Errorf("queue path %q does not have exactly 2 parts", path)
- }
- hostParts := strings.Split(u.Host, ".")
- if len(hostParts) != 4 { // <service>.<region>.amazonaws.com
- return a, fmt.Errorf("queue host %q does not have exactly 4 parts", u.Host)
- }
- a = arn.ARN{
- Partition: "aws",
- Service: hostParts[0],
- Region: hostParts[1],
- AccountID: pathParts[0],
- Resource: pathParts[1],
- }
- return a, nil
- }
- func NameFromURL(qURL string) (name string, err error) {
- u, err := url.Parse(qURL)
- if err != nil {
- return "", fmt.Errorf("queue URL %q is not a valid URL: %w", qURL, err)
- }
- path := u.EscapedPath()
- parts := strings.Split(strings.Trim(path, "/"), "/")
- if len(parts) != 2 {
- return "", fmt.Errorf("queue path %q does not have exactly 2 parts", path)
- }
- return parts[1], nil
- }
- func NameFromARN(qARN arn.ARN) string {
- return qARN.Resource
- }
- func NameFromARNString(qARN string) (name string, err error) {
- a, err := arn.Parse(qARN)
- if err != nil {
- return "", fmt.Errorf("queue \"ARN\" %q is not an valid ARN", qARN)
- }
- return NameFromARN(a), nil
- }
- func URLFromARNString(qARN string) (name string, err error) {
- a, err := arn.Parse(qARN)
- if err != nil {
- return "", fmt.Errorf("queue \"ARN\" %q is not an valid ARN", qARN)
- }
- return URLFromARN(a)
- }
- func URLFromARN(qARN arn.ARN) (name string, err error) {
- path, err := url.JoinPath("/", qARN.AccountID, qARN.Resource)
- if err != nil {
- return "", fmt.Errorf("incorrect queue ARN: %w", err)
- }
- u := url.URL{
- Scheme: "https",
- Host: fmt.Sprintf("%s.%s.%s", qARN.Service, qARN.Region, "amazonaws.com"),
- Path: path,
- }
- return u.String(), nil
- }
- // MessageAttributeValuesFromJSONable attempts to convert a plain JSON to Message.MessageAttributes field value.
- //
- // FIXME we should not be storing those maps in JSONable form anyway, because that loses information.
- func MessageAttributeValuesFromJSONable(in map[string]any) (map[string]types.MessageAttributeValue, error) {
- m := make(map[string]types.MessageAttributeValue, len(in))
- for k, v := range in {
- mav := types.MessageAttributeValue{StringValue: aws.String(fmt.Sprint(v))}
- switch v.(type) {
- case int:
- mav.DataType = aws.String("Number")
- case string:
- mav.DataType = aws.String("String")
- default:
- return nil, fmt.Errorf("message attributes contain a non-convertible value: %T", v)
- }
- m[k] = mav
- }
- return m, nil
- }
- func JSONableFromMessageAttributeValues(m map[string]types.MessageAttributeValue) (map[string]any, error) {
- j := make(map[string]any)
- for name, attr := range m {
- if attr.DataType == nil {
- return nil, errors.New("empty DataType on message attribute value")
- }
- switch t := *attr.DataType; t {
- case "String":
- if attr.StringValue == nil {
- return nil, fmt.Errorf("nil string value on string field %q", name)
- }
- j[name] = *attr.StringValue
- case "Number":
- if attr.StringValue == nil {
- return nil, fmt.Errorf("nil string value on number field %q", name)
- }
- n, err := strconv.Atoi(*attr.StringValue)
- if err != nil {
- return nil, fmt.Errorf("invalid numeric string on number field %q", name)
- }
- j[name] = n
- case "Binary":
- if attr.BinaryValue == nil {
- j[name] = nil
- continue
- }
- in := attr.BinaryValue
- out := make([]byte, base64.StdEncoding.DecodedLen(len(in)))
- _, err := base64.StdEncoding.Decode(out, in)
- if err != nil {
- return nil, fmt.Errorf("failed decoding binary field %q: %w", name, err)
- }
- j[name] = out
- default:
- return nil, fmt.Errorf("unimplemented DataType %q", t)
- }
- }
- return j, nil
- }
|