riak-client 0.9.0.beta → 0.9.0.beta2
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.
- data/Gemfile +10 -7
- data/Rakefile +21 -3
- data/erl_src/riak_kv_test_backend.beam +0 -0
- data/erl_src/riak_kv_test_backend.erl +29 -13
- data/lib/riak/bucket.rb +1 -1
- data/lib/riak/cache_store.rb +1 -1
- data/lib/riak/client.rb +119 -8
- data/lib/riak/client/beefcake/messages.rb +162 -0
- data/lib/riak/client/beefcake/object_methods.rb +92 -0
- data/lib/riak/client/beefcake_protobuffs_backend.rb +186 -0
- data/lib/riak/client/curb_backend.rb +10 -16
- data/lib/riak/client/excon_backend.rb +14 -18
- data/lib/riak/client/http_backend.rb +13 -13
- data/lib/riak/client/http_backend/object_methods.rb +1 -1
- data/lib/riak/client/http_backend/transport_methods.rb +6 -2
- data/lib/riak/client/net_http_backend.rb +33 -20
- data/lib/riak/client/protobuffs_backend.rb +103 -0
- data/lib/riak/client/pump.rb +44 -0
- data/lib/riak/failed_request.rb +58 -3
- data/lib/riak/locale/en.yml +11 -3
- data/lib/riak/map_reduce.rb +15 -6
- data/lib/riak/map_reduce/filter_builder.rb +4 -4
- data/lib/riak/test_server.rb +5 -1
- data/lib/riak/util/multipart.rb +30 -16
- data/lib/riak/util/multipart/stream_parser.rb +74 -0
- data/riak-client.gemspec +14 -12
- data/spec/fixtures/server.cert.crt +15 -0
- data/spec/fixtures/server.cert.key +15 -0
- data/spec/fixtures/test.pem +1 -0
- data/spec/integration/riak/http_backends_spec.rb +45 -0
- data/spec/integration/riak/protobuffs_backends_spec.rb +45 -0
- data/spec/integration/riak/test_server_spec.rb +2 -2
- data/spec/riak/bucket_spec.rb +4 -4
- data/spec/riak/client_spec.rb +209 -3
- data/spec/riak/excon_backend_spec.rb +8 -7
- data/spec/riak/http_backend/configuration_spec.rb +64 -0
- data/spec/riak/http_backend/object_methods_spec.rb +1 -1
- data/spec/riak/http_backend/transport_methods_spec.rb +129 -0
- data/spec/riak/http_backend_spec.rb +13 -1
- data/spec/riak/map_reduce/filter_builder_spec.rb +45 -0
- data/spec/riak/map_reduce/phase_spec.rb +149 -0
- data/spec/riak/map_reduce_spec.rb +5 -5
- data/spec/riak/net_http_backend_spec.rb +1 -0
- data/spec/riak/{object_spec.rb → robject_spec.rb} +1 -1
- data/spec/riak/stream_parser_spec.rb +66 -0
- data/spec/support/drb_mock_server.rb +2 -2
- data/spec/support/http_backend_implementation_examples.rb +27 -0
- data/spec/support/mock_server.rb +22 -1
- data/spec/support/unified_backend_examples.rb +255 -0
- metadata +43 -54
@@ -0,0 +1,92 @@
|
|
1
|
+
# Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
|
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
|
+
require 'riak'
|
15
|
+
|
16
|
+
module Riak
|
17
|
+
class Client
|
18
|
+
class BeefcakeProtobuffsBackend
|
19
|
+
module ObjectMethods
|
20
|
+
# Returns RpbPutReq
|
21
|
+
def dump_object(robject)
|
22
|
+
pbuf = RpbPutReq.new(:bucket => robject.bucket.name)
|
23
|
+
pbuf.key = robject.key || generate_key
|
24
|
+
pbuf.vclock = Base64.decode64(robject.vclock) if robject.vclock
|
25
|
+
pbuf.content = RpbContent.new(:value => robject.raw_data,
|
26
|
+
:content_type => robject.content_type,
|
27
|
+
:links => robject.links.map {|l| encode_link(l) }.compact)
|
28
|
+
|
29
|
+
pbuf.content.usermeta = robject.meta.map {|k,v| encode_meta(k,v)} if robject.meta.any?
|
30
|
+
pbuf.content.vtag = robject.etag if robject.etag.present?
|
31
|
+
if robject.raw_data.respond_to?(:encoding) # 1.9 support
|
32
|
+
pbuf.content.charset = robject.raw_data.encoding.name
|
33
|
+
end
|
34
|
+
pbuf
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns RObject
|
38
|
+
def load_object(pbuf, robject)
|
39
|
+
robject.vclock = Base64.encode64(pbuf.vclock).chomp if pbuf.vclock
|
40
|
+
if pbuf.content.size > 1
|
41
|
+
robject.conflict = true
|
42
|
+
robject.siblings = pbuf.content.map do |c|
|
43
|
+
sibling = RObject.new(robject.bucket, robject.key)
|
44
|
+
sibling.vclock = robject.vclock
|
45
|
+
load_content(c, sibling)
|
46
|
+
end
|
47
|
+
else
|
48
|
+
load_content(pbuf.content.first, robject)
|
49
|
+
end
|
50
|
+
robject
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
def load_content(pbuf, robject)
|
55
|
+
if pbuf.value.respond_to?(:force_encoding) && pbuf.charset.present?
|
56
|
+
pbuf.value.force_encoding(pbuf.charset) if Encoding.find(pbuf.charset)
|
57
|
+
end
|
58
|
+
robject.raw_data = pbuf.value
|
59
|
+
robject.etag = pbuf.vtag if pbuf.vtag.present?
|
60
|
+
robject.content_type = pbuf.content_type if pbuf.content_type.present?
|
61
|
+
robject.links = pbuf.links.map(&method(:decode_link)) if pbuf.links.present?
|
62
|
+
pbuf.usermeta.each {|pair| decode_meta(pair, robject.meta) } if pbuf.usermeta.present?
|
63
|
+
if pbuf.last_mod.present?
|
64
|
+
robject.last_modified = Time.at(pbuf.last_mod)
|
65
|
+
robject.last_modified += pbuf.last_mod_usecs / 1000000 if pbuf.last_mod_usecs.present?
|
66
|
+
end
|
67
|
+
robject
|
68
|
+
end
|
69
|
+
|
70
|
+
def decode_link(pbuf)
|
71
|
+
Riak::Link.new(pbuf.bucket, pbuf.key, pbuf.tag)
|
72
|
+
end
|
73
|
+
|
74
|
+
def encode_link(link)
|
75
|
+
return nil unless link.key.present?
|
76
|
+
RpbLink.new(:bucket => link.bucket.to_s, :key => link.key.to_s, :tag => link.tag.to_s)
|
77
|
+
end
|
78
|
+
|
79
|
+
def decode_meta(pbuf, hash)
|
80
|
+
hash[pbuf.key] = pbuf.value
|
81
|
+
end
|
82
|
+
|
83
|
+
def encode_meta(key,value)
|
84
|
+
return nil unless value.present?
|
85
|
+
RpbPair.new(:key.to_s, :value => value.to_s)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
include ObjectMethods
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
# Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
|
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
|
+
require 'riak'
|
15
|
+
require 'riak/client/protobuffs_backend'
|
16
|
+
require 'riak/client/pump'
|
17
|
+
|
18
|
+
module Riak
|
19
|
+
class Client
|
20
|
+
class BeefcakeProtobuffsBackend < ProtobuffsBackend
|
21
|
+
def self.configured?
|
22
|
+
begin
|
23
|
+
require 'beefcake'
|
24
|
+
require 'riak/client/beefcake/messages'
|
25
|
+
require "riak/client/beefcake/object_methods"
|
26
|
+
true
|
27
|
+
rescue LoadError, NameError
|
28
|
+
false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def set_client_id(id)
|
33
|
+
value = case id
|
34
|
+
when Integer
|
35
|
+
[id].pack("N")
|
36
|
+
else
|
37
|
+
id.to_s
|
38
|
+
end
|
39
|
+
req = RpbSetClientIdReq.new(:client_id => value)
|
40
|
+
write_protobuff(:SetClientIdReq, req)
|
41
|
+
decode_response
|
42
|
+
end
|
43
|
+
|
44
|
+
def fetch_object(bucket, key, r=nil)
|
45
|
+
bucket = Bucket === bucket ? bucket.name : bucket
|
46
|
+
req = RpbGetReq.new(:bucket => bucket, :key => key)
|
47
|
+
req.r = normalize_quorum_value(r) if r
|
48
|
+
write_protobuff(:GetReq, req)
|
49
|
+
decode_response(RObject.new(client.bucket(bucket), key))
|
50
|
+
end
|
51
|
+
|
52
|
+
def reload_object(robject, r=nil)
|
53
|
+
req = RpbGetReq.new(:bucket => robject.bucket.name, :key => robject.key)
|
54
|
+
req.r = normalize_quorum_value(r) if r
|
55
|
+
write_protobuff(:GetReq, req)
|
56
|
+
decode_response(robject)
|
57
|
+
end
|
58
|
+
|
59
|
+
def store_object(robject, returnbody=false, w=nil, dw=nil)
|
60
|
+
if robject.prevent_stale_writes
|
61
|
+
other = fetch_object(robject.bucket, robject.key)
|
62
|
+
raise Riak::ProtobuffsFailedRequest(:stale_object, t("stale_write_prevented")) unless other.vclock == robject.vclock
|
63
|
+
end
|
64
|
+
req = dump_object(robject)
|
65
|
+
req.w = normalize_quorum_value(w) if w
|
66
|
+
req.dw = normalize_quorum_value(dw) if dw
|
67
|
+
req.return_body = returnbody
|
68
|
+
write_protobuff(:PutReq, req)
|
69
|
+
decode_response(robject)
|
70
|
+
end
|
71
|
+
|
72
|
+
def delete_object(bucket, key, rw=nil)
|
73
|
+
bucket = Bucket === bucket ? bucket.name : bucket
|
74
|
+
req = RpbDelReq.new(:bucket => bucket, :key => key)
|
75
|
+
req.rw = normalize_quorum_value(rw) if rw
|
76
|
+
write_protobuff(:DelReq, req)
|
77
|
+
decode_response
|
78
|
+
end
|
79
|
+
|
80
|
+
def get_bucket_props(bucket)
|
81
|
+
bucket = bucket.name if Bucket === bucket
|
82
|
+
req = RpbGetBucketReq.new(:bucket => bucket)
|
83
|
+
write_protobuff(:GetBucketReq, req)
|
84
|
+
decode_response
|
85
|
+
end
|
86
|
+
|
87
|
+
def set_bucket_props(bucket, props)
|
88
|
+
bucket = bucket.name if Bucket === bucket
|
89
|
+
props = props.slice('n_val', 'allow_mult')
|
90
|
+
req = RpbSetBucketReq.new(:bucket => bucket, :props => RpbBucketProps.new(props))
|
91
|
+
write_protobuff(:SetBucketReq, req)
|
92
|
+
decode_response
|
93
|
+
end
|
94
|
+
|
95
|
+
def list_keys(bucket, &block)
|
96
|
+
bucket = bucket.name if Bucket === bucket
|
97
|
+
req = RpbListKeysReq.new(:bucket => bucket)
|
98
|
+
write_protobuff(:ListKeysReq, req)
|
99
|
+
keys = []
|
100
|
+
pump = Pump.new(block) if block_given?
|
101
|
+
while msg = decode_response
|
102
|
+
break if msg.done
|
103
|
+
if pump
|
104
|
+
pump.pump msg.keys
|
105
|
+
else
|
106
|
+
keys += msg.keys
|
107
|
+
end
|
108
|
+
end
|
109
|
+
block_given? || keys
|
110
|
+
end
|
111
|
+
|
112
|
+
def mapred(mr, &block)
|
113
|
+
req = RpbMapRedReq.new(:request => mr.to_json, :content_type => "application/json")
|
114
|
+
write_protobuff(:MapRedReq, req)
|
115
|
+
results = []
|
116
|
+
pump = Pump.new(lambda do |msg|
|
117
|
+
block.call msg.phase, JSON.parse(msg.response)
|
118
|
+
end) if block_given?
|
119
|
+
while msg = decode_response
|
120
|
+
break if msg.done
|
121
|
+
if pump
|
122
|
+
pump.pump msg
|
123
|
+
else
|
124
|
+
results[msg.phase] ||= []
|
125
|
+
results[msg.phase] += JSON.parse(msg.response)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
block_given? || results.size == 1 ? results.first : results
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
def write_protobuff(code, message)
|
133
|
+
encoded = message.encode
|
134
|
+
socket.write([encoded.length+1, MESSAGE_CODES.index(code)].pack("NC"))
|
135
|
+
socket.write(encoded)
|
136
|
+
end
|
137
|
+
|
138
|
+
def decode_response(*args)
|
139
|
+
header = socket.read(5)
|
140
|
+
raise SocketError, "Unexpected EOF on PBC socket" if header.nil?
|
141
|
+
msglen, msgcode = header.unpack("NC")
|
142
|
+
if msglen == 1
|
143
|
+
case MESSAGE_CODES[msgcode]
|
144
|
+
when :PingResp, :SetClientIdResp, :PutResp, :DelResp, :SetBucketResp
|
145
|
+
true
|
146
|
+
when :ListBucketsResp, :ListKeysResp
|
147
|
+
[]
|
148
|
+
when :GetResp
|
149
|
+
raise Riak::ProtobuffsFailedRequest.new(:not_found, t('not_found'))
|
150
|
+
else
|
151
|
+
false
|
152
|
+
end
|
153
|
+
else
|
154
|
+
message = socket.read(msglen-1)
|
155
|
+
case MESSAGE_CODES[msgcode]
|
156
|
+
when :ErrorResp
|
157
|
+
res = RpbErrorResp.decode(message)
|
158
|
+
raise Riak::ProtobuffsFailedRequest.new(res.errcode, res.errmsg)
|
159
|
+
when :GetClientIdResp
|
160
|
+
res = RpbGetClientIdResp.decode(message)
|
161
|
+
res.client_id
|
162
|
+
when :GetServerInfoResp
|
163
|
+
res = RpbGetServerInfoResp.decode(message)
|
164
|
+
{:node => res.node, :server_version => res.server_version}
|
165
|
+
when :GetResp, :PutResp
|
166
|
+
res = RpbGetResp.decode(message)
|
167
|
+
load_object(res, args.first)
|
168
|
+
when :ListBucketsResp
|
169
|
+
res = RpbListBucketsResp.decode(message)
|
170
|
+
res.buckets
|
171
|
+
when :ListKeysResp
|
172
|
+
RpbListKeysResp.decode(message)
|
173
|
+
when :GetBucketResp
|
174
|
+
res = RpbGetBucketResp.decode(message)
|
175
|
+
{'n_val' => res.props.n_val, 'allow_mult' => res.props.allow_mult}
|
176
|
+
when :MapRedResp
|
177
|
+
RpbMapRedResp.decode(message)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
rescue SocketError => e
|
181
|
+
reset_socket
|
182
|
+
raise Riak::ProtobuffsFailedRequest.new(:server_error, e.message)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
@@ -12,12 +12,7 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
require 'riak'
|
15
|
-
|
16
|
-
begin
|
17
|
-
require 'fiber'
|
18
|
-
rescue LoadError
|
19
|
-
require 'riak/util/fiber1.8'
|
20
|
-
end
|
15
|
+
require 'riak/client/pump'
|
21
16
|
|
22
17
|
module Riak
|
23
18
|
class Client
|
@@ -34,20 +29,13 @@ module Riak
|
|
34
29
|
end
|
35
30
|
|
36
31
|
private
|
37
|
-
def perform(method, uri, headers, expect, data=nil)
|
32
|
+
def perform(method, uri, headers, expect, data=nil, &block)
|
38
33
|
# Setup
|
39
34
|
curl.headers = RequestHeaders.new(headers).to_a
|
40
35
|
curl.url = uri.to_s
|
41
36
|
response_headers.initialize_http_header(nil)
|
42
37
|
if block_given?
|
43
|
-
|
44
|
-
Fiber.new {
|
45
|
-
f = Fiber.current
|
46
|
-
_curl.on_body {|chunk| f.resume(chunk); chunk.size }
|
47
|
-
loop do
|
48
|
-
yield Fiber.yield
|
49
|
-
end
|
50
|
-
}.resume
|
38
|
+
curl.on_body(&Pump.new(block))
|
51
39
|
else
|
52
40
|
curl.on_body
|
53
41
|
end
|
@@ -74,12 +62,14 @@ module Riak
|
|
74
62
|
end
|
75
63
|
result
|
76
64
|
else
|
77
|
-
raise
|
65
|
+
raise HTTPFailedRequest.new(method, expect, curl.response_code, response_headers.to_hash, curl.body_str)
|
78
66
|
end
|
79
67
|
end
|
80
68
|
|
81
69
|
def curl
|
82
70
|
Thread.current[:curl_easy_handle] ||= Curl::Easy.new.tap do |c|
|
71
|
+
configure_ssl(c) if @client.ssl_enabled?
|
72
|
+
|
83
73
|
c.follow_location = false
|
84
74
|
c.on_header do |header_line|
|
85
75
|
response_headers.parse(header_line)
|
@@ -87,6 +77,10 @@ module Riak
|
|
87
77
|
end
|
88
78
|
end
|
89
79
|
end
|
80
|
+
|
81
|
+
def configure_ssl(curl)
|
82
|
+
curl.ssl_verify_peer = @client.ssl_options[:verify_mode] == "peer"
|
83
|
+
end
|
90
84
|
end
|
91
85
|
end
|
92
86
|
end
|
@@ -12,22 +12,18 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
require 'riak'
|
15
|
+
require 'riak/client/pump'
|
15
16
|
|
16
17
|
module Riak
|
17
18
|
class Client
|
18
19
|
# An HTTP backend for Riak::Client that uses Wesley Beary's Excon
|
19
|
-
# HTTP library.
|
20
|
+
# HTTP library. Conforms to the Riak::Client::HTTPBackend
|
20
21
|
# interface.
|
21
22
|
class ExconBackend < HTTPBackend
|
22
23
|
def self.configured?
|
23
24
|
begin
|
24
|
-
begin
|
25
|
-
require 'fiber'
|
26
|
-
rescue LoadError
|
27
|
-
require 'riak/util/fiber1.8'
|
28
|
-
end
|
29
25
|
require 'excon'
|
30
|
-
Excon::VERSION >= "0.
|
26
|
+
Excon::VERSION >= "0.5.7"
|
31
27
|
rescue LoadError
|
32
28
|
false
|
33
29
|
end
|
@@ -35,6 +31,8 @@ module Riak
|
|
35
31
|
|
36
32
|
private
|
37
33
|
def perform(method, uri, headers, expect, data=nil, &block)
|
34
|
+
configure_ssl if @client.ssl_enabled?
|
35
|
+
|
38
36
|
params = {
|
39
37
|
:method => method.to_s.upcase,
|
40
38
|
:headers => RequestHeaders.new(headers).to_hash,
|
@@ -43,16 +41,9 @@ module Riak
|
|
43
41
|
params[:query] = uri.query if uri.query
|
44
42
|
params[:body] = data if [:put,:post].include?(method)
|
45
43
|
params[:idempotent] = (method != :post)
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
f = Fiber.current
|
50
|
-
block = lambda {|chunk| f.resume(chunk) }
|
51
|
-
loop do
|
52
|
-
passed_block.call Fiber.yield
|
53
|
-
end
|
54
|
-
}.resume
|
55
|
-
end
|
44
|
+
|
45
|
+
block = Pump.new(block) if block_given?
|
46
|
+
|
56
47
|
response = connection.request(params, &block)
|
57
48
|
if valid_response?(expect, response.status)
|
58
49
|
response_headers.initialize_http_header(response.headers)
|
@@ -62,13 +53,18 @@ module Riak
|
|
62
53
|
end
|
63
54
|
result
|
64
55
|
else
|
65
|
-
raise
|
56
|
+
raise HTTPFailedRequest.new(method, expect, response.status, response.headers, response.body)
|
66
57
|
end
|
67
58
|
end
|
68
59
|
|
69
60
|
def connection
|
70
61
|
@connection ||= Excon::Connection.new(root_uri.to_s)
|
71
62
|
end
|
63
|
+
|
64
|
+
def configure_ssl
|
65
|
+
Excon.ssl_verify_peer = @client.ssl_options[:verify_mode].to_s === "peer"
|
66
|
+
Excon.ssl_ca_path = @client.ssl_options[:ca_path] if @client.ssl_options[:ca_path]
|
67
|
+
end
|
72
68
|
end
|
73
69
|
end
|
74
70
|
end
|
@@ -164,20 +164,20 @@ module Riak
|
|
164
164
|
# @return [Array<Object>] the list of results, if no block was
|
165
165
|
# given
|
166
166
|
def mapred(mr)
|
167
|
-
response = post(200, riak_kv_wm_mapred, mr.to_json, {"Content-Type" => "application/json", "Accept" => "application/json"})
|
168
|
-
data = begin
|
169
|
-
JSON.parse(response[:body])
|
170
|
-
rescue
|
171
|
-
response
|
172
|
-
end
|
173
|
-
# This fakes streaming until the streaming MIME parser works.
|
174
167
|
if block_given?
|
175
|
-
|
176
|
-
|
177
|
-
|
168
|
+
parser = Riak::Util::Multipart::StreamParser.new do |response|
|
169
|
+
result = JSON.parse(response[:body])
|
170
|
+
yield result['phase'], result['data']
|
178
171
|
end
|
172
|
+
post(200, riak_kv_wm_mapred, {:chunked => true}, mr.to_json, {"Content-Type" => "application/json", "Accept" => "application/json"}, &parser)
|
173
|
+
nil
|
179
174
|
else
|
180
|
-
|
175
|
+
response = post(200, riak_kv_wm_mapred, mr.to_json, {"Content-Type" => "application/json", "Accept" => "application/json"})
|
176
|
+
begin
|
177
|
+
JSON.parse(response[:body])
|
178
|
+
rescue
|
179
|
+
response
|
180
|
+
end
|
181
181
|
end
|
182
182
|
end
|
183
183
|
|
@@ -200,8 +200,8 @@ module Riak
|
|
200
200
|
Util::Multipart.parse(response[:body], boundary).map do |group|
|
201
201
|
group.map do |obj|
|
202
202
|
if obj[:headers] && obj[:body] && obj[:headers]['location']
|
203
|
-
bucket
|
204
|
-
load_object(RObject.new(client.bucket(bucket),
|
203
|
+
bucket = $1 if obj[:headers]['location'].first =~ %r{/.*/(.*)/.*$}
|
204
|
+
load_object(RObject.new(client.bucket(bucket), nil), obj)
|
205
205
|
end
|
206
206
|
end
|
207
207
|
end
|