gcloud 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +8 -8
- data/AUTHENTICATION.md +1 -1
- data/CHANGELOG.md +14 -0
- data/OVERVIEW.md +87 -0
- data/lib/gcloud.rb +106 -0
- data/lib/gcloud/credentials.rb +1 -1
- data/lib/gcloud/datastore.rb +44 -31
- data/lib/gcloud/datastore/credentials.rb +1 -1
- data/lib/gcloud/datastore/dataset.rb +20 -14
- data/lib/gcloud/datastore/entity.rb +25 -18
- data/lib/gcloud/datastore/key.rb +11 -8
- data/lib/gcloud/pubsub.rb +375 -0
- data/lib/gcloud/pubsub/connection.rb +284 -0
- data/lib/gcloud/pubsub/credentials.rb +29 -0
- data/lib/gcloud/pubsub/errors.rb +91 -0
- data/lib/gcloud/pubsub/message.rb +90 -0
- data/lib/gcloud/pubsub/project.rb +408 -0
- data/lib/gcloud/pubsub/received_message.rb +170 -0
- data/lib/gcloud/pubsub/subscription.rb +605 -0
- data/lib/gcloud/pubsub/subscription/list.rb +50 -0
- data/lib/gcloud/pubsub/topic.rb +640 -0
- data/lib/gcloud/pubsub/topic/list.rb +46 -0
- data/lib/gcloud/storage.rb +84 -66
- data/lib/gcloud/storage/bucket.rb +87 -68
- data/lib/gcloud/storage/bucket/acl.rb +140 -105
- data/lib/gcloud/storage/credentials.rb +1 -1
- data/lib/gcloud/storage/errors.rb +8 -0
- data/lib/gcloud/storage/file.rb +138 -78
- data/lib/gcloud/storage/file/acl.rb +98 -80
- data/lib/gcloud/storage/project.rb +42 -32
- data/lib/gcloud/version.rb +1 -1
- metadata +16 -9
- data/CONTRIBUTING.md +0 -93
- data/LICENSE +0 -201
- data/README.md +0 -110
@@ -0,0 +1,284 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2015 Google Inc. All rights reserved.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
require "gcloud/version"
|
17
|
+
require "google/api_client"
|
18
|
+
|
19
|
+
module Gcloud
|
20
|
+
module Pubsub
|
21
|
+
##
|
22
|
+
# Represents the connection to Pub/Sub,
|
23
|
+
# as well as expose the API calls.
|
24
|
+
class Connection #:nodoc:
|
25
|
+
API_VERSION = "v1"
|
26
|
+
|
27
|
+
attr_accessor :project
|
28
|
+
attr_accessor :credentials #:nodoc:
|
29
|
+
|
30
|
+
##
|
31
|
+
# Creates a new Connection instance.
|
32
|
+
def initialize project, credentials
|
33
|
+
@project = project
|
34
|
+
@credentials = credentials
|
35
|
+
@client = Google::APIClient.new application_name: "gcloud-ruby",
|
36
|
+
application_version: Gcloud::VERSION
|
37
|
+
@client.authorization = @credentials.client
|
38
|
+
@pubsub = @client.discovered_api "pubsub", API_VERSION
|
39
|
+
end
|
40
|
+
|
41
|
+
##
|
42
|
+
# Gets the configuration of a topic.
|
43
|
+
# Since the topic only has the name attribute,
|
44
|
+
# this method is only useful to check the existence of a topic.
|
45
|
+
# If other attributes are added in the future,
|
46
|
+
# they will be returned here.
|
47
|
+
def get_topic topic_name, options = {}
|
48
|
+
@client.execute(
|
49
|
+
api_method: @pubsub.projects.topics.get,
|
50
|
+
parameters: { topic: topic_path(topic_name, options) }
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# Creates the given topic with the given name.
|
56
|
+
def create_topic topic_name, options = {}
|
57
|
+
@client.execute(
|
58
|
+
api_method: @pubsub.projects.topics.create,
|
59
|
+
parameters: { name: topic_path(topic_name, options) }
|
60
|
+
)
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# Lists matching topics.
|
65
|
+
def list_topics options = {}
|
66
|
+
params = { project: project_path(options),
|
67
|
+
pageToken: options.delete(:token),
|
68
|
+
pageSize: options.delete(:max)
|
69
|
+
}.delete_if { |_, v| v.nil? }
|
70
|
+
|
71
|
+
@client.execute(
|
72
|
+
api_method: @pubsub.projects.topics.list,
|
73
|
+
parameters: params
|
74
|
+
)
|
75
|
+
end
|
76
|
+
|
77
|
+
##
|
78
|
+
# Deletes the topic with the given name.
|
79
|
+
# All subscriptions to this topic are also deleted.
|
80
|
+
# Returns NOT_FOUND if the topic does not exist.
|
81
|
+
# After a topic is deleted, a new topic may be created with the same name.
|
82
|
+
def delete_topic topic
|
83
|
+
@client.execute(
|
84
|
+
api_method: @pubsub.projects.topics.delete,
|
85
|
+
parameters: { topic: topic }
|
86
|
+
)
|
87
|
+
end
|
88
|
+
|
89
|
+
def get_topic_policy topic_name, options = {}
|
90
|
+
@client.execute(
|
91
|
+
api_method: @pubsub.projects.topics.get_iam_policy,
|
92
|
+
parameters: { resource: topic_path(topic_name, options) }
|
93
|
+
)
|
94
|
+
end
|
95
|
+
|
96
|
+
def set_topic_policy topic_name, new_policy, options = {}
|
97
|
+
@client.execute(
|
98
|
+
api_method: @pubsub.projects.topics.set_iam_policy,
|
99
|
+
parameters: { resource: topic_path(topic_name, options) },
|
100
|
+
body_object: { policy: new_policy }
|
101
|
+
)
|
102
|
+
end
|
103
|
+
|
104
|
+
##
|
105
|
+
# Creates a subscription on a given topic for a given subscriber.
|
106
|
+
def create_subscription topic, subscription_name, options = {}
|
107
|
+
data = subscription_data topic, options
|
108
|
+
@client.execute(
|
109
|
+
api_method: @pubsub.projects.subscriptions.create,
|
110
|
+
parameters: { name: subscription_path(subscription_name, options) },
|
111
|
+
body_object: data
|
112
|
+
)
|
113
|
+
end
|
114
|
+
|
115
|
+
##
|
116
|
+
# Gets the details of a subscription.
|
117
|
+
def get_subscription subscription_name, options = {}
|
118
|
+
@client.execute(
|
119
|
+
api_method: @pubsub.projects.subscriptions.get,
|
120
|
+
parameters: {
|
121
|
+
subscription: subscription_path(subscription_name, options) }
|
122
|
+
)
|
123
|
+
end
|
124
|
+
|
125
|
+
##
|
126
|
+
# Lists matching subscriptions by project.
|
127
|
+
def list_subscriptions options = {}
|
128
|
+
params = { project: project_path(options),
|
129
|
+
pageToken: options.delete(:token),
|
130
|
+
pageSize: options.delete(:max)
|
131
|
+
}.delete_if { |_, v| v.nil? }
|
132
|
+
|
133
|
+
@client.execute(
|
134
|
+
api_method: @pubsub.projects.subscriptions.list,
|
135
|
+
parameters: params
|
136
|
+
)
|
137
|
+
end
|
138
|
+
|
139
|
+
##
|
140
|
+
# Lists matching subscriptions by project and topic.
|
141
|
+
def list_topics_subscriptions topic, options = {}
|
142
|
+
params = { topic: topic,
|
143
|
+
pageToken: options.delete(:token),
|
144
|
+
pageSize: options.delete(:max)
|
145
|
+
}.delete_if { |_, v| v.nil? }
|
146
|
+
|
147
|
+
@client.execute(
|
148
|
+
api_method: @pubsub.projects.topics.subscriptions.list,
|
149
|
+
parameters: params
|
150
|
+
)
|
151
|
+
end
|
152
|
+
|
153
|
+
##
|
154
|
+
# Deletes an existing subscription.
|
155
|
+
# All pending messages in the subscription are immediately dropped.
|
156
|
+
def delete_subscription subscription
|
157
|
+
@client.execute(
|
158
|
+
api_method: @pubsub.projects.subscriptions.delete,
|
159
|
+
parameters: { subscription: subscription }
|
160
|
+
)
|
161
|
+
end
|
162
|
+
|
163
|
+
def get_subscription_policy subscription_name, options = {}
|
164
|
+
@client.execute(
|
165
|
+
api_method: @pubsub.projects.subscriptions.get_iam_policy,
|
166
|
+
parameters: {
|
167
|
+
resource: subscription_path(subscription_name, options) }
|
168
|
+
)
|
169
|
+
end
|
170
|
+
|
171
|
+
def set_subscription_policy subscription_name, new_policy, options = {}
|
172
|
+
@client.execute(
|
173
|
+
api_method: @pubsub.projects.subscriptions.set_iam_policy,
|
174
|
+
parameters: {
|
175
|
+
resource: subscription_path(subscription_name, options) },
|
176
|
+
body_object: { policy: new_policy }
|
177
|
+
)
|
178
|
+
end
|
179
|
+
|
180
|
+
##
|
181
|
+
# Adds one or more messages to the topic.
|
182
|
+
# Returns NOT_FOUND if the topic does not exist.
|
183
|
+
# The messages parameter is an array of arrays.
|
184
|
+
# The first element is the data, second is attributes hash.
|
185
|
+
def publish topic, messages
|
186
|
+
gapi_msgs = messages.map do |data, attributes|
|
187
|
+
{ data: [data].pack("m"), attributes: attributes }
|
188
|
+
end
|
189
|
+
@client.execute(
|
190
|
+
api_method: @pubsub.projects.topics.publish,
|
191
|
+
parameters: { topic: topic },
|
192
|
+
body_object: { messages: gapi_msgs }
|
193
|
+
)
|
194
|
+
end
|
195
|
+
|
196
|
+
##
|
197
|
+
# Pulls a single message from the server.
|
198
|
+
def pull subscription, options = {}
|
199
|
+
body = { returnImmediately: !(!options.fetch(:immediate, true)),
|
200
|
+
maxMessages: options.fetch(:max, 100).to_i }
|
201
|
+
|
202
|
+
@client.execute(
|
203
|
+
api_method: @pubsub.projects.subscriptions.pull,
|
204
|
+
parameters: { subscription: subscription },
|
205
|
+
body_object: body
|
206
|
+
)
|
207
|
+
end
|
208
|
+
|
209
|
+
##
|
210
|
+
# Acknowledges receipt of a message.
|
211
|
+
def acknowledge subscription, *ack_ids
|
212
|
+
@client.execute(
|
213
|
+
api_method: @pubsub.projects.subscriptions.acknowledge,
|
214
|
+
parameters: { subscription: subscription },
|
215
|
+
body_object: { ackIds: ack_ids }
|
216
|
+
)
|
217
|
+
end
|
218
|
+
|
219
|
+
##
|
220
|
+
# Modifies the PushConfig for a specified subscription.
|
221
|
+
def modify_push_config subscription, endpoint, attributes
|
222
|
+
@client.execute(
|
223
|
+
api_method: @pubsub.projects.subscriptions.modify_push_config,
|
224
|
+
parameters: { subscription: subscription },
|
225
|
+
body_object: { pushConfig: { pushEndpoint: endpoint,
|
226
|
+
attributes: attributes } }
|
227
|
+
)
|
228
|
+
end
|
229
|
+
|
230
|
+
##
|
231
|
+
# Modifies the ack deadline for a specific message.
|
232
|
+
def modify_ack_deadline subscription, ids, deadline
|
233
|
+
ids = Array ids
|
234
|
+
@client.execute(
|
235
|
+
api_method: @pubsub.projects.subscriptions.modify_ack_deadline,
|
236
|
+
parameters: { subscription: subscription },
|
237
|
+
body_object: { ackIds: ids, ackDeadlineSeconds: deadline }
|
238
|
+
)
|
239
|
+
end
|
240
|
+
|
241
|
+
def project_path options = {}
|
242
|
+
project_name = options[:project] || project
|
243
|
+
"projects/#{project_name}"
|
244
|
+
end
|
245
|
+
|
246
|
+
def topic_path topic_name, options = {}
|
247
|
+
return topic_name if topic_name.to_s.include? "/"
|
248
|
+
"#{project_path(options)}/topics/#{topic_name}"
|
249
|
+
end
|
250
|
+
|
251
|
+
def subscription_path subscription_name, options = {}
|
252
|
+
return subscription_name if subscription_name.to_s.include? "/"
|
253
|
+
"#{project_path(options)}/subscriptions/#{subscription_name}"
|
254
|
+
end
|
255
|
+
|
256
|
+
protected
|
257
|
+
|
258
|
+
def subscription_data topic, options = {}
|
259
|
+
deadline = options[:deadline]
|
260
|
+
endpoint = options[:endpoint]
|
261
|
+
attributes = hashify options[:attributes]
|
262
|
+
|
263
|
+
data = { topic: topic }
|
264
|
+
data[:ackDeadlineSeconds] = deadline if deadline
|
265
|
+
if endpoint
|
266
|
+
data[:pushConfig] = { pushEndpoint: endpoint,
|
267
|
+
attributes: attributes }
|
268
|
+
end
|
269
|
+
data
|
270
|
+
end
|
271
|
+
|
272
|
+
##
|
273
|
+
# Make sure the object is converted to a hash
|
274
|
+
# Ruby 1.9.3 doesn't support to_h, so here we are.
|
275
|
+
def hashify hash
|
276
|
+
if hash.respond_to? :to_h
|
277
|
+
hash.to_h
|
278
|
+
else
|
279
|
+
Hash.try_convert(hash) || {}
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2015 Google Inc. All rights reserved.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
require "gcloud/credentials"
|
17
|
+
|
18
|
+
module Gcloud
|
19
|
+
module Pubsub
|
20
|
+
##
|
21
|
+
# Represents the OAuth 2.0 signing logic for Pub/Sub.
|
22
|
+
class Credentials < Gcloud::Credentials #:nodoc:
|
23
|
+
SCOPE = ["https://www.googleapis.com/auth/pubsub",
|
24
|
+
"https://www.googleapis.com/auth/cloud-platform"]
|
25
|
+
PATH_ENV_VARS = %w(PUBSUB_KEYFILE GOOGLE_CLOUD_KEYFILE)
|
26
|
+
JSON_ENV_VARS = %w(PUBSUB_KEYFILE_JSON GOOGLE_CLOUD_KEYFILE_JSON)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2015 Google Inc. All rights reserved.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
module Gcloud
|
17
|
+
module Pubsub
|
18
|
+
##
|
19
|
+
# = Storage Error
|
20
|
+
#
|
21
|
+
# Base Pub/Sub exception class.
|
22
|
+
class Error < Gcloud::Error
|
23
|
+
##
|
24
|
+
# The response object of the failed HTTP request.
|
25
|
+
attr_reader :response
|
26
|
+
|
27
|
+
def self.from_response resp #:nodoc:
|
28
|
+
new.tap do |e|
|
29
|
+
e.response = resp
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
##
|
35
|
+
# = ApiError
|
36
|
+
#
|
37
|
+
# Raised when an API call is not successful.
|
38
|
+
class ApiError < Error
|
39
|
+
##
|
40
|
+
# The code of the error.
|
41
|
+
def code
|
42
|
+
response.data["error"]["code"]
|
43
|
+
rescue
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# The errors encountered.
|
49
|
+
def errors
|
50
|
+
response.data["error"]["errors"]
|
51
|
+
rescue
|
52
|
+
[]
|
53
|
+
end
|
54
|
+
|
55
|
+
def initialize message, response
|
56
|
+
super message
|
57
|
+
@response = response
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.from_response resp #:nodoc:
|
61
|
+
klass = klass_for resp.data["error"]["status"]
|
62
|
+
klass.new resp.data["error"]["message"], resp
|
63
|
+
rescue
|
64
|
+
Gcloud::Pubsub::Error.from_response resp
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.klass_for status
|
68
|
+
if status == "ALREADY_EXISTS"
|
69
|
+
return AlreadyExistsError
|
70
|
+
elsif status == "NOT_FOUND"
|
71
|
+
return NotFoundError
|
72
|
+
end
|
73
|
+
self
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
##
|
78
|
+
# = AlreadyExistsError
|
79
|
+
#
|
80
|
+
# Raised when Pub/Sub returns an +ALREADY_EXISTS+ error.
|
81
|
+
class AlreadyExistsError < ApiError
|
82
|
+
end
|
83
|
+
|
84
|
+
##
|
85
|
+
# = NotFoundError
|
86
|
+
#
|
87
|
+
# Raised when Pub/Sub returns a +NOT_FOUND+ error.
|
88
|
+
class NotFoundError < ApiError
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2015 Google Inc. All rights reserved.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
require "gcloud/pubsub/errors"
|
17
|
+
|
18
|
+
module Gcloud
|
19
|
+
module Pubsub
|
20
|
+
##
|
21
|
+
# = Message
|
22
|
+
#
|
23
|
+
# Represents a Pub/Sub Message.
|
24
|
+
#
|
25
|
+
# Message objects are created by Topic#publish.
|
26
|
+
# Subscription#pull returns an array of ReceivedMessage objects, each of
|
27
|
+
# which contains a Message object. Each ReceivedMessage object can be
|
28
|
+
# acknowledged and/or delayed.
|
29
|
+
#
|
30
|
+
# require "gcloud"
|
31
|
+
#
|
32
|
+
# gcloud = Gcloud.new
|
33
|
+
# pubsub = gcloud.pubsub
|
34
|
+
#
|
35
|
+
# # Publish a message
|
36
|
+
# topic = pubsub.topic "my-topic"
|
37
|
+
# message = topic.publish "new-message"
|
38
|
+
# puts message.data #=> "new-message"
|
39
|
+
#
|
40
|
+
# # Pull a message
|
41
|
+
# sub = pubsub.subscription "my-topic-sub"
|
42
|
+
# received_message = sub.pull.first
|
43
|
+
# puts received_message.message.data #=> "new-message"
|
44
|
+
#
|
45
|
+
class Message
|
46
|
+
##
|
47
|
+
# The Google API Client object.
|
48
|
+
attr_accessor :gapi #:nodoc:
|
49
|
+
|
50
|
+
##
|
51
|
+
# Create an empty Message object.
|
52
|
+
# This can be used to publish several messages in bulk.
|
53
|
+
def initialize data = nil, attributes = {}
|
54
|
+
@gapi = {}
|
55
|
+
@gapi["data"] = data
|
56
|
+
@gapi["attributes"] = attributes
|
57
|
+
end
|
58
|
+
|
59
|
+
##
|
60
|
+
# The received data.
|
61
|
+
def data
|
62
|
+
@gapi["data"]
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# The received attributes.
|
67
|
+
def attributes
|
68
|
+
attrs = @gapi["attributes"]
|
69
|
+
attrs = attrs.to_hash if attrs.respond_to? :to_hash
|
70
|
+
attrs
|
71
|
+
end
|
72
|
+
|
73
|
+
##
|
74
|
+
# The ID of this message, assigned by the server at publication time.
|
75
|
+
# Guaranteed to be unique within the topic.
|
76
|
+
def message_id
|
77
|
+
@gapi["messageId"]
|
78
|
+
end
|
79
|
+
alias_method :msg_id, :message_id
|
80
|
+
|
81
|
+
##
|
82
|
+
# New Topic from a Google API Client object.
|
83
|
+
def self.from_gapi gapi #:nodoc:
|
84
|
+
new.tap do |f|
|
85
|
+
f.gapi = gapi
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|