em-riak 0.2.0 → 0.2.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/lib/em-riak/basic.rb CHANGED
@@ -7,319 +7,367 @@ require 'httpi'
7
7
  require 'yajl'
8
8
 
9
9
  module EmRiak
10
- attr_accessor :bucket, :interface, :adapter, :hosts, :cluster, :async, :http_client, :vector_lock, :replication, :debug
11
- extend self
12
-
13
- # A easy interface to create connections
14
- class Connection
15
- def initialize(*opts)
16
- if opts && opts.length>0
17
- opts=opts.first
18
- methods=[:bucket, :interface, :adapter, :hosts, :cluster, :async, :http_client, :vector_lock, :repliaction, :debug]
19
- opts.each{|key,opt| EmRiak.send "#{key}=".to_sym, opt if opt && methods.index(key.to_sym) }
20
- else
21
- EmRiak.bucket=RIAKBUCKET
22
- end
23
- EmRiak.debug=false if EmRiak.debug.nil?
24
- end
25
- def find; EmRiak.find(self); end
26
- end
27
-
28
- # -- CRUD
29
- class StorageObject < Hash
30
- def find; EmRiak.find(self); end
31
- def save; EmRiak.save(self); end
32
- def destroy; EmRiak.destroy(self); end
33
- def add_tag(*args); EmRiak::SecondaryIndex.add_tag(self,args); end
34
- def remove_tag(*args); EmRiak::SecondaryIndex.remove_tag(self,args); end
35
- def save_as_key(); EmRiak::Grapher.save_object_as_key_name(self) ; end
36
- def method_missing(name,*args)
37
- return self[name] if key? name
38
- if name.to_s.index("=")
39
- sym_name=name.to_s.gsub("=","").to_sym
40
- self[sym_name]=args.first
41
- else
42
- self.each { |k,v| return v if k.to_s.to_sym == name }
43
- super.method_missing name
44
- end
45
- end
46
- end
47
- def create(key,*opts)
48
- data={:body=>{}}
49
- data[:head], data[:query] = handle_options("save",opts)
50
- opts.first.each{|key,value| data[:body][key]=value} if opts && opts.count>0
51
-
52
- url="/buckets/#{bucket}/keys/#{key_handler(key)}"
53
- http("put",key,url,data)
54
- end
55
- def find(key,*opts)
56
- data={}; link=""
57
- data[:head], data[:query] = handle_options("get",opts)
58
- if data[:head][:link]
59
- link=data[:head][:link]
60
- data[:head].reject!{|o| o==:link}
61
- end
62
-
63
- url="/buckets/#{bucket}/keys/#{key_handler(key)}#{link}"
64
- http("get",key,url,data)
65
- end
66
- def save(obj,*opts)
67
- data={:body=>{}}
68
- obj.each{|key,value| data[:body][key]=value }
69
- data[:head], data[:query] = handle_options("save",opts)
70
-
71
- url="/buckets/#{bucket}/keys/#{obj[:riak_key]}"
72
- http("put",obj[:riak_key],url,data)
73
- end
74
- def destroy(key,*opts)
75
- data={}
76
- obj_key=defined?(obj) ? obj[:riak_key] : (key.class==String ? key : key[:riak_key])
77
- data[:head], data[:query] = handle_options("delete",opts)
78
-
79
- url="/buckets/#{bucket}/keys/#{key_handler(obj_key)}"
80
- http("put",obj_key,url,data)
81
- key=nil
82
- end
83
-
84
- # -- Search
85
- def search(*args)
86
- return "you must provide search mode" if !SEARCH_SUPPORT.index(args[0])
87
-
88
- method=args[0]
89
- collect_data=if args[1].class==Hash
90
- opts=args[1]
91
- args[2..args.count]
92
- else
93
- args[1..args.count]
94
- end
95
-
96
- return "you must provide some vars to do search, for example, bucket name, bin name..." if !defined?(opts) && method!=:map_reduce || opts[:bin].nil? && method==:secondary_index
97
-
98
- case method
99
- when :secondary_index
100
- bin=opts[:bin].to_s.index("_bin") ? opts[:bin] : "#{opts[:bin]}_bin"
101
- mapper_key=collect_data.count>1 ? :secondary_index_multiple_query : :secondary_index_single_query
102
-
103
- members={}
104
- EmRiak::MapReduce.submit(mapper_key,{'bucket'=>opts[:bucket],'index'=>bin,'value'=>collect_data.join(',')}).each do |object|
105
- if object[1]["body"]
106
- members[object[0].to_sym]=object[1]["body"]
107
- else
108
- members[object[0].to_sym]=[] if !members[object[0].to_sym]
109
- members[object[0].to_sym] << object[1]
110
- end if object[0]!=false
111
- end
112
- members
113
- when :full_text # TODO : full-text search is still under implement...
114
- []
115
- when :map_reduce
116
- EmRiak::MapReduce.submit(collect_data[0])
117
- end
118
- end
119
-
120
- def http(method,key,url,data,res=nil)
121
- self.async && ["delete","put","post"].index(method) && key!="mapred" ? em_http(method,key,url,data) : open_http(method,key,url,data)
122
- end
123
- def return_body_handler(string,hash_container,handle_type,handle_type_split_mapper={"hash"=>":","string"=>"=","common"=>","})
124
- hash_container={} if !hash_container
125
-
126
- string=string.gsub("{","").gsub("}","") if handle_type!="hash"
127
- split_by= hash_container.class==EmRiak::StorageObject ? "&" : ","
128
- string.split(split_by).each do |vars|
129
- key,value=vars.split(handle_type_split_mapper[handle_type])
130
- value=return_body_handler(value,nil,"hash") if value && value.index("{")
131
- value=json_decode("{#{value}}") if value && value.index(":") && value.index(",")
132
- hash_container[key.to_sym]=value if value
133
- end
134
- hash_container
135
- end
136
-
137
- def open_http(method,key,url,data,res={})
138
- has_http_instance?
139
- data={:body=>{},:head=>{},:query=>{}} if !data
140
-
141
- http_client.url = generate_path(url)
142
- http_client.headers = key!="mapred" ? convert_params_layers(data[:head],:to_s) : data[:head]
143
- http_client.body = key!="mapred" ? convert_params_layers(data[:body],:to_s) : data[:body]
144
-
145
- res=HTTPI.request(method.to_sym,http_client)
146
- res=res.body if res.class==HTTPI::Response
147
-
148
- res=if !["2i","mapred"].index(key) && res && !["not found\n"].index(res) && ["get","put","post"].index(method)
149
- obj=EmRiak::StorageObject.new()
150
- if res && res!="not found\n"
151
- if res.class==String
152
- obj=return_body_handler(URI.unescape(res.force_encoding("UTF-8")).gsub("+"," ").gsub("=>",":"),obj,"string")
153
- elsif res.class==Hash
154
- res.each{|varkey,value| obj[varkey.to_sym]=value }
155
- end
156
-
157
- data.each{|k,v| obj[k]=v } if res.length<1
158
- obj[:riak_key]=key if obj.length>0
159
- end
160
- obj
161
- elsif key=="mapred"
162
- res
163
- else
164
- nil
165
- end
166
- res=nil if res && res.class!=String && res.count<1
167
-
168
- return res
169
- end
170
-
171
- def em_http(method,key,url,data)
172
- data[:retry]=0 if !data[:retry]
173
- begin
174
- raise "Retry too much time" if data[:retry]>RETRY_TIMES
175
-
176
- #conn options
177
- conn_options = {
178
- :connect_timeout => EM_REQUEST_TIMEOUT, # default connection setup timeout
179
- :inactivity_timeout => EM_INACTIVITY_TIMEOUT, # default connection inactivity (post-setup) timeout
180
- }
181
-
182
- #data[:body]=data[:body] if data[:body].class==Hash && data[:head]['Content-Type'] && data[:head]['Content-Type']=="application/json"
183
- #request options
184
- data[:query]="?returnbody=true"
185
- request_options=data.reject{|k,v| k==:retry}
186
-
187
- #do job
188
- case method
189
- when "post"
190
- riakHttp = EventMachine::HttpRequest.new(hosts[rand(hosts.count)]+url).post request_options
191
- when "delete"
192
- riakHttp = EventMachine::HttpRequest.new(hosts[rand(hosts.count)]+url).delete request_options
193
- when "get"
194
- riakHttp = EventMachine::HttpRequest.new(hosts[rand(hosts.count)]+url).get request_options
195
- when "put"
196
- riakHttp = EventMachine::HttpRequest.new(hosts[rand(hosts.count)]+url).put request_options
197
- end
198
-
199
- riakHttp.errback{ #Error Callback
200
- puts "#{method} - #{key} - riak callback error #{riakHttp.response}" if EmRiak.debug
201
- data[:retry]+=1
202
- http(method,key,url,data)
203
- }
204
-
205
- #Success Callback
206
- riakHttp.callback{ puts "#{method} - #{url} - #{key} - riak response #{riakHttp.response}" if EmRiak.debug }
207
- rescue Exception => e
208
- puts "em_http - #{method} - #{url} - #{key} error #{e}" if EmRiak.debug
209
- end
210
-
211
- # Return Response
212
- res=if ["put","post"].index(method)
213
- obj=EmRiak::StorageObject.new()
214
- data.each{|k,v| obj[k]=v }
215
- obj[:riak_key]=key if obj.length>0
216
- obj
217
- else
218
- nil
219
- end
220
- res
221
- end
222
-
223
- def handle_options(action,opts,header={},query="")
224
- #Load default header setting
225
- case action
226
- when "save"
227
- header["Content-Type"]="application/json"
228
- when "get"
229
- header["Content-Type"]="application/json"
230
- when "destroy"
231
-
232
- when "add_link"
233
- header["Content-Type"]="application/json"
234
- when "remove_link"
235
- # else
236
- # header["Content-Type"]="application/json"
237
- end
238
-
239
- if opts && opts.count>0
240
- #Map & overwrite if header specisfic
241
- opts=opts.first if opts.class==Array
242
- opts.each{|k,v|
243
- meta=METAMAPPER[k]
244
- if meta
245
- header[meta[:key]] = meta[:value]
246
- opts.reject!{true}
247
- end
248
- }
249
-
250
- # --- Handle the rest headers
251
- # Link Walk
252
- if opts[:links] && (["save"].index(action))
253
- links=[]
254
- opts[:links].each{|link| links << %Q[</buckets/#{bucket}/keys/#{link[:target]}>; riaktag="#{link[:tag]}"] }
255
- header['Link']= links.join(",")
256
- elsif opts[:links] && (["add_link","remove_link"].index(action))
257
- links=[]
258
- opts[:links].each{|link| links << %Q[</buckets/#{bucket}/keys/#{link[:target]}>; riaktag="#{link[:tag]}"] }
259
- header['Link']= links
260
- elsif opts[:links] && action=="get"
261
- header["Content-Type"]="multipart/mixed"
262
- header["Accept"]="multipart/mixed"
263
- header[:link]=""
264
- keep=opts[:links][:keep] ? '1' : '0' #keep the result
265
- opts[:links][:tag].each{|tag| header[:link]+= "/#{bucket},#{tag},#{keep}" }
266
- end
267
- # 2i
268
- header["x-riak-index-#{opts[:bin].to_s}_bin"]=opts[:secondary_index].join(", ") if opts[:secondary_index]
269
-
270
- # Replication, available configs : w, dw, pw
271
- # read more at http://docs.basho.com/riak/latest/references/apis/http/HTTP-Store-Object/
272
- replication.each{|key,value| hreader[key.to_s]=value} if replication
273
-
274
- header["Content-Type"]=opts[:content_type] if opts[:content_type]
275
- header["X-Riak-Vclock"]=opts[:vlock] if opts[:vlock]
276
- header["ETag"]=opts[:etag] if opts[:etag]
277
- header["Last-Modified"]=opts[:last_modified] if opts[:last_modified]
278
- header["returnbody"]= "true" if !async
279
- #header["unique"] = true if async=false
280
- query="?returnbody=true"
281
- opts[:query].each{|k,v| query+="&#{k}={v}" } if opts[:query]
282
- end
283
- [header,query]
284
- end
285
-
286
- def key_handler(key,map={"["=>"%5B","]"=>"%5D","+"=>"%2B","/"=>"%2F","("=>"%28",")"=>"%29",":"=>"%3A"})
287
- # To match the key rule from Basho : If your field contains special characters, such as (‘+’,‘/’,‘[’,‘]’,‘(’,‘)’,‘:’ or space), then either surround the phrase in single quotes, or escape each special character with a backslash.
288
- # map.each{|origin,value| key.gsub!(origin,value) }
289
- EscapeUtils.escape_url(key.to_s.encode('UTF-8'))
290
- end
291
-
292
- def json_encode(obj,times=0)
293
- y=Yajl::Encoder.new()
294
- y.encode(obj)
295
- rescue Exception => e
296
- puts "json_encode error : #{e}" if EmRiak.debug
297
- nil
298
- end
299
- def json_decode(obj,times=0)
300
- y=Yajl::Parser.new()
301
- y.parse(obj)
302
- rescue Exception => e
303
- puts "json_decode error : #{e}" if EmRiak.debug
304
- nil
305
- end
306
-
307
- def convert_params_layers(origin,to_type,params={})
308
- origin.each{|key,value|
309
- converted=convert_params_layers(value,to_type) if value.class==Hash
310
- key=key.send(to_type)
311
- params[key]= converted ? converted : value
312
- } if origin
313
- params
314
- end
315
-
316
- private
317
- def generate_path(url); EmRiak.hosts[rand(EmRiak.hosts.length)]+url; end
318
- def has_http_instance?
319
- if !EmRiak.http_client
320
- HTTPI.log=false
321
- HTTPI.adapter=:net_http
322
- EmRiak.http_client=HTTPI::Request.new
323
- end
324
- end
10
+ attr_accessor :bucket, :interface, :adapter, :hosts, :cluster, :async, :http_client, :vector_lock, :replication, :debug
11
+ extend self
12
+
13
+ # A easy interface to create connections
14
+ class Connection
15
+ def initialize(*opts)
16
+ if opts && opts.length>0
17
+ opts=opts.first
18
+ methods=[:bucket, :interface, :adapter, :hosts, :cluster, :async, :http_client, :vector_lock, :repliaction, :debug]
19
+ opts.each{|key,opt| EmRiak.send "#{key}=".to_sym, opt if opt && methods.index(key.to_sym) }
20
+ else
21
+ EmRiak.bucket=RIAKBUCKET
22
+ end
23
+ EmRiak.debug=false if EmRiak.debug.nil?
24
+ end
25
+ end
26
+
27
+ # -- CRUD
28
+ class StorageObject < Hash
29
+ def save(block=nil); EmRiak.save(self,block); end
30
+ def destroy(block=nil); EmRiak.destroy(self,block); end
31
+ def add_tag(*args); EmRiak::SecondaryIndex.add_tag(self,args); end
32
+ def remove_tag(*args); EmRiak::SecondaryIndex.remove_tag(self,args); end
33
+ def save_as_key(); EmRiak::Grapher.save_object_as_key_name(self) ; end
34
+ def method_missing(name,*args)
35
+ return self[name] if key? name
36
+ if name.to_s.index("=")
37
+ sym_name=name.to_s.gsub("=","").to_sym
38
+ self[sym_name]=args.first
39
+ else
40
+ self.each { |k,v| return v if k.to_s.to_sym == name }
41
+ super.method_missing name
42
+ end
43
+ end
44
+ end
45
+ def create(key,*opts,&callback)
46
+ data={:body=>{}}
47
+ opts.first.each{|key,value| data[:body][key]=value} if opts && opts.count>0
48
+ data,callback=handle_callback(key,"save",opts,callback,data)
49
+
50
+ url="/buckets/#{bucket}/keys/#{key_handler(key)}"
51
+ http("put",key,url,data,callback)
52
+ end
53
+ def find(key,*opts,&callback)
54
+ link=""
55
+ data,callback=handle_callback(key,"get",opts,callback)
56
+
57
+ if data[:head][:link]
58
+ link=data[:head][:link]
59
+ data[:head].reject!{|o| o==:link}
60
+ end
61
+
62
+ url="/buckets/#{bucket}/keys/#{key_handler(key)}#{link}"
63
+ http("get",key,url,data,callback)
64
+ end
65
+ def save(obj,*opts,&callback)
66
+ data={:body=>{}}
67
+ obj.each{|key,value| data[:body][key]=value }
68
+ data,callback=handle_callback(obj[:riak_key],"save",opts,callback,data)
69
+
70
+ url="/buckets/#{bucket}/keys/#{obj[:riak_key]}"
71
+ http("put",obj[:riak_key],url,data,callback)
72
+ end
73
+ def destroy(key,*opts,&callback)
74
+ obj_key=defined?(obj) ? obj[:riak_key] : (key.class==String ? key : key[:riak_key])
75
+ data,callback=handle_callback(obj_key,"delete",opts,callback)
76
+
77
+ url="/buckets/#{bucket}/keys/#{key_handler(obj_key)}"
78
+ http("put",obj_key,url,data,callback)
79
+ key=nil
80
+ end
81
+
82
+ # -- Search
83
+ def search(method_name,*args,&callback)
84
+ result_handler=nil
85
+ response=[]
86
+ return "you must provide search mode" if !SEARCH_SUPPORT.index(method_name)
87
+
88
+ collect_data= case
89
+ when args[0].class==Hash && args.last.class==Proc
90
+ opts=args[0]
91
+ callback=args.last
92
+ args[1..args.count-2]
93
+ when args[0].class==Hash
94
+ opts=args[0]
95
+ args[1..args.count]
96
+ when args.last.class==Proc
97
+ callback=args.last
98
+ args[0..args.count-2]
99
+ else
100
+ args[0..args.count]
101
+ end
102
+
103
+ collect_data=collect_data.first if collect_data.count==1
104
+
105
+ return "you must provide some vars to do search, for example, bucket name, bin name..." if !defined?(opts) && method_name!=:map_reduce || opts[:bin].nil? && method_name==:secondary_index
106
+
107
+ case method_name
108
+ when :secondary_index
109
+ bin=opts[:bin].to_s.index("_bin") ? opts[:bin] : "#{opts[:bin]}_bin"
110
+ bucket=opts[:bucket] ? opts[:bucket] : EmRiak.bucket
111
+ mapper_key=collect_data.count>1 ? :secondary_index_multiple_query : :secondary_index_single_query
112
+
113
+ result_handler=Proc.new{|map_reduce_results,results|
114
+ map_reduce_results.each do |object|
115
+ if object[1]["body"]
116
+ results[object[0].to_sym]=object[1]["body"]
117
+ else
118
+ results[object[0].to_sym]=[] if !results[object[0].to_sym]
119
+ results[object[0].to_sym] << object[1]
120
+ end if object[0]!=false
121
+ end
122
+ }
123
+ map_reduce_work=[mapper_key,{'bucket'=>bucket,'index'=>bin,'value'=>collect_data.join(',')},result_handler,callback]
124
+ when :full_text # TODO : full-text search is still under implement...
125
+ map_reduce_work=[]
126
+ end
127
+
128
+ response=EmRiak::MapReduce.submit(map_reduce_work) if map_reduce_work.count>0
129
+ response
130
+ end
131
+
132
+ def http(method,key,url,data,callback=nil,res=nil)
133
+ (callback || self.async && ["delete","put","post"].index(method) && key!="mapred") ? em_http(method,key,url,data,callback) : open_http(method,key,url,data)
134
+ end
135
+ def return_body_handler(string,hash_container,handle_type,handle_type_split_mapper={"hash"=>":","string"=>"=","common"=>","})
136
+ hash_container={} if !hash_container
137
+
138
+ string=string.gsub("{","").gsub("}","") if handle_type!="hash"
139
+ split_by= hash_container.class==EmRiak::StorageObject ? "&" : ","
140
+ string.split(split_by).each do |vars|
141
+ key,value=vars.split(handle_type_split_mapper[handle_type])
142
+ value=return_body_handler(value,nil,"hash") if value && value.index("{")
143
+ value=json_decode("{#{value}}") if value && value.index(":") && value.index(",")
144
+ hash_container[key.to_sym]=value if value
145
+ end
146
+ hash_container
147
+ end
148
+
149
+ def open_http(method,key,url,data,res={})
150
+ has_http_instance?
151
+ data={:body=>{},:head=>{},:query=>{}} if !data
152
+
153
+ http_client.url = generate_path(url)
154
+ http_client.headers = key!="mapred" ? convert_params_layers(data[:head],:to_s) : data[:head]
155
+ http_client.body = key!="mapred" ? convert_params_layers(data[:body],:to_s) : data[:body]
156
+ http_client.open_timeout = 300 # seconds. change it if you need
157
+ http_client.read_timeout = 300 # seconds. change it if you need
158
+
159
+ res=HTTPI.request(method.to_sym,http_client)
160
+ res=res.body if res.class==HTTPI::Response
161
+
162
+ res=handle_response_string_to_object(key,res,method,data)
163
+
164
+ res=nil if res && res.class!=String && res.count<1
165
+
166
+ return res
167
+ end
168
+
169
+ def handle_response_string_to_object(key,res,method,data)
170
+ raise "response can't be nil" if !res
171
+
172
+ return res if key=="mapred"
173
+ return nil if ["2i"].index(key)
174
+
175
+ raise "data not found" if ["not found\n"].index(res)
176
+ raise "method is not match" if !["get","put","post"].index(method)
177
+ raise "data is empty" if method=="get" && res.gsub(" ","").length<1
178
+
179
+ obj=EmRiak::StorageObject.new()
180
+
181
+ if res && res!="not found\n" &&
182
+ if res.class==String
183
+ obj=return_body_handler(URI.unescape(res.force_encoding("UTF-8")).gsub("+"," ").gsub("=>",":"),obj,"string")
184
+ elsif res.class==Hash
185
+ res.each{|varkey,value| obj[varkey.to_sym]=value }
186
+ end
187
+
188
+ data.each{|k,v| obj[k]=v } if res.length<1
189
+ obj[:riak_key]=key if obj.length>0
190
+ end
191
+ return obj
192
+ rescue Exception=>e
193
+ puts "handle response error reason #{e}"
194
+ return nil
195
+ end
196
+
197
+ def em_http(method,key,url,data,async_callback)
198
+ data[:retry]=0 if !data[:retry]
199
+ begin
200
+ raise "Retry too much time" if data[:retry]>RETRY_TIMES
201
+
202
+ #conn options
203
+ conn_options = {
204
+ :connect_timeout => EM_REQUEST_TIMEOUT, # default connection setup timeout
205
+ :inactivity_timeout => EM_INACTIVITY_TIMEOUT, # default connection inactivity (post-setup) timeout
206
+ }
207
+ #data[:body]=data[:body] if data[:body].class==Hash && data[:head]['Content-Type'] && data[:head]['Content-Type']=="application/json"
208
+ #request options
209
+ data[:query]="?returnbody=true"
210
+ request_options=data.reject{|k,v| k==:retry}
211
+
212
+ #do job
213
+ case method
214
+ when "post"
215
+ riakHttp = EventMachine::HttpRequest.new(hosts[rand(hosts.count)]+url).post request_options
216
+ when "delete"
217
+ riakHttp = EventMachine::HttpRequest.new(hosts[rand(hosts.count)]+url).delete request_options
218
+ when "get"
219
+ riakHttp = EventMachine::HttpRequest.new(hosts[rand(hosts.count)]+url).get request_options
220
+ when "put"
221
+ riakHttp = EventMachine::HttpRequest.new(hosts[rand(hosts.count)]+url).put request_options
222
+ end
223
+
224
+ riakHttp.errback{ #Error Callback
225
+ puts "#{method} - #{key} - riak callback error #{riakHttp.response}" if EmRiak.debug
226
+ data[:retry]+=1
227
+ http(method,key,url,data,async_callback)
228
+ }
229
+
230
+ #Success Callback
231
+ riakHttp.callback{
232
+ puts "#{method} - #{url} - #{key} - riak response #{riakHttp.response}" if EmRiak.debug
233
+ async_callback.call(riakHttp.response) if async_callback
234
+ }
235
+ rescue Exception => e
236
+ puts "em_http - #{method} - #{url} - #{key} error #{e}" if EmRiak.debug
237
+ end
238
+
239
+ # Return Response
240
+ res=if ["put","post"].index(method)
241
+ obj=EmRiak::StorageObject.new()
242
+ data.each{|k,v| obj[k]=v }
243
+ obj[:riak_key]=key if obj.length>0
244
+ obj
245
+ else
246
+ nil
247
+ end
248
+ res
249
+ end
250
+
251
+ def handle_callback(key,method,opts,callback,data={})
252
+ option_response=handle_options(method,opts)
253
+ if callback
254
+ data[:head], data[:query] = option_response
255
+ else
256
+ data[:head], data[:query], callback = option_response
257
+ end
258
+
259
+ new_proc=Proc.new{|res|
260
+ obj=handle_response_string_to_object(key,res,method,data)
261
+ callback.call(obj)
262
+ } if callback
263
+
264
+ [data,new_proc]
265
+ end
266
+ def handle_options(action,opts,header={},query="")
267
+ #Load default header setting
268
+ case action
269
+ when "save"
270
+ header["Content-Type"]="application/json"
271
+ when "get"
272
+ header["Content-Type"]="application/json"
273
+ when "destroy","delete"
274
+ header["Content-Type"]="application/json"
275
+ when "add_link"
276
+ header["Content-Type"]="application/json"
277
+ when "remove_link"
278
+ # else
279
+ # header["Content-Type"]="application/json"
280
+ end
281
+ # Map & overwrite if header specisfic
282
+ opts=opts.first if opts && opts.class==Array
283
+
284
+ if opts && opts.count>0
285
+ # Map the options class
286
+ callback=opts.reject!{|obj| obj.class==Proc}
287
+
288
+ opts.each{|k,v|
289
+ meta=METAMAPPER[k]
290
+ if meta
291
+ header[meta[:key]] = meta[:value]
292
+ opts.reject!{true}
293
+ end
294
+ }
295
+
296
+ # --- Handle the rest headers
297
+ # Link Walk
298
+ if opts[:links] && (["save"].index(action))
299
+ links=[]
300
+ opts[:links].each{|link| links << %Q[</buckets/#{bucket}/keys/#{link[:target]}>; riaktag="#{link[:tag]}"] }
301
+ header['Link']= links.join(",")
302
+ elsif opts[:links] && (["add_link","remove_link"].index(action))
303
+ links=[]
304
+ opts[:links].each{|link| links << %Q[</buckets/#{bucket}/keys/#{link[:target]}>; riaktag="#{link[:tag]}"] }
305
+ header['Link']= links
306
+ elsif opts[:links] && action=="get"
307
+ header["Content-Type"]="multipart/mixed"
308
+ header["Accept"]="multipart/mixed"
309
+ header[:link]=""
310
+ keep=opts[:links][:keep] ? '1' : '0' #keep the result
311
+ opts[:links][:tag].each{|tag| header[:link]+= "/#{bucket},#{tag},#{keep}" }
312
+ end
313
+ # 2i
314
+ header["x-riak-index-#{opts[:bin].to_s}_bin"]=opts[:secondary_index].join(", ") if opts[:secondary_index]
315
+
316
+ # Replication, available configs : w, dw, pw
317
+ # read more at http://docs.basho.com/riak/latest/references/apis/http/HTTP-Store-Object/
318
+ replication.each{|key,value| hreader[key.to_s]=value} if replication
319
+
320
+ header["Content-Type"]=opts[:content_type] if opts[:content_type]
321
+ header["X-Riak-Vclock"]=opts[:vlock] if opts[:vlock]
322
+ header["ETag"]=opts[:etag] if opts[:etag]
323
+ header["Last-Modified"]=opts[:last_modified] if opts[:last_modified]
324
+ header["returnbody"]= "true" if !async
325
+ #header["unique"] = true if async=false
326
+ query="?returnbody=true"
327
+ opts[:query].each{|k,v| query+="&#{k}={v}" } if opts[:query]
328
+ end
329
+ res=[header,query]
330
+ res << callback if callback
331
+ res
332
+ end
333
+
334
+ def key_handler(key,map={"["=>"%5B","]"=>"%5D","+"=>"%2B","/"=>"%2F","("=>"%28",")"=>"%29",":"=>"%3A"})
335
+ # To match the key rule from Basho : If your field contains special characters, such as (‘+’,‘/’,‘[’,‘]’,‘(’,‘)’,‘:’ or space), then either surround the phrase in single quotes, or escape each special character with a backslash.
336
+ # map.each{|origin,value| key.gsub!(origin,value) }
337
+ EscapeUtils.escape_url(key.to_s.encode('UTF-8'))
338
+ end
339
+
340
+ def json_encode(obj,times=0)
341
+ y=Yajl::Encoder.new()
342
+ y.encode(obj)
343
+ rescue Exception => e
344
+ puts "json_encode error : #{e}" if EmRiak.debug
345
+ obj
346
+ end
347
+ def json_decode(obj,times=0)
348
+ y=Yajl::Parser.new()
349
+ y.parse(obj)
350
+ rescue Exception => e
351
+ puts "json_decode error : #{e}" if EmRiak.debug
352
+ obj
353
+ end
354
+
355
+ def convert_params_layers(origin,to_type,params={})
356
+ origin.each{|key,value|
357
+ converted=convert_params_layers(value,to_type) if value.class==Hash
358
+ key=key.send(to_type)
359
+ params[key]= converted ? converted : value
360
+ } if origin
361
+ params
362
+ end
363
+
364
+ private
365
+ def generate_path(url); EmRiak.hosts[rand(EmRiak.hosts.length)]+url; end
366
+ def has_http_instance?
367
+ if !EmRiak.http_client
368
+ HTTPI.log=false
369
+ HTTPI.adapter=:net_http
370
+ EmRiak.http_client=HTTPI::Request.new
371
+ end
372
+ end
325
373
  end