You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

189 lines
5.8 KiB

  1. // Copyright 2017 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package storage
  15. import (
  16. "context"
  17. "errors"
  18. "fmt"
  19. "regexp"
  20. "cloud.google.com/go/internal/trace"
  21. raw "google.golang.org/api/storage/v1"
  22. )
  23. // A Notification describes how to send Cloud PubSub messages when certain
  24. // events occur in a bucket.
  25. type Notification struct {
  26. //The ID of the notification.
  27. ID string
  28. // The ID of the topic to which this subscription publishes.
  29. TopicID string
  30. // The ID of the project to which the topic belongs.
  31. TopicProjectID string
  32. // Only send notifications about listed event types. If empty, send notifications
  33. // for all event types.
  34. // See https://cloud.google.com/storage/docs/pubsub-notifications#events.
  35. EventTypes []string
  36. // If present, only apply this notification configuration to object names that
  37. // begin with this prefix.
  38. ObjectNamePrefix string
  39. // An optional list of additional attributes to attach to each Cloud PubSub
  40. // message published for this notification subscription.
  41. CustomAttributes map[string]string
  42. // The contents of the message payload.
  43. // See https://cloud.google.com/storage/docs/pubsub-notifications#payload.
  44. PayloadFormat string
  45. }
  46. // Values for Notification.PayloadFormat.
  47. const (
  48. // Send no payload with notification messages.
  49. NoPayload = "NONE"
  50. // Send object metadata as JSON with notification messages.
  51. JSONPayload = "JSON_API_V1"
  52. )
  53. // Values for Notification.EventTypes.
  54. const (
  55. // Event that occurs when an object is successfully created.
  56. ObjectFinalizeEvent = "OBJECT_FINALIZE"
  57. // Event that occurs when the metadata of an existing object changes.
  58. ObjectMetadataUpdateEvent = "OBJECT_METADATA_UPDATE"
  59. // Event that occurs when an object is permanently deleted.
  60. ObjectDeleteEvent = "OBJECT_DELETE"
  61. // Event that occurs when the live version of an object becomes an
  62. // archived version.
  63. ObjectArchiveEvent = "OBJECT_ARCHIVE"
  64. )
  65. func toNotification(rn *raw.Notification) *Notification {
  66. n := &Notification{
  67. ID: rn.Id,
  68. EventTypes: rn.EventTypes,
  69. ObjectNamePrefix: rn.ObjectNamePrefix,
  70. CustomAttributes: rn.CustomAttributes,
  71. PayloadFormat: rn.PayloadFormat,
  72. }
  73. n.TopicProjectID, n.TopicID = parseNotificationTopic(rn.Topic)
  74. return n
  75. }
  76. var topicRE = regexp.MustCompile("^//pubsub.googleapis.com/projects/([^/]+)/topics/([^/]+)")
  77. // parseNotificationTopic extracts the project and topic IDs from from the full
  78. // resource name returned by the service. If the name is malformed, it returns
  79. // "?" for both IDs.
  80. func parseNotificationTopic(nt string) (projectID, topicID string) {
  81. matches := topicRE.FindStringSubmatch(nt)
  82. if matches == nil {
  83. return "?", "?"
  84. }
  85. return matches[1], matches[2]
  86. }
  87. func toRawNotification(n *Notification) *raw.Notification {
  88. return &raw.Notification{
  89. Id: n.ID,
  90. Topic: fmt.Sprintf("//pubsub.googleapis.com/projects/%s/topics/%s",
  91. n.TopicProjectID, n.TopicID),
  92. EventTypes: n.EventTypes,
  93. ObjectNamePrefix: n.ObjectNamePrefix,
  94. CustomAttributes: n.CustomAttributes,
  95. PayloadFormat: string(n.PayloadFormat),
  96. }
  97. }
  98. // AddNotification adds a notification to b. You must set n's TopicProjectID, TopicID
  99. // and PayloadFormat, and must not set its ID. The other fields are all optional. The
  100. // returned Notification's ID can be used to refer to it.
  101. func (b *BucketHandle) AddNotification(ctx context.Context, n *Notification) (ret *Notification, err error) {
  102. ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.AddNotification")
  103. defer func() { trace.EndSpan(ctx, err) }()
  104. if n.ID != "" {
  105. return nil, errors.New("storage: AddNotification: ID must not be set")
  106. }
  107. if n.TopicProjectID == "" {
  108. return nil, errors.New("storage: AddNotification: missing TopicProjectID")
  109. }
  110. if n.TopicID == "" {
  111. return nil, errors.New("storage: AddNotification: missing TopicID")
  112. }
  113. call := b.c.raw.Notifications.Insert(b.name, toRawNotification(n))
  114. setClientHeader(call.Header())
  115. if b.userProject != "" {
  116. call.UserProject(b.userProject)
  117. }
  118. rn, err := call.Context(ctx).Do()
  119. if err != nil {
  120. return nil, err
  121. }
  122. return toNotification(rn), nil
  123. }
  124. // Notifications returns all the Notifications configured for this bucket, as a map
  125. // indexed by notification ID.
  126. func (b *BucketHandle) Notifications(ctx context.Context) (n map[string]*Notification, err error) {
  127. ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Notifications")
  128. defer func() { trace.EndSpan(ctx, err) }()
  129. call := b.c.raw.Notifications.List(b.name)
  130. setClientHeader(call.Header())
  131. if b.userProject != "" {
  132. call.UserProject(b.userProject)
  133. }
  134. var res *raw.Notifications
  135. err = runWithRetry(ctx, func() error {
  136. res, err = call.Context(ctx).Do()
  137. return err
  138. })
  139. if err != nil {
  140. return nil, err
  141. }
  142. return notificationsToMap(res.Items), nil
  143. }
  144. func notificationsToMap(rns []*raw.Notification) map[string]*Notification {
  145. m := map[string]*Notification{}
  146. for _, rn := range rns {
  147. m[rn.Id] = toNotification(rn)
  148. }
  149. return m
  150. }
  151. // DeleteNotification deletes the notification with the given ID.
  152. func (b *BucketHandle) DeleteNotification(ctx context.Context, id string) (err error) {
  153. ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.DeleteNotification")
  154. defer func() { trace.EndSpan(ctx, err) }()
  155. call := b.c.raw.Notifications.Delete(b.name, id)
  156. setClientHeader(call.Header())
  157. if b.userProject != "" {
  158. call.UserProject(b.userProject)
  159. }
  160. return call.Context(ctx).Do()
  161. }