]>
Commit | Line | Data |
---|---|---|
107c1cdb ND |
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 | ||
15 | package storage | |
16 | ||
17 | import ( | |
18 | "context" | |
19 | "errors" | |
20 | "fmt" | |
21 | "regexp" | |
22 | ||
23 | "cloud.google.com/go/internal/trace" | |
24 | raw "google.golang.org/api/storage/v1" | |
25 | ) | |
26 | ||
27 | // A Notification describes how to send Cloud PubSub messages when certain | |
28 | // events occur in a bucket. | |
29 | type Notification struct { | |
30 | //The ID of the notification. | |
31 | ID string | |
32 | ||
33 | // The ID of the topic to which this subscription publishes. | |
34 | TopicID string | |
35 | ||
36 | // The ID of the project to which the topic belongs. | |
37 | TopicProjectID string | |
38 | ||
39 | // Only send notifications about listed event types. If empty, send notifications | |
40 | // for all event types. | |
41 | // See https://cloud.google.com/storage/docs/pubsub-notifications#events. | |
42 | EventTypes []string | |
43 | ||
44 | // If present, only apply this notification configuration to object names that | |
45 | // begin with this prefix. | |
46 | ObjectNamePrefix string | |
47 | ||
48 | // An optional list of additional attributes to attach to each Cloud PubSub | |
49 | // message published for this notification subscription. | |
50 | CustomAttributes map[string]string | |
51 | ||
52 | // The contents of the message payload. | |
53 | // See https://cloud.google.com/storage/docs/pubsub-notifications#payload. | |
54 | PayloadFormat string | |
55 | } | |
56 | ||
57 | // Values for Notification.PayloadFormat. | |
58 | const ( | |
59 | // Send no payload with notification messages. | |
60 | NoPayload = "NONE" | |
61 | ||
62 | // Send object metadata as JSON with notification messages. | |
63 | JSONPayload = "JSON_API_V1" | |
64 | ) | |
65 | ||
66 | // Values for Notification.EventTypes. | |
67 | const ( | |
68 | // Event that occurs when an object is successfully created. | |
69 | ObjectFinalizeEvent = "OBJECT_FINALIZE" | |
70 | ||
71 | // Event that occurs when the metadata of an existing object changes. | |
72 | ObjectMetadataUpdateEvent = "OBJECT_METADATA_UPDATE" | |
73 | ||
74 | // Event that occurs when an object is permanently deleted. | |
75 | ObjectDeleteEvent = "OBJECT_DELETE" | |
76 | ||
77 | // Event that occurs when the live version of an object becomes an | |
78 | // archived version. | |
79 | ObjectArchiveEvent = "OBJECT_ARCHIVE" | |
80 | ) | |
81 | ||
82 | func toNotification(rn *raw.Notification) *Notification { | |
83 | n := &Notification{ | |
84 | ID: rn.Id, | |
85 | EventTypes: rn.EventTypes, | |
86 | ObjectNamePrefix: rn.ObjectNamePrefix, | |
87 | CustomAttributes: rn.CustomAttributes, | |
88 | PayloadFormat: rn.PayloadFormat, | |
89 | } | |
90 | n.TopicProjectID, n.TopicID = parseNotificationTopic(rn.Topic) | |
91 | return n | |
92 | } | |
93 | ||
94 | var topicRE = regexp.MustCompile("^//pubsub.googleapis.com/projects/([^/]+)/topics/([^/]+)") | |
95 | ||
96 | // parseNotificationTopic extracts the project and topic IDs from from the full | |
97 | // resource name returned by the service. If the name is malformed, it returns | |
98 | // "?" for both IDs. | |
99 | func parseNotificationTopic(nt string) (projectID, topicID string) { | |
100 | matches := topicRE.FindStringSubmatch(nt) | |
101 | if matches == nil { | |
102 | return "?", "?" | |
103 | } | |
104 | return matches[1], matches[2] | |
105 | } | |
106 | ||
107 | func toRawNotification(n *Notification) *raw.Notification { | |
108 | return &raw.Notification{ | |
109 | Id: n.ID, | |
110 | Topic: fmt.Sprintf("//pubsub.googleapis.com/projects/%s/topics/%s", | |
111 | n.TopicProjectID, n.TopicID), | |
112 | EventTypes: n.EventTypes, | |
113 | ObjectNamePrefix: n.ObjectNamePrefix, | |
114 | CustomAttributes: n.CustomAttributes, | |
115 | PayloadFormat: string(n.PayloadFormat), | |
116 | } | |
117 | } | |
118 | ||
119 | // AddNotification adds a notification to b. You must set n's TopicProjectID, TopicID | |
120 | // and PayloadFormat, and must not set its ID. The other fields are all optional. The | |
121 | // returned Notification's ID can be used to refer to it. | |
122 | func (b *BucketHandle) AddNotification(ctx context.Context, n *Notification) (ret *Notification, err error) { | |
123 | ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.AddNotification") | |
124 | defer func() { trace.EndSpan(ctx, err) }() | |
125 | ||
126 | if n.ID != "" { | |
127 | return nil, errors.New("storage: AddNotification: ID must not be set") | |
128 | } | |
129 | if n.TopicProjectID == "" { | |
130 | return nil, errors.New("storage: AddNotification: missing TopicProjectID") | |
131 | } | |
132 | if n.TopicID == "" { | |
133 | return nil, errors.New("storage: AddNotification: missing TopicID") | |
134 | } | |
135 | call := b.c.raw.Notifications.Insert(b.name, toRawNotification(n)) | |
136 | setClientHeader(call.Header()) | |
137 | if b.userProject != "" { | |
138 | call.UserProject(b.userProject) | |
139 | } | |
140 | rn, err := call.Context(ctx).Do() | |
141 | if err != nil { | |
142 | return nil, err | |
143 | } | |
144 | return toNotification(rn), nil | |
145 | } | |
146 | ||
147 | // Notifications returns all the Notifications configured for this bucket, as a map | |
148 | // indexed by notification ID. | |
149 | func (b *BucketHandle) Notifications(ctx context.Context) (n map[string]*Notification, err error) { | |
150 | ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Notifications") | |
151 | defer func() { trace.EndSpan(ctx, err) }() | |
152 | ||
153 | call := b.c.raw.Notifications.List(b.name) | |
154 | setClientHeader(call.Header()) | |
155 | if b.userProject != "" { | |
156 | call.UserProject(b.userProject) | |
157 | } | |
158 | var res *raw.Notifications | |
159 | err = runWithRetry(ctx, func() error { | |
160 | res, err = call.Context(ctx).Do() | |
161 | return err | |
162 | }) | |
163 | if err != nil { | |
164 | return nil, err | |
165 | } | |
166 | return notificationsToMap(res.Items), nil | |
167 | } | |
168 | ||
169 | func notificationsToMap(rns []*raw.Notification) map[string]*Notification { | |
170 | m := map[string]*Notification{} | |
171 | for _, rn := range rns { | |
172 | m[rn.Id] = toNotification(rn) | |
173 | } | |
174 | return m | |
175 | } | |
176 | ||
177 | // DeleteNotification deletes the notification with the given ID. | |
178 | func (b *BucketHandle) DeleteNotification(ctx context.Context, id string) (err error) { | |
179 | ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.DeleteNotification") | |
180 | defer func() { trace.EndSpan(ctx, err) }() | |
181 | ||
182 | call := b.c.raw.Notifications.Delete(b.name, id) | |
183 | setClientHeader(call.Header()) | |
184 | if b.userProject != "" { | |
185 | call.UserProject(b.userProject) | |
186 | } | |
187 | return call.Context(ctx).Do() | |
188 | } |