gstore 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.textile +53 -0
- data/lib/gstore.rb +5 -0
- data/lib/gstore/bucket.rb +21 -0
- data/lib/gstore/client.rb +41 -0
- data/lib/gstore/object.rb +25 -0
- data/lib/gstore/request.rb +98 -0
- metadata +62 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) Richard Taylor
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.textile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
h1. Ruby client library for the Google Storage API
|
2
|
+
|
3
|
+
This is the first release and supports all the basic operations. Advanced support for ACLs etc.. coming soon
|
4
|
+
|
5
|
+
h2. Install the gem
|
6
|
+
|
7
|
+
sudo gem install gstore
|
8
|
+
|
9
|
+
h2. Using the gem
|
10
|
+
|
11
|
+
Visit "The Google Storage Key Manager":https://sandbox.google.com/storage/m/manage to get your access and secret keys.
|
12
|
+
|
13
|
+
In your code just: <code>require 'gstore'</code>
|
14
|
+
|
15
|
+
h2. Example
|
16
|
+
|
17
|
+
Create an instance of the client with your credentials:
|
18
|
+
|
19
|
+
<pre><code>client = GStore::Client.new(
|
20
|
+
:access_key => 'YOUR_ACCESS_KEY',
|
21
|
+
:secret_key => 'YOUR_SECRET_KEY'
|
22
|
+
)
|
23
|
+
|
24
|
+
# List all of your existing Buckets
|
25
|
+
client.list_buckets
|
26
|
+
</code></pre>
|
27
|
+
|
28
|
+
Here are some example bucket operations:
|
29
|
+
|
30
|
+
<pre><code># Create a Bucket
|
31
|
+
client.create_bucket('my_unique_bucket')
|
32
|
+
|
33
|
+
# Retrieve a Bucket
|
34
|
+
client.get_bucket('my_unique_bucket')
|
35
|
+
|
36
|
+
# Delete a [empty] Bucket
|
37
|
+
client.delete_bucket('my_unique_bucket')
|
38
|
+
</code></pre>
|
39
|
+
|
40
|
+
Once you have a bucket you can manipulate objects in the following way:
|
41
|
+
|
42
|
+
<pre><code># Store a file in a bucket
|
43
|
+
client.put_object('my_unique_bucket', 'my_first_object', :data => File.read('mytext.txt'))
|
44
|
+
|
45
|
+
# Retrieve the contents of the object in the specified bucket
|
46
|
+
puts client.get_object('my_unique_bucket', 'my_first_object')
|
47
|
+
|
48
|
+
# Alternatively specify an outfile and the contents will be saved to there
|
49
|
+
client.get_object('my_unique_bucket', 'my_first_object', :outfile => 'retrieved_mytext.txt')
|
50
|
+
|
51
|
+
# Delete an object from the bucket
|
52
|
+
client.delete_object('my_unique_bucket', 'my_first_object')
|
53
|
+
</code></pre>
|
data/lib/gstore.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module GStore
|
2
|
+
class Client
|
3
|
+
|
4
|
+
def list_buckets(options={})
|
5
|
+
get(nil, '/', options)
|
6
|
+
end
|
7
|
+
|
8
|
+
def create_bucket(bucket, options={})
|
9
|
+
put(bucket, '/', options)
|
10
|
+
end
|
11
|
+
|
12
|
+
def get_bucket(bucket, options={})
|
13
|
+
get(bucket, '/', options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def delete_bucket(bucket, options={})
|
17
|
+
delete(bucket, '/', options)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'gstore/request'
|
2
|
+
require 'gstore/bucket'
|
3
|
+
require 'gstore/object'
|
4
|
+
|
5
|
+
module GStore
|
6
|
+
class Client
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
@access_key = options[:access_key]
|
10
|
+
@secret_key = options[:secret_key]
|
11
|
+
@debug = options[:debug] and options[:debug] == true
|
12
|
+
@host = options[:host] || 'commondatastorage.googleapis.com'
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def get(bucket, path, params={}, options={})
|
18
|
+
_http_request(Net::HTTP::Get, bucket, path, params, options)
|
19
|
+
end
|
20
|
+
|
21
|
+
def put(bucket, path, params={}, options={})
|
22
|
+
_http_request(Net::HTTP::Put, bucket, path, params, options)
|
23
|
+
end
|
24
|
+
|
25
|
+
def delete(bucket, path, params={}, options={})
|
26
|
+
_http_request(Net::HTTP::Delete, bucket, path, params, options)
|
27
|
+
end
|
28
|
+
|
29
|
+
def head(bucket, path, params={}, options={})
|
30
|
+
_http_request(Net::HTTP::Head, bucket, path, params, options)
|
31
|
+
end
|
32
|
+
|
33
|
+
def _http_request(method, bucket, path, params, options={})
|
34
|
+
host = @host
|
35
|
+
host = "#{bucket}.#{@host}" if bucket
|
36
|
+
signed_request(method, host, path, params, options)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module GStore
|
2
|
+
class Client
|
3
|
+
def put_object(bucket, filename, data, options={})
|
4
|
+
put(bucket, "/#{filename}", options, data)
|
5
|
+
end
|
6
|
+
|
7
|
+
def get_object(bucket, filename, options={})
|
8
|
+
outfile = options.delete(:outfile)
|
9
|
+
res = get(bucket, "/#{filename}", options)
|
10
|
+
if outfile
|
11
|
+
File.open(outfile, 'w') {|f| f.write(res) }
|
12
|
+
else
|
13
|
+
res
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def delete_object(bucket, filename, options={})
|
18
|
+
delete(bucket, "/#{filename}", options)
|
19
|
+
end
|
20
|
+
|
21
|
+
def get_object_metadata(bucket, filename, options={})
|
22
|
+
head(bucket, "/#{filename}", options)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'time'
|
2
|
+
require 'openssl'
|
3
|
+
require 'digest/sha1'
|
4
|
+
require 'base64'
|
5
|
+
require 'uri'
|
6
|
+
require 'net/https'
|
7
|
+
require 'cgi'
|
8
|
+
|
9
|
+
module GStore
|
10
|
+
class Client
|
11
|
+
|
12
|
+
def signed_request(method, host, path, params={}, options={})
|
13
|
+
|
14
|
+
if @debug
|
15
|
+
puts
|
16
|
+
puts "***** METHOD: #{method}"
|
17
|
+
puts "***** HOST: #{host}"
|
18
|
+
puts "***** PATH: #{path}"
|
19
|
+
puts "***** PARAMS: #{params.inspect}"
|
20
|
+
puts "***** OPTIONS: #{options.inspect}"
|
21
|
+
puts
|
22
|
+
end
|
23
|
+
|
24
|
+
headers = {
|
25
|
+
:Host => host,
|
26
|
+
:Date => Time.now.utc.strftime('%a, %d %b %Y %H:%M:%S -0000'),
|
27
|
+
:"Content-Type" => 'text/plain',
|
28
|
+
#:"Content-MD5" => ''
|
29
|
+
}
|
30
|
+
if options[:data]
|
31
|
+
headers = headers.merge(:"Content-Length" => options[:data].size)
|
32
|
+
else
|
33
|
+
headers = headers.merge(:"Content-Length" => 0)
|
34
|
+
end
|
35
|
+
|
36
|
+
bucket = nil
|
37
|
+
if host =~ /(\S+).#{@host}/
|
38
|
+
bucket = $1
|
39
|
+
end
|
40
|
+
|
41
|
+
canonical_headers = method.name.gsub('Net::HTTP::', '').upcase + "\n" +
|
42
|
+
'' + "\n" + # Content-MD5
|
43
|
+
headers[:"Content-Type"] + "\n" + # Content-Type
|
44
|
+
headers[:Date] + "\n" # Date
|
45
|
+
|
46
|
+
canonical_resource = ""
|
47
|
+
canonical_resource += "/#{bucket}" if bucket
|
48
|
+
canonical_resource += path
|
49
|
+
|
50
|
+
authorization = 'GOOG1 ' + @access_key + ':' + sign((canonical_headers + canonical_resource).toutf8)
|
51
|
+
|
52
|
+
if @debug
|
53
|
+
puts
|
54
|
+
puts "+++++ BUCKET: #{bucket}"
|
55
|
+
puts "+++++ HEADERS: #{headers.inspect}"
|
56
|
+
puts "+++++ CANONICAL_HEADERS: #{canonical_headers}"
|
57
|
+
puts "+++++ CANONICAL_RESOURCE: #{canonical_resource}"
|
58
|
+
puts "+++++ AUTHORIZATION: #{authorization}"
|
59
|
+
puts
|
60
|
+
end
|
61
|
+
|
62
|
+
_http_do(method, host, path, params_to_request_string(params), headers.merge(:Authorization => authorization), options[:data])
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
def sign(str)
|
67
|
+
digest = OpenSSL::Digest::Digest.new('sha1')
|
68
|
+
b64_hmac = Base64.encode64(OpenSSL::HMAC.digest(digest, @secret_key, str)).gsub("\n","")
|
69
|
+
end
|
70
|
+
|
71
|
+
def _http_do(method, host, path, params, headers, data=nil)
|
72
|
+
http = Net::HTTP.new(host, 443)
|
73
|
+
http.use_ssl = true
|
74
|
+
|
75
|
+
http.start do
|
76
|
+
req = method.new(path)
|
77
|
+
req.content_type = 'application/x-www-form-urlencoded'
|
78
|
+
req['User-Agent'] = "moomerman-gstore-gem"
|
79
|
+
headers.each do |key, value|
|
80
|
+
req[key.to_s] = value
|
81
|
+
end
|
82
|
+
|
83
|
+
response = http.request(req, data)
|
84
|
+
|
85
|
+
return response.body
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def params_to_request_string(params)
|
90
|
+
sorted_params = params.sort {|x,y| x[0].to_s <=> y[0].to_s}
|
91
|
+
escaped_params = sorted_params.collect do |p|
|
92
|
+
encoded = (CGI::escape(p[0].to_s) + "=" + CGI::escape(p[1].to_s))
|
93
|
+
encoded.gsub('+', '%20')
|
94
|
+
end
|
95
|
+
escaped_params.join('&')
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
metadata
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gstore
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Richard Taylor
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-06-15 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: gstore is a Ruby client library for the Google Storage API.
|
17
|
+
email: moomerman@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- LICENSE
|
26
|
+
- README.textile
|
27
|
+
- lib/gstore.rb
|
28
|
+
- lib/gstore/bucket.rb
|
29
|
+
- lib/gstore/client.rb
|
30
|
+
- lib/gstore/object.rb
|
31
|
+
- lib/gstore/request.rb
|
32
|
+
has_rdoc: true
|
33
|
+
homepage: http://github.com/moomerman/gstore
|
34
|
+
licenses: []
|
35
|
+
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options:
|
38
|
+
- --inline-source
|
39
|
+
- --charset=UTF-8
|
40
|
+
require_paths:
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "0"
|
47
|
+
version:
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: "0"
|
53
|
+
version:
|
54
|
+
requirements: []
|
55
|
+
|
56
|
+
rubyforge_project: gstore
|
57
|
+
rubygems_version: 1.3.5
|
58
|
+
signing_key:
|
59
|
+
specification_version: 2
|
60
|
+
summary: gstore is a Ruby client library for the Google Storage API.
|
61
|
+
test_files: []
|
62
|
+
|