better-riak-client 1.0.5
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/LICENSE +16 -0
- data/README.markdown +198 -0
- data/RELEASE_NOTES.md +211 -0
- data/better-riak-client.gemspec +61 -0
- data/erl_src/riak_kv_test014_backend.beam +0 -0
- data/erl_src/riak_kv_test014_backend.erl +189 -0
- data/erl_src/riak_kv_test_backend.beam +0 -0
- data/erl_src/riak_kv_test_backend.erl +697 -0
- data/erl_src/riak_search_test_backend.beam +0 -0
- data/erl_src/riak_search_test_backend.erl +175 -0
- data/lib/riak/bucket.rb +221 -0
- data/lib/riak/client/beefcake/messages.rb +213 -0
- data/lib/riak/client/beefcake/object_methods.rb +111 -0
- data/lib/riak/client/beefcake_protobuffs_backend.rb +226 -0
- data/lib/riak/client/decaying.rb +36 -0
- data/lib/riak/client/excon_backend.rb +162 -0
- data/lib/riak/client/feature_detection.rb +88 -0
- data/lib/riak/client/http_backend/configuration.rb +211 -0
- data/lib/riak/client/http_backend/key_streamer.rb +43 -0
- data/lib/riak/client/http_backend/object_methods.rb +106 -0
- data/lib/riak/client/http_backend/request_headers.rb +34 -0
- data/lib/riak/client/http_backend/transport_methods.rb +201 -0
- data/lib/riak/client/http_backend.rb +340 -0
- data/lib/riak/client/net_http_backend.rb +82 -0
- data/lib/riak/client/node.rb +115 -0
- data/lib/riak/client/protobuffs_backend.rb +173 -0
- data/lib/riak/client/search.rb +91 -0
- data/lib/riak/client.rb +540 -0
- data/lib/riak/cluster.rb +151 -0
- data/lib/riak/core_ext/blank.rb +53 -0
- data/lib/riak/core_ext/deep_dup.rb +13 -0
- data/lib/riak/core_ext/extract_options.rb +7 -0
- data/lib/riak/core_ext/json.rb +15 -0
- data/lib/riak/core_ext/slice.rb +18 -0
- data/lib/riak/core_ext/stringify_keys.rb +10 -0
- data/lib/riak/core_ext/symbolize_keys.rb +10 -0
- data/lib/riak/core_ext/to_param.rb +31 -0
- data/lib/riak/core_ext.rb +7 -0
- data/lib/riak/encoding.rb +6 -0
- data/lib/riak/failed_request.rb +81 -0
- data/lib/riak/i18n.rb +5 -0
- data/lib/riak/json.rb +52 -0
- data/lib/riak/link.rb +94 -0
- data/lib/riak/locale/en.yml +53 -0
- data/lib/riak/locale/fr.yml +52 -0
- data/lib/riak/map_reduce/filter_builder.rb +103 -0
- data/lib/riak/map_reduce/phase.rb +98 -0
- data/lib/riak/map_reduce.rb +225 -0
- data/lib/riak/map_reduce_error.rb +7 -0
- data/lib/riak/node/configuration.rb +293 -0
- data/lib/riak/node/console.rb +133 -0
- data/lib/riak/node/control.rb +207 -0
- data/lib/riak/node/defaults.rb +83 -0
- data/lib/riak/node/generation.rb +106 -0
- data/lib/riak/node/log.rb +34 -0
- data/lib/riak/node/version.rb +43 -0
- data/lib/riak/node.rb +38 -0
- data/lib/riak/robject.rb +318 -0
- data/lib/riak/search.rb +3 -0
- data/lib/riak/serializers.rb +74 -0
- data/lib/riak/stamp.rb +77 -0
- data/lib/riak/test_server.rb +89 -0
- data/lib/riak/util/escape.rb +76 -0
- data/lib/riak/util/headers.rb +53 -0
- data/lib/riak/util/multipart/stream_parser.rb +62 -0
- data/lib/riak/util/multipart.rb +52 -0
- data/lib/riak/util/tcp_socket_extensions.rb +58 -0
- data/lib/riak/util/translation.rb +19 -0
- data/lib/riak/version.rb +3 -0
- data/lib/riak/walk_spec.rb +105 -0
- data/lib/riak.rb +21 -0
- metadata +348 -0
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'riak/robject'
|
2
|
+
require 'riak/link'
|
3
|
+
require 'riak/client/beefcake/messages'
|
4
|
+
|
5
|
+
module Riak
|
6
|
+
class Client
|
7
|
+
class BeefcakeProtobuffsBackend
|
8
|
+
module ObjectMethods
|
9
|
+
ENCODING = "Riak".respond_to?(:encoding)
|
10
|
+
|
11
|
+
# Returns RpbPutReq
|
12
|
+
def dump_object(robject, options={})
|
13
|
+
pbuf = RpbPutReq.new(options.merge(:bucket => maybe_encode(robject.bucket.name)))
|
14
|
+
pbuf.key = maybe_encode(robject.key) if robject.key # Put w/o key supported!
|
15
|
+
pbuf.vclock = maybe_encode(Base64.decode64(robject.vclock)) if robject.vclock
|
16
|
+
pbuf.content = RpbContent.new(:value => maybe_encode(robject.raw_data),
|
17
|
+
:content_type => maybe_encode(robject.content_type),
|
18
|
+
:links => robject.links.map {|l| encode_link(l) }.compact,
|
19
|
+
:indexes => robject.indexes.map {|k,s| encode_index(k,s) }.flatten)
|
20
|
+
|
21
|
+
pbuf.content.usermeta = robject.meta.map {|k,v| encode_meta(k,v)} if robject.meta.any?
|
22
|
+
pbuf.content.vtag = maybe_encode(robject.etag) if robject.etag.present?
|
23
|
+
if ENCODING # 1.9 support
|
24
|
+
pbuf.content.charset = maybe_encode(robject.raw_data.encoding.name)
|
25
|
+
end
|
26
|
+
pbuf
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns RObject
|
30
|
+
def load_object(pbuf, robject)
|
31
|
+
return robject if pbuf.respond_to?(:unchanged) && pbuf.unchanged # Reloading
|
32
|
+
robject.vclock = Base64.encode64(pbuf.vclock).chomp if pbuf.vclock
|
33
|
+
robject.key = maybe_unescape(pbuf.key) if pbuf.respond_to?(:key) && pbuf.key # Put w/o key
|
34
|
+
if pbuf.content.size > 1
|
35
|
+
robject.conflict = true
|
36
|
+
robject.siblings = pbuf.content.map do |c|
|
37
|
+
sibling = RObject.new(robject.bucket, robject.key)
|
38
|
+
sibling.vclock = robject.vclock
|
39
|
+
load_content(c, sibling)
|
40
|
+
end
|
41
|
+
|
42
|
+
return robject.attempt_conflict_resolution
|
43
|
+
else
|
44
|
+
load_content(pbuf.content.first, robject)
|
45
|
+
end
|
46
|
+
robject
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
def load_content(pbuf, robject)
|
51
|
+
if ENCODING && pbuf.charset.present?
|
52
|
+
pbuf.value.force_encoding(pbuf.charset) if Encoding.find(pbuf.charset)
|
53
|
+
end
|
54
|
+
robject.raw_data = pbuf.value
|
55
|
+
robject.etag = pbuf.vtag if pbuf.vtag.present?
|
56
|
+
robject.content_type = pbuf.content_type if pbuf.content_type.present?
|
57
|
+
robject.links = pbuf.links.map(&method(:decode_link)) if pbuf.links.present?
|
58
|
+
pbuf.usermeta.each {|pair| decode_meta(pair, robject.meta) } if pbuf.usermeta.present?
|
59
|
+
if pbuf.indexes.present?
|
60
|
+
robject.indexes.clear
|
61
|
+
pbuf.indexes.each {|pair| decode_index(pair, robject.indexes) }
|
62
|
+
end
|
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 => maybe_encode(link.bucket.to_s),
|
77
|
+
:key => maybe_encode(link.key.to_s),
|
78
|
+
:tag => maybe_encode(link.tag.to_s))
|
79
|
+
end
|
80
|
+
|
81
|
+
def decode_meta(pbuf, hash)
|
82
|
+
hash[pbuf.key] = pbuf.value
|
83
|
+
end
|
84
|
+
|
85
|
+
def encode_meta(key,value)
|
86
|
+
return nil unless value.present?
|
87
|
+
RpbPair.new(:key => maybe_encode(key.to_s),
|
88
|
+
:value => maybe_encode(value.to_s))
|
89
|
+
end
|
90
|
+
|
91
|
+
def decode_index(pbuf, hash)
|
92
|
+
value = pbuf.key =~ /int$/ ? pbuf.value.to_i : pbuf.value
|
93
|
+
hash[pbuf.key] << value
|
94
|
+
end
|
95
|
+
|
96
|
+
def encode_index(key, set)
|
97
|
+
set.map do |v|
|
98
|
+
RpbPair.new(:key => maybe_encode(key),
|
99
|
+
:value => maybe_encode(v.to_s))
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def maybe_encode(string)
|
104
|
+
ENCODING ? string.dup.force_encoding('BINARY') : string
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
include ObjectMethods
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'riak/json'
|
3
|
+
require 'riak/client'
|
4
|
+
require 'riak/failed_request'
|
5
|
+
require 'riak/client/protobuffs_backend'
|
6
|
+
|
7
|
+
module Riak
|
8
|
+
class Client
|
9
|
+
class BeefcakeProtobuffsBackend < ProtobuffsBackend
|
10
|
+
def self.configured?
|
11
|
+
begin
|
12
|
+
require 'beefcake'
|
13
|
+
require 'riak/client/beefcake/messages'
|
14
|
+
require 'riak/client/beefcake/object_methods'
|
15
|
+
true
|
16
|
+
rescue LoadError, NameError
|
17
|
+
false
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def set_client_id(id)
|
22
|
+
value = case id
|
23
|
+
when Integer
|
24
|
+
[id].pack("N")
|
25
|
+
else
|
26
|
+
id.to_s
|
27
|
+
end
|
28
|
+
req = RpbSetClientIdReq.new(:client_id => value)
|
29
|
+
write_protobuff(:SetClientIdReq, req)
|
30
|
+
decode_response
|
31
|
+
end
|
32
|
+
|
33
|
+
def fetch_object(bucket, key, options={})
|
34
|
+
options = prune_unsupported_options(:GetReq, normalize_quorums(options))
|
35
|
+
bucket = Bucket === bucket ? bucket.name : bucket
|
36
|
+
req = RpbGetReq.new(options.merge(:bucket => maybe_encode(bucket), :key => maybe_encode(key)))
|
37
|
+
write_protobuff(:GetReq, req)
|
38
|
+
decode_response(RObject.new(client.bucket(bucket), key))
|
39
|
+
end
|
40
|
+
|
41
|
+
def reload_object(robject, options={})
|
42
|
+
options = normalize_quorums(options)
|
43
|
+
options[:bucket] = maybe_encode(robject.bucket.name)
|
44
|
+
options[:key] = maybe_encode(robject.key)
|
45
|
+
options[:if_modified] = maybe_encode Base64.decode64(robject.vclock) if robject.vclock
|
46
|
+
req = RpbGetReq.new(prune_unsupported_options(:GetReq, options))
|
47
|
+
write_protobuff(:GetReq, req)
|
48
|
+
decode_response(robject)
|
49
|
+
end
|
50
|
+
|
51
|
+
def store_object(robject, options={})
|
52
|
+
options = normalize_quorums(options)
|
53
|
+
if robject.prevent_stale_writes
|
54
|
+
unless pb_conditionals?
|
55
|
+
other = fetch_object(robject.bucket, robject.key)
|
56
|
+
raise Riak::ProtobuffsFailedRequest.new(:stale_object, t("stale_write_prevented")) unless other.vclock == robject.vclock
|
57
|
+
end
|
58
|
+
if robject.vclock
|
59
|
+
options[:if_not_modified] = true
|
60
|
+
else
|
61
|
+
options[:if_none_match] = true
|
62
|
+
end
|
63
|
+
end
|
64
|
+
req = dump_object(robject, prune_unsupported_options(:PutReq, options))
|
65
|
+
write_protobuff(:PutReq, req)
|
66
|
+
decode_response(robject)
|
67
|
+
end
|
68
|
+
|
69
|
+
def delete_object(bucket, key, options={})
|
70
|
+
bucket = Bucket === bucket ? bucket.name : bucket
|
71
|
+
options = normalize_quorums(options)
|
72
|
+
options[:bucket] = maybe_encode(bucket)
|
73
|
+
options[:key] = maybe_encode(key)
|
74
|
+
options[:vclock] = Base64.decode64(options[:vclock]) if options[:vclock]
|
75
|
+
req = RpbDelReq.new(prune_unsupported_options(:DelReq, options))
|
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 => maybe_encode(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 => maybe_encode(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 => maybe_encode(bucket))
|
98
|
+
write_protobuff(:ListKeysReq, req)
|
99
|
+
keys = []
|
100
|
+
while msg = decode_response
|
101
|
+
break if msg.done
|
102
|
+
if block_given?
|
103
|
+
yield msg.keys
|
104
|
+
else
|
105
|
+
keys += msg.keys
|
106
|
+
end
|
107
|
+
end
|
108
|
+
block_given? || keys
|
109
|
+
end
|
110
|
+
|
111
|
+
def mapred(mr, &block)
|
112
|
+
raise MapReduceError.new(t("empty_map_reduce_query")) if mr.query.empty? && !mapred_phaseless?
|
113
|
+
req = RpbMapRedReq.new(:request => mr.to_json, :content_type => "application/json")
|
114
|
+
write_protobuff(:MapRedReq, req)
|
115
|
+
results = []
|
116
|
+
while msg = decode_response
|
117
|
+
break if msg.done
|
118
|
+
if block_given?
|
119
|
+
yield msg.phase, JSON.parse(msg.response)
|
120
|
+
else
|
121
|
+
results[msg.phase] ||= []
|
122
|
+
results[msg.phase] += JSON.parse(msg.response)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
block_given? || results.compact.size == 1 ? results.last : results
|
126
|
+
end
|
127
|
+
|
128
|
+
def get_index(bucket, index, query)
|
129
|
+
return super unless pb_indexes?
|
130
|
+
if Range === query
|
131
|
+
options = {
|
132
|
+
:qtype => RpbIndexReq::IndexQueryType::RANGE,
|
133
|
+
:range_min => query.begin.to_s,
|
134
|
+
:range_max => query.end.to_s
|
135
|
+
}
|
136
|
+
else
|
137
|
+
options = {
|
138
|
+
:qtype => RpbIndexReq::IndexQueryType::EQ,
|
139
|
+
:key => query.to_s
|
140
|
+
}
|
141
|
+
end
|
142
|
+
req = RpbIndexReq.new(options.merge(:bucket => bucket, :index => index))
|
143
|
+
write_protobuff(:IndexReq, req)
|
144
|
+
decode_response
|
145
|
+
end
|
146
|
+
|
147
|
+
def search(index, query, options={})
|
148
|
+
return super unless pb_search?
|
149
|
+
options = options.symbolize_keys
|
150
|
+
options[:op] = options.delete(:'q.op') if options[:'q.op']
|
151
|
+
req = RpbSearchQueryReq.new(options.merge(:index => index || 'search', :q => query))
|
152
|
+
write_protobuff(:SearchQueryReq, req)
|
153
|
+
decode_response
|
154
|
+
end
|
155
|
+
|
156
|
+
private
|
157
|
+
def write_protobuff(code, message)
|
158
|
+
encoded = message.encode
|
159
|
+
header = [encoded.length+1, MESSAGE_CODES.index(code)].pack("NC")
|
160
|
+
socket.write(header + encoded)
|
161
|
+
end
|
162
|
+
|
163
|
+
def decode_response(*args)
|
164
|
+
header = socket.read(5)
|
165
|
+
raise SocketError, "Unexpected EOF on PBC socket" if header.nil?
|
166
|
+
msglen, msgcode = header.unpack("NC")
|
167
|
+
if msglen == 1
|
168
|
+
case MESSAGE_CODES[msgcode]
|
169
|
+
when :PingResp, :SetClientIdResp, :PutResp, :DelResp, :SetBucketResp
|
170
|
+
true
|
171
|
+
when :ListBucketsResp, :ListKeysResp
|
172
|
+
[]
|
173
|
+
when :GetResp
|
174
|
+
raise Riak::ProtobuffsFailedRequest.new(:not_found, t('not_found'))
|
175
|
+
else
|
176
|
+
false
|
177
|
+
end
|
178
|
+
else
|
179
|
+
message = socket.read(msglen-1)
|
180
|
+
case MESSAGE_CODES[msgcode]
|
181
|
+
when :ErrorResp
|
182
|
+
res = RpbErrorResp.decode(message)
|
183
|
+
raise Riak::ProtobuffsFailedRequest.new(res.errcode, res.errmsg)
|
184
|
+
when :GetClientIdResp
|
185
|
+
res = RpbGetClientIdResp.decode(message)
|
186
|
+
res.client_id
|
187
|
+
when :GetServerInfoResp
|
188
|
+
res = RpbGetServerInfoResp.decode(message)
|
189
|
+
{:node => res.node, :server_version => res.server_version}
|
190
|
+
when :GetResp
|
191
|
+
res = RpbGetResp.decode(message)
|
192
|
+
load_object(res, args.first)
|
193
|
+
when :PutResp
|
194
|
+
res = RpbPutResp.decode(message)
|
195
|
+
load_object(res, args.first)
|
196
|
+
when :ListBucketsResp
|
197
|
+
res = RpbListBucketsResp.decode(message)
|
198
|
+
res.buckets
|
199
|
+
when :ListKeysResp
|
200
|
+
RpbListKeysResp.decode(message)
|
201
|
+
when :GetBucketResp
|
202
|
+
res = RpbGetBucketResp.decode(message)
|
203
|
+
{'n_val' => res.props.n_val, 'allow_mult' => res.props.allow_mult}
|
204
|
+
when :MapRedResp
|
205
|
+
RpbMapRedResp.decode(message)
|
206
|
+
when :IndexResp
|
207
|
+
res = RpbIndexResp.decode(message)
|
208
|
+
res.keys
|
209
|
+
when :SearchQueryResp
|
210
|
+
res = RpbSearchQueryResp.decode(message)
|
211
|
+
{ 'docs' => res.docs.map {|d| decode_doc(d) },
|
212
|
+
'max_score' => res.max_score,
|
213
|
+
'num_found' => res.num_found }
|
214
|
+
end
|
215
|
+
end
|
216
|
+
rescue SystemCallError, SocketError => e
|
217
|
+
reset_socket
|
218
|
+
raise
|
219
|
+
end
|
220
|
+
|
221
|
+
def decode_doc(doc)
|
222
|
+
Hash[doc.properties.map {|p| [ p.key, p.value ] }]
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Riak
|
2
|
+
class Client
|
3
|
+
# A float value which decays exponentially toward 0 over time.
|
4
|
+
# @private
|
5
|
+
class Decaying
|
6
|
+
attr_accessor :e
|
7
|
+
attr_accessor :p
|
8
|
+
|
9
|
+
# @param [Hash] opts options
|
10
|
+
# @option options [Float] :p (0.0) The initial value
|
11
|
+
# @option options [Float] :e (Math::E) Exponent base
|
12
|
+
# @option options [Float] :r (Math.log(0.5) / 10) Timescale
|
13
|
+
# factor - defaulting to decay 50% every 10 seconds
|
14
|
+
def initialize(opts = {})
|
15
|
+
@p = opts[:p] || 0.0
|
16
|
+
@e = opts[:e] || Math::E
|
17
|
+
@r = opts[:r] || Math.log(0.5) / 10
|
18
|
+
@t0 = Time.now
|
19
|
+
end
|
20
|
+
|
21
|
+
# Add to current value.
|
22
|
+
# @param [Float] d the value to add
|
23
|
+
def <<(d)
|
24
|
+
@p = value + d
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [Float] the current value (adjusted for the time decay)
|
28
|
+
def value
|
29
|
+
now = Time.now
|
30
|
+
dt = now - @t0
|
31
|
+
@t0 = now
|
32
|
+
@p = @p * (@e ** (@r * dt))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
require 'riak/failed_request'
|
2
|
+
require 'riak/client/http_backend'
|
3
|
+
require 'riak/client/http_backend/request_headers'
|
4
|
+
|
5
|
+
module Riak
|
6
|
+
class Client
|
7
|
+
# An HTTP backend for Riak::Client that uses Wesley Beary's Excon
|
8
|
+
# HTTP library. Conforms to the Riak::Client::HTTPBackend
|
9
|
+
# interface.
|
10
|
+
class ExconBackend < HTTPBackend
|
11
|
+
def self.configured?
|
12
|
+
begin
|
13
|
+
require 'excon'
|
14
|
+
minimum_version?("0.5.7") && register_exceptions && handle_deprecations && patch_sockets
|
15
|
+
rescue LoadError
|
16
|
+
false
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Adds Excon's relevant internal exceptions to the rescuable
|
21
|
+
# network-related errors.
|
22
|
+
def self.register_exceptions
|
23
|
+
unless Client::NETWORK_ERRORS.include?(Excon::Errors::SocketError)
|
24
|
+
Client::NETWORK_ERRORS << Excon::Errors::SocketError
|
25
|
+
Client::NETWORK_ERRORS << Excon::Errors::Timeout if defined? Excon::Errors::Timeout
|
26
|
+
end
|
27
|
+
true
|
28
|
+
end
|
29
|
+
|
30
|
+
# Adjusts Excon's connection collection to allow multiple
|
31
|
+
# connections to the same host from the same Thread. Instead we
|
32
|
+
# use the Riak::Client::Pool to segregate connections.
|
33
|
+
# @note This can be changed when Excon has a proper pool of its own.
|
34
|
+
def self.patch_sockets
|
35
|
+
unless defined? @@patched
|
36
|
+
::Excon::Connection.class_eval do
|
37
|
+
def sockets
|
38
|
+
@sockets ||= {}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
@@patched = true
|
43
|
+
end
|
44
|
+
|
45
|
+
# Defines instance methods that handle changes in the Excon API
|
46
|
+
# across different versions.
|
47
|
+
def self.handle_deprecations
|
48
|
+
# Define #make_request
|
49
|
+
unless method_defined?(:make_request)
|
50
|
+
if minimum_version?("0.10.2")
|
51
|
+
def make_request(params, block)
|
52
|
+
params[:response_block] = block if block
|
53
|
+
connection.request(params)
|
54
|
+
end
|
55
|
+
else
|
56
|
+
def make_request(params, block)
|
57
|
+
response = connection.request(params, &block)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
private :make_request
|
61
|
+
end
|
62
|
+
|
63
|
+
# Define #configure_ssl
|
64
|
+
unless method_defined?(:configure_ssl)
|
65
|
+
if minimum_version?("0.9.6")
|
66
|
+
def configure_ssl
|
67
|
+
Excon.defaults[:ssl_verify_peer] = (@node.ssl_options[:verify_mode].to_s === "peer")
|
68
|
+
Excon.defaults[:ssl_ca_path] = @node.ssl_options[:ca_path] if @node.ssl_options[:ca_path]
|
69
|
+
end
|
70
|
+
else
|
71
|
+
def configure_ssl
|
72
|
+
Excon.ssl_verify_peer = (@node.ssl_options[:verify_mode].to_s === "peer")
|
73
|
+
Excon.ssl_ca_path = @node.ssl_options[:ca_path] if @node.ssl_options[:ca_path]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
private :configure_ssl
|
77
|
+
end
|
78
|
+
true
|
79
|
+
end
|
80
|
+
|
81
|
+
# Returns true if the Excon library is at least the given
|
82
|
+
# version. This is used inside the backend to check how to
|
83
|
+
# provide certain request and configuration options.
|
84
|
+
def self.minimum_version?(version)
|
85
|
+
Gem::Version.new(Excon::VERSION) >= Gem::Version.new(version)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Sets the connect timeout applied to the Excon connection
|
89
|
+
# Increase this if you have very long request times.
|
90
|
+
def self.connect_timeout=(timeout)
|
91
|
+
@connect_timeout = timeout
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.connect_timeout
|
95
|
+
@connect_timeout ||= 4096
|
96
|
+
end
|
97
|
+
|
98
|
+
# Sets the read_timeout applied to the Excon connection
|
99
|
+
# Increase this if you have very long request times.
|
100
|
+
def self.read_timeout=(timeout)
|
101
|
+
@read_timeout = timeout
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.read_timeout
|
105
|
+
@read_timeout ||= 4096
|
106
|
+
end
|
107
|
+
|
108
|
+
# Sets the write_timeout applied to the Excon connection
|
109
|
+
# Increase this if you have very long request times.
|
110
|
+
def self.write_timeout=(timeout)
|
111
|
+
@write_timeout = timeout
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.write_timeout
|
115
|
+
@write_timeout ||= 4096
|
116
|
+
end
|
117
|
+
|
118
|
+
def teardown
|
119
|
+
connection.reset
|
120
|
+
end
|
121
|
+
|
122
|
+
private
|
123
|
+
def perform(method, uri, headers, expect, data=nil, &block)
|
124
|
+
configure_ssl if @node.ssl_enabled?
|
125
|
+
|
126
|
+
params = {
|
127
|
+
:method => method.to_s.upcase,
|
128
|
+
:headers => RequestHeaders.new(headers).to_hash,
|
129
|
+
:path => uri.path
|
130
|
+
}
|
131
|
+
params[:query] = uri.query if uri.query
|
132
|
+
params[:body] = data if [:put,:post].include?(method)
|
133
|
+
params[:idempotent] = (method != :post)
|
134
|
+
|
135
|
+
# Later versions of Excon pass multiple arguments to the block
|
136
|
+
block = lambda {|*args| yield args.first } if block_given?
|
137
|
+
|
138
|
+
response = make_request(params, block)
|
139
|
+
response_headers.initialize_http_header(response.headers)
|
140
|
+
|
141
|
+
if valid_response?(expect, response.status)
|
142
|
+
result = {:headers => response_headers.to_hash, :code => response.status}
|
143
|
+
if return_body?(method, response.status, block_given?)
|
144
|
+
result[:body] = response.body
|
145
|
+
end
|
146
|
+
result
|
147
|
+
else
|
148
|
+
raise HTTPFailedRequest.new(method, expect, response.status, response_headers.to_hash, response.body)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def connection
|
153
|
+
@connection ||= Excon::Connection.new(
|
154
|
+
root_uri.to_s,
|
155
|
+
:read_timeout => self.class.read_timeout,
|
156
|
+
:write_timeout => self.class.write_timeout,
|
157
|
+
:connect_timeout => self.class.connect_timeout
|
158
|
+
)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|