183 lines
6.2 KiB
Go
183 lines
6.2 KiB
Go
/*
|
|
Copyright 2021 The Dapr Authors
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package servicebus
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"time"
|
|
|
|
azservicebus "github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus"
|
|
|
|
"github.com/dapr/components-contrib/bindings"
|
|
mdutils "github.com/dapr/components-contrib/metadata"
|
|
"github.com/dapr/components-contrib/pubsub"
|
|
"github.com/dapr/kit/ptr"
|
|
)
|
|
|
|
const (
|
|
// MessageKeyMessageID defines the metadata key for the message id.
|
|
MessageKeyMessageID = "MessageId" // read, write.
|
|
// MessageKeyMessageIDAlias is an alias for "MessageId" for write only, for backwards-compatibility
|
|
MessageKeyMessageIDAlias = "id"
|
|
|
|
// MessageKeyCorrelationID defines the metadata key for the correlation id.
|
|
MessageKeyCorrelationID = "CorrelationId" // read, write.
|
|
// MessageKeyCorrelationIDAlias is an alias for "CorrelationId" for write only, for backwards-compatibility
|
|
MessageKeyCorrelationIDAlias = "correlationID"
|
|
|
|
// MessageKeySessionID defines the metadata key for the session id.
|
|
MessageKeySessionID = "SessionId" // read, write.
|
|
|
|
// MessageKeyLabel defines the metadata key for the label.
|
|
MessageKeyLabel = "Label" // read, write.
|
|
|
|
// MessageKeyReplyTo defines the metadata key for the reply to value.
|
|
MessageKeyReplyTo = "ReplyTo" // read, write.
|
|
|
|
// MessageKeyTo defines the metadata key for the to value.
|
|
MessageKeyTo = "To" // read, write.
|
|
|
|
// MessageKeyPartitionKey defines the metadata key for the partition key.
|
|
MessageKeyPartitionKey = "PartitionKey" // read, write.
|
|
|
|
// MessageKeyContentType defines the metadata key for the content type.
|
|
MessageKeyContentType = "ContentType" // read, write.
|
|
|
|
// MessageKeyDeliveryCount defines the metadata key for the delivery count.
|
|
MessageKeyDeliveryCount = "DeliveryCount" // read.
|
|
|
|
// MessageKeyLockedUntilUtc defines the metadata key for the locked until utc value.
|
|
MessageKeyLockedUntilUtc = "LockedUntilUtc" // read.
|
|
|
|
// MessageKeyLockToken defines the metadata key for the lock token.
|
|
MessageKeyLockToken = "LockToken" // read.
|
|
|
|
// MessageKeyEnqueuedTimeUtc defines the metadata key for the enqueued time utc value.
|
|
MessageKeyEnqueuedTimeUtc = "EnqueuedTimeUtc" // read.
|
|
|
|
// MessageKeySequenceNumber defines the metadata key for the sequence number.
|
|
MessageKeySequenceNumber = "SequenceNumber" // read.
|
|
|
|
// MessageKeyScheduledEnqueueTimeUtc defines the metadata key for the scheduled enqueue time utc value.
|
|
MessageKeyScheduledEnqueueTimeUtc = "ScheduledEnqueueTimeUtc" // read, write.
|
|
|
|
// MessageKeyReplyToSessionID defines the metadata key for the reply to session id.
|
|
// Currently unused.
|
|
MessageKeyReplyToSessionID = "ReplyToSessionId" // read, write.
|
|
)
|
|
|
|
// NewASBMessageFromPubsubRequest builds a new Azure Service Bus message from a PublishRequest.
|
|
func NewASBMessageFromPubsubRequest(req *pubsub.PublishRequest) (*azservicebus.Message, error) {
|
|
asbMsg := &azservicebus.Message{
|
|
Body: req.Data,
|
|
}
|
|
|
|
err := addMetadataToMessage(asbMsg, req.Metadata)
|
|
return asbMsg, err
|
|
}
|
|
|
|
// NewASBMessageFromBulkMessageEntry builds a new Azure Service Bus message from a BulkMessageEntry.
|
|
func NewASBMessageFromBulkMessageEntry(entry pubsub.BulkMessageEntry) (*azservicebus.Message, error) {
|
|
asbMsg := &azservicebus.Message{
|
|
Body: entry.Event,
|
|
ContentType: &entry.ContentType,
|
|
}
|
|
|
|
err := addMetadataToMessage(asbMsg, entry.Metadata)
|
|
return asbMsg, err
|
|
}
|
|
|
|
// NewASBMessageFromInvokeRequest builds a new Azure Service Bus message from a binding's Invoke request.
|
|
func NewASBMessageFromInvokeRequest(req *bindings.InvokeRequest) (*azservicebus.Message, error) {
|
|
asbMsg := &azservicebus.Message{
|
|
Body: req.Data,
|
|
}
|
|
|
|
err := addMetadataToMessage(asbMsg, req.Metadata)
|
|
return asbMsg, err
|
|
}
|
|
|
|
// Adds metadata to the message.
|
|
// Reference for Azure Service Bus specific properties: https://docs.microsoft.com/en-us/rest/api/servicebus/message-headers-and-properties#message-headers
|
|
func addMetadataToMessage(asbMsg *azservicebus.Message, metadata map[string]string) error {
|
|
asbMsg.ApplicationProperties = make(map[string]interface{}, len(metadata))
|
|
|
|
for k, v := range metadata {
|
|
// Note: do not just do &v because we're in a loop
|
|
if v == "" && k != MessageKeySessionID { // blank session ID is valid
|
|
continue
|
|
}
|
|
|
|
switch k {
|
|
// Common keys
|
|
case mdutils.TTLMetadataKey:
|
|
// Ignore v here and use TryGetTTL for the validation it performs
|
|
ttl, ok, _ := mdutils.TryGetTTL(metadata)
|
|
if ok {
|
|
asbMsg.TimeToLive = &ttl
|
|
}
|
|
|
|
// Keys with aliases
|
|
case MessageKeyMessageID, MessageKeyMessageIDAlias:
|
|
if asbMsg.MessageID == nil {
|
|
asbMsg.MessageID = ptr.Of(v)
|
|
}
|
|
|
|
case MessageKeyCorrelationID, MessageKeyCorrelationIDAlias:
|
|
if asbMsg.CorrelationID == nil {
|
|
asbMsg.CorrelationID = ptr.Of(v)
|
|
}
|
|
|
|
// String types
|
|
case MessageKeySessionID:
|
|
asbMsg.SessionID = ptr.Of(v)
|
|
case MessageKeyLabel:
|
|
asbMsg.Subject = ptr.Of(v)
|
|
case MessageKeyReplyTo:
|
|
asbMsg.ReplyTo = ptr.Of(v)
|
|
case MessageKeyTo:
|
|
asbMsg.To = ptr.Of(v)
|
|
case MessageKeyPartitionKey:
|
|
asbMsg.PartitionKey = ptr.Of(v)
|
|
case MessageKeyContentType:
|
|
asbMsg.ContentType = ptr.Of(v)
|
|
|
|
// Time
|
|
case MessageKeyScheduledEnqueueTimeUtc:
|
|
timeVal, err := time.Parse(http.TimeFormat, v)
|
|
if err == nil {
|
|
asbMsg.ScheduledEnqueueTime = &timeVal
|
|
} else {
|
|
timeVal, err2 := time.Parse(time.RFC3339, v)
|
|
if err2 == nil {
|
|
asbMsg.ScheduledEnqueueTime = &timeVal
|
|
} else {
|
|
return fmt.Errorf("invalid time format for %s; expected HTTP time format or RFC3339", k)
|
|
}
|
|
}
|
|
|
|
// Fallback: set as application property
|
|
default:
|
|
asbMsg.ApplicationProperties[k] = v
|
|
}
|
|
}
|
|
|
|
if asbMsg.PartitionKey != nil && asbMsg.SessionID != nil && *asbMsg.PartitionKey != *asbMsg.SessionID {
|
|
return fmt.Errorf("session id %s and partition key %s should be equal when both present", *asbMsg.SessionID, *asbMsg.PartitionKey)
|
|
}
|
|
|
|
return nil
|
|
}
|