riakpb 0.1.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.
data/lib/riak/key.rb ADDED
@@ -0,0 +1,284 @@
1
+ require 'riak'
2
+
3
+ module Riak
4
+ # Represents and encapsulates operations on a Riak bucket. You may retrieve a bucket
5
+ # using {Client#bucket}, or create it manually and retrieve its meta-information later.
6
+ class Key
7
+ include Util::Translation
8
+ include Util::MessageCode
9
+
10
+ # @return [Riak::Client] the associated client
11
+ attr_reader :bucket
12
+
13
+ # @return [String] the bucket name
14
+ attr_reader :name
15
+
16
+ # @return [String] the bucket name
17
+ attr_reader :vclock
18
+
19
+ # Create a Riak bucket manually.
20
+ # @param [Bucket] bucket the Bucket object within which this Key exists
21
+ # @option options [String] name the name assigned to this Key entity
22
+ # @option options [Fixnum] vclock Careful! Do not set this unless you have a reason to
23
+ # @option options [RiakContent] content a content object, that's to be inserted in this Key
24
+ def initialize(bucket, key, get_response=nil)
25
+ # options.assert_valid_keys(:name, :vclock, :content)
26
+
27
+ self.bucket = bucket
28
+ self.name = key
29
+
30
+ @contents = Hash.new{|k,v| k[v] = Riak::RiakContent.new(self)}
31
+
32
+ # @contents[:new]
33
+
34
+ load(get_response) unless get_response.nil?
35
+ end
36
+
37
+ # Load information for the key from the response object, Riak::RpbGetResp.
38
+ #
39
+ # @param [RpbGetResp/Hash] response an RpbGetResp/RpbPutResp object or a Hash.
40
+ # @return [Key] self
41
+ def load(response)
42
+ @blargh = response
43
+ raise ArgumentError, t("response_type") unless response.is_a?(Protobuf::Message)
44
+
45
+ self.vclock = response.vclock if response.has_field?(:vclock)
46
+
47
+ if response.has_field?(:content)
48
+ self.content = response.content
49
+ elsif @contents.empty?
50
+ @contents[:new]
51
+ end
52
+
53
+ return(self)
54
+ end
55
+
56
+ # Load information for the key from Riak::RpbGetResp object.
57
+ #
58
+ # @param [RpbGetResp/Hash] response an RpbGetResp/RpbPutResp object or a Hash.
59
+ # @return [Key] self
60
+ def load!(response)
61
+ raise ArgumentError, t("response_type") unless response.is_a?(Riak::RpbGetResp)
62
+
63
+ if response.has_field?(:vclock) and response.has_field?(:content)
64
+
65
+ self.vclock = response.vclock
66
+ self.content = response.content
67
+
68
+ elsif response.has_field?(:vclock) or response.has_field?(:content)
69
+ raise MalformedKeyError # This should never happen
70
+
71
+ else
72
+ raise KeyNotFoundError
73
+
74
+ end
75
+
76
+ return(self)
77
+ end
78
+
79
+ # Indicates whether or not the Key is empty
80
+ # @return [Boolean] true or false, whether or not the vclock/content is empty
81
+ def empty?
82
+ return(true) if @vclock.empty? && (@contents.nil? || @contents.empty?)
83
+ return(false)
84
+ end
85
+
86
+ # Refreshes the Key and its content with fresh data, if there's concern that separate updates may have taken place.
87
+ # @return
88
+ def reload!
89
+
90
+ end
91
+
92
+ # Retrieves any Keys that are linked to, inside RiakContent elements.
93
+ # @return [Key] the Key to which the RiakContent is linked (may be empty if it does not exist)
94
+ def get_linked(bucket, key, options={})
95
+ @bucket.get_linked(bucket, key, options)
96
+ end
97
+
98
+ # Sets the name attribute for this Key object
99
+ # @param [String] key_name sets the name of the Key
100
+ # @return [Hash] the properties that were accepted
101
+ # @raise [FailedRequest] if the new properties were not accepted by the Riak server
102
+ def name=(key_name)
103
+ raise ArgumentError, t("key_name_type") unless key_name.is_a?(String)
104
+
105
+ @name = key_name
106
+ end
107
+
108
+ # Sets the content object for this Key. I do not yet support siblings in this method and, therefore,
109
+ # you may or may not destroy them if you use this and are not careful.
110
+ # @param [Riak::RiakContent] content a RiakContent instance that should be contained within this Key
111
+ # @return [Riak::RiakContent] the RiakContent instance that was just set
112
+ # @raise [ArgumentError] will yell at you if the supplied riak_content is not of the RiakContent class
113
+ def content=(riak_contents)
114
+
115
+ if riak_contents.is_a?(Protobuf::Field::FieldArray)
116
+ @contents.clear
117
+
118
+ return(false) if riak_contents.empty?
119
+
120
+ riak_contents.each do |rc|
121
+ @contents[rc.vtag].load(rc)
122
+ end
123
+
124
+ return(true)
125
+ elsif riak_contents.is_a?(Riak::RiakContent)
126
+
127
+ @contents.clear
128
+
129
+ @contents[riak_contents.vtag].load(riak_contents)
130
+
131
+ elsif riak_contents.nil?
132
+ @contents.clear
133
+
134
+ else
135
+ raise ArgumentError, t("riak_content_type")
136
+ end # if riak_contents
137
+
138
+ end # def content=
139
+
140
+ # "@contents" is an array of RiakContent objects, though only contains more than one in the event that
141
+ # there are siblings.
142
+ # @return [Riak::RiakContent] the content of this Key instance's value (ie, key/value)
143
+ def content
144
+ case @contents.size
145
+ when 0 then @contents[:new]
146
+ when 1 then contents[0]
147
+ else contents
148
+ end
149
+ end
150
+
151
+ # "@contents" is an array of RiakContent objects. This gives you that entire array.
152
+ # @return [Array<Riak::RiakContent>] the contents of this Key instance's value and its siblings, if any
153
+ def contents
154
+ retr_c = []
155
+
156
+ @contents.each{|k,v| retr_c << v}
157
+
158
+ return(retr_c)
159
+ end
160
+
161
+ # Save the Key+RiakContent instance in riak.
162
+ # @option options [RiakContent] content RiakContent instance to be saved in this Key. Must be specified if there are siblings.
163
+ # @option options [Fixnum] w (write quorum) how many replicas to write to before returning a successful response
164
+ # @option options [Fixnum] dw how many replicas to commit to durable storage before returning a successful response
165
+ # @option options [Boolean] return_body whether or not to have riak return the key, once saved. default = true
166
+ # TODO: Add in content checking, perhaps?
167
+ def save(options={})
168
+ rcontent = options[:content]
169
+
170
+ if rcontent.nil?
171
+ case contents.size
172
+ when 0 then raise ArgumentError, t('empty_content')
173
+ when 1 then rcontent = contents[0]
174
+ else raise SiblingError.new(self.name)
175
+ end
176
+ end
177
+
178
+ options[:content] = rcontent.to_pb if rcontent.is_a?(Riak::RiakContent)
179
+ options[:content] = rcontent if rcontent.is_a?(Riak::RpbContent)
180
+ options[:key] = @name
181
+ options[:vclock] = @vclock unless @vclock.nil?
182
+
183
+ begin
184
+ response = @bucket.store(options)
185
+ load(response)
186
+ return(true) if @contents.count == 1
187
+ return(false)
188
+ rescue FailedRequest
189
+ return(false)
190
+ end
191
+ end
192
+
193
+ # Save the RiakContent instance in riak. Raise/do not rescue on failure.
194
+ # @option options [Fixnum] w (write quorum) how many replicas to write to before returning a successful response
195
+ # @option options [Fixnum] dw how many replicas to commit to durable storage before returning a successful response
196
+ # @option options [Boolean] return_body whether or not to have riak return the key, once saved. default = true
197
+ def save!(options={})
198
+ begin
199
+ save(options)
200
+ return(true) if @contents.count == 1
201
+ raise FailedRequest.new("save_resp_siblings", 1, @contents.count, @contents) if @contents.count > 1
202
+ rescue FailedRequest
203
+ raise FailedRequest.new("save_resp_err")
204
+ end
205
+ end
206
+
207
+ # Creates an RpbPutReq instance, to be shipped off to riak and saved
208
+ # @option options [Fixnum] w (write quorum) how many replicas to write to before returning a successful response
209
+ # @option options [Fixnum] dw how many replicas to commit to durable storage before returning a successful response
210
+ # @option options [Boolean] return_body whether or not to have riak return the key, once saved. default = true
211
+ # @return [Riak::RpbPutReq]
212
+ def to_pb_put(options={})
213
+ rcontent = options[:content]
214
+
215
+ if rcontent.nil?
216
+ case contents.size
217
+ when 0 then raise ArgumentError, t('empty_content')
218
+ when 1 then rcontent = contents[0]
219
+ else raise SiblingError.new(self.name)
220
+ end
221
+ end
222
+
223
+ pb_put_req = Riak::RpbPutReq.new
224
+ pb_put_req.key = @name
225
+ pb_put_req.content = rcontent.to_pb if rcontent.is_a?(Riak::RiakContent)
226
+ pb_put_req.content = rcontent if rcontent.is_a?(Riak::RpbContent)
227
+ pb_put_req.vclock = @vclock unless @vclock.nil?
228
+
229
+ return(pb_put_req)
230
+ end
231
+
232
+ # "@contents" is an array of RiakContent objects. This gives you that entire array.
233
+ # @return [Riak::RpbLink]
234
+ def to_pb_link
235
+ pb_link = Riak::RpbLink.new
236
+ pb_link[:bucket] = @bucket.name
237
+ pb_link[:key] = @name
238
+
239
+ return(pb_link)
240
+ end
241
+
242
+ # Converts this Key into an array, that can be used by a RiakContent, if desired.
243
+ # @return [Array] contains the name of the bucket and the name of the key
244
+ def to_link
245
+ [@bucket.name, @name]
246
+ end
247
+ alias :to_input :to_link
248
+
249
+ # Deletes this key from its Bucket container
250
+ # @param [Hash] options quorum options
251
+ # @option options [Fixnum] :rw - the read/write quorum for the delete
252
+ def delete(options={})
253
+ bucket.delete(@name, options)
254
+ end
255
+
256
+ # @return [String] a representation suitable for IRB and debugging output
257
+ def inspect
258
+ "#<Riak::Key name=#{@name.inspect}, vclock=#{@vclock.inspect}, contents=#{contents.inspect}>"
259
+ end
260
+
261
+ private
262
+
263
+ # Sets the name attribute for this Key object
264
+ # @param [String] key_name sets the name of the Key
265
+ # @return [Hash] the properties that were accepted
266
+ # @raise [FailedRequest] if the new properties were not accepted by the Riak server
267
+ def bucket=(bucket)
268
+ raise ArgumentError, t("invalid_bucket") unless bucket.is_a?(Riak::Bucket)
269
+
270
+ @bucket ||= bucket
271
+ end
272
+
273
+ # Sets the vclock attribute for this Key, which was supplied by the Riak node (if you're doing it right)
274
+ # @param [Fixnum] vclock the vector clock
275
+ # @return [Fixnum] the vector clock
276
+ # @raise [ArgumentError] if you failed at this task, you'll be instructed to place your head on the keyboard
277
+ def vclock=(vclock)
278
+ raise ArgumentError, t("vclock_type") unless vclock.is_a?(String)
279
+
280
+ @vclock = vclock
281
+ end
282
+
283
+ end # class Key
284
+ end # module Riak
@@ -0,0 +1,37 @@
1
+ en:
2
+ riak:
3
+ client_type: "invalid argument {{client}} is not a Riak::Client"
4
+ string_type: "invalid_argument {{string}} is not a String"
5
+ loading_bucket: "while loading bucket '{{name}}'"
6
+ invalid_bucket: "the specified bucket is invalid"
7
+ invalid_key: "the specified key does not exist"
8
+ value_empty: "a value must be set in order to serialize into a protocol buffer"
9
+ failed_request: "Expected message code {{expected}} from Riak but received {{actual}}. {{output}}"
10
+ decode_error: "Riak reported a message length of {{expected}} but length was {{actual}}. {{output}}"
11
+ save_resp_siblings: "The save operation has resulted in unresolved siblings. {{output}}"
12
+ save_resp_err: "The attempted save operation resulted in an error response from riak."
13
+ failed_rx: "You might have discovered a bug. {{failure}}"
14
+ hash_type: "invalid argument {{hash}} is not a Hash"
15
+ path_and_body_required: "You must supply both a resource path and a body."
16
+ request_body_type: "Request body must be a string or IO."
17
+ resource_path_short: "Resource path too short"
18
+ missing_host_and_port: "You must specify a host and port, or use the defaults of 127.0.0.1:8098"
19
+ invalid_client_id: "Invalid client ID, must be a string or between 0 and {{max_id}}"
20
+ hostname_invalid: "host must be a valid hostname"
21
+ port_invalid: "port must be an integer between 0 and 65535"
22
+ install_curb: "curb library not found! Please `gem install curb` for better performance."
23
+ bucket_link_conversion: "Can't convert a bucket link to a walk spec"
24
+ invalid_phase_type: "type must be :map, :reduce, or :link"
25
+ module_function_pair_required: "function must have two elements when an array"
26
+ stored_function_invalid: "function must have :bucket and :key when a hash"
27
+ walk_spec_invalid_unless_link: "WalkSpec is only valid for a function when the type is :link"
28
+ invalid_function_value: "invalid value for function: {{value}}"
29
+ content_type_undefined: "content_type is not defined!"
30
+ too_few_arguments: "too few arguments: {{params}}"
31
+ wrong_argument_count_walk_spec: "wrong number of arguments (one Hash or bucket,tag,keep required)"
32
+ boolean_type: "invalid_argument {{value}} is not true or false"
33
+ fixnum_type: "invalid_argument {{value}} must be an integer"
34
+ error_response: "the riak node responded with an error message code"
35
+ unresolved_siblings: "this Key contains unresolved siblings, which must first be resolved"
36
+ empty_content: "key instance cannot be serialized into a protobuf without a valid key name and content"
37
+
@@ -0,0 +1,219 @@
1
+ require 'riak'
2
+ require 'set'
3
+
4
+ module Riak
5
+ # Parent class of all object types supported by ripple. {Riak::RObject} represents
6
+ # the data and metadata stored in a bucket/key pair in the Riak database.
7
+ class RiakContent
8
+ include Util::Translation
9
+ include Util::MessageCode
10
+
11
+ # @return [Key] the key in which this RiakContent is stored.
12
+ attr_accessor :key
13
+
14
+ # @return [String] the data stored in Riak at this object's key. Varies in format by content-type.
15
+ attr_accessor :value
16
+ alias_attribute :data, :value
17
+
18
+ # @return [String] the MIME content type of the object
19
+ attr_accessor :content_type
20
+
21
+ # @return [String] the charset of the object
22
+ attr_accessor :charset
23
+
24
+ # @return [String] the content encoding of the object
25
+ attr_accessor :content_encoding
26
+
27
+ # @return [String] the vtag of the object
28
+ attr_accessor :vtag
29
+
30
+ # @return [Set<Link>] an Set of {Riak::Link} objects for relationships between this object and other resources
31
+ attr_accessor :links
32
+
33
+ # @return [Time] the Last-Modified header from the most recent HTTP response, useful for caching and reloading
34
+ attr_accessor :last_mod
35
+ alias_attribute :last_modified, :last_mod
36
+
37
+ # @return [Time] the Last-Modified header from the most recent HTTP response, useful for caching and reloading
38
+ attr_accessor :last_mod_usecs
39
+ alias_attribute :last_modified_usecs, :last_mod_usecs
40
+
41
+ # @return [Hash] a hash of any user-supplied metadata, consisting of a key/value pair
42
+ attr_accessor :usermeta
43
+ alias_attribute :meta, :usermeta
44
+
45
+ # Create a new riak_content object manually
46
+ # @param [Riak::Key] key Key instance that owns this RiakContent (really, you should use the Key to get this)
47
+ # @param [Hash] contents Any contents to initialize this instance with
48
+ # @see Key#content
49
+ # @see RiakContent#load
50
+ def initialize(key, contents={})
51
+ @key = key unless key.nil?
52
+ @links = Hash.new{|k,v| k[v] = []}
53
+ @_links = []
54
+ @usermeta = {}
55
+
56
+ load(contents) unless contents.empty?
57
+
58
+ yield self if block_given?
59
+ end
60
+
61
+ # Load information for the content from the response object, Riak::RpbContent.
62
+ #
63
+ # @param [RpbContent/Hash] contents an RpbContent object or a Hash.
64
+ # @return [RiakContent] self
65
+ def load(contents)
66
+ if contents.is_a?(Riak::RpbContent) or contents.is_a?(Hash)
67
+ @content_type = contents[:content_type] unless contents[:content_type].blank?
68
+ @charset = contents[:charset] unless contents[:charset].blank?
69
+ @content_encoding = contents[:content_encoding] unless contents[:content_encoding].blank?
70
+ @vtag = contents[:vtag] unless contents[:vtag].blank?
71
+ self.links = contents[:links] unless contents[:links].blank?
72
+ @last_mod = contents[:last_mod]
73
+ @last_mod_usecs = contents[:last_mod_usecs]
74
+ self.usermeta = contents[:usermeta] unless contents[:usermeta].blank?
75
+
76
+ unless contents[:value].blank?
77
+ case @content_type
78
+ when /json/
79
+ @value = ActiveSupport::JSON.decode(contents[:value])
80
+ when /octet/
81
+ @value = Marshal.load(contents[:value])
82
+ else
83
+ @value = contents[:value]
84
+ end
85
+ end
86
+
87
+ return(self)
88
+ end
89
+
90
+ raise ArgumentError, t("riak_content_type")
91
+ end
92
+
93
+ # Save the RiakContent instance in riak.
94
+ # @option options [Fixnum] w (write quorum) how many replicas to write to before returning a successful response
95
+ # @option options [Fixnum] dw how many replicas to commit to durable storage before returning a successful response
96
+ # @option options [true/false] return_body whether or not to have riak return the key, once saved. default = true
97
+ def save(options={})
98
+ begin
99
+ save!(options)
100
+ rescue FailedRequest
101
+ return(false)
102
+ end
103
+ return(true)
104
+ end
105
+
106
+ # Save the RiakContent instance in riak. Raise/do not rescue on failure.
107
+ # @option options [Fixnum] w (write quorum) how many replicas to write to before returning a successful response
108
+ # @option options [Fixnum] dw how many replicas to commit to durable storage before returning a successful response
109
+ # @option options [true/false] return_body whether or not to have riak return the key, once saved. default = true
110
+ def save!(options={})
111
+ options[:content] = self
112
+ return(true) if @key.save(options)
113
+ return(false) # Create and raise Error message for this? Extend "Failed Request"?
114
+ end
115
+
116
+ # Internalizes a link to a Key, which will be saved on next call to... uh, save
117
+ # @param [Hash] tags name of the tag, pointing to a Key instance, or an array ["bucket", "key"]
118
+ # @return [Hash] links that this RiakContent points to
119
+ def link_key(tags)
120
+ raise TypeError.new t('invalid_tag') unless tag.is_a?(Hash)
121
+ tags.each do |tag, link|
122
+ case link
123
+ when Array
124
+ bucket ||= link[0]
125
+ key ||= link[1]
126
+ raise TypeError.new t('invalid_tag') if bucket.nil? or key.nil?
127
+
128
+ get_link ||= @key.get_linked(bucket, key, {:safely => true})
129
+ raise RuntimeError.new t('invalid_key') if get_link.nil?
130
+
131
+ @links[tag.to_s] << get_link
132
+
133
+ when Riak::Key
134
+ @links[tag.to_s] << link
135
+
136
+ else
137
+ raise TypeError.new t('invalid_tag')
138
+ end
139
+ end # tags.each do |tag, link|
140
+ end
141
+
142
+ # Set the links to other Key in riak.
143
+ # @param [RpbGetResp, RpbPutResp] contains the tag/bucket/key of a given link
144
+ # @return [Set] links that this RiakContent points to
145
+ def links=(pb_links)
146
+ @links.clear
147
+
148
+ pb_links.each do |pb_link|
149
+ @links[pb_link.tag] << @key.get_linked(pb_link.bucket, pb_link.key, {:safely => true})
150
+ end
151
+
152
+ return(@links)
153
+ end
154
+
155
+ # @return [Riak::RpbContent] An instance of a RpbContent, suitable for protobuf exchange
156
+ def to_pb
157
+ raise TypeError.new t('value_empty') if @value.nil?
158
+
159
+ rpb_content = Riak::RpbContent.new
160
+
161
+ links = []
162
+ @links.each do |link|
163
+ pb_link = link[1].to_pb_link
164
+ pb_link[:tag] = link[0]
165
+ links << pb_link
166
+ end
167
+
168
+ usermeta = []
169
+ @usermeta.each do |key,value|
170
+ pb_pair = Riak::RpbPair.new
171
+ pb_pair[:key] = key
172
+ pb_pair[:value] = value
173
+ usermeta << pb_pair
174
+ end
175
+
176
+ catch(:redo) do
177
+ case @content_type
178
+ when /octet/
179
+ rpb_content.value = Marshal.dump(@value)
180
+ when /json/
181
+ rpb_content.value = ActiveSupport::JSON.encode(@value)
182
+ when "", nil
183
+ @content_type = "application/json"
184
+ redo
185
+ else
186
+ rpb_content.value = @value.to_s
187
+ end
188
+ end
189
+
190
+ rpb_content.content_type = @content_type unless @content_type.nil?
191
+ rpb_content.charset = @charset unless @charset.nil? # || @charset.empty?
192
+ rpb_content.content_encoding = @content_encoding unless @content_encoding.nil? # || @content_encoding.empty?
193
+ rpb_content.vtag = @vtag unless @vtag.nil?
194
+ rpb_content.links = links unless links.empty?
195
+ rpb_content.usermeta = usermeta unless usermeta.empty?
196
+
197
+ return(rpb_content)
198
+ end
199
+
200
+ # @return [String] A representation suitable for IRB and debugging output
201
+ def inspect
202
+ "#<#Riak::RiakContent " + [
203
+ (@value.nil?) ? nil : "value=#{@value.inspect}",
204
+ (@content_type.nil?) ? nil : "content_type=#{@content_type.inspect}",
205
+ (@charset.nil?) ? nil : "charset=#{@charset.inspect}",
206
+ (@content_encoding.nil?) ? nil : "content_encoding=#{@content_encoding.inspect}",
207
+ (@vtag.nil?) ? nil : "vtag=#{@vtag.inspect}",
208
+ (@links.nil?) ? nil : "links=#{@_links.inspect}",
209
+ (@last_mod.nil?) ? nil : "last_mod=#{last_mod.inspect}",
210
+ (@last_mod_usecs.nil?) ? nil : "last_mod_usecs=#{last_mod_usecs.inspect}",
211
+ (@usermeta.nil?) ? nil : "usermeta=#{@usermeta.inspect}"
212
+
213
+ ].compact.join(", ") + ">"
214
+ end
215
+
216
+ private
217
+
218
+ end # class RiakContent
219
+ end # module Riak
@@ -0,0 +1,16 @@
1
+ require 'riak'
2
+
3
+ module Riak
4
+ # Exception raised when the expected response code from Riak
5
+ # fails to match the actual response code.
6
+ class SiblingError < StandardError
7
+ include Riak::Util::Translation
8
+
9
+ attr_reader :key
10
+
11
+ def initialize(key)
12
+ @key = key
13
+ super t("unresolved_siblings", :key => @key)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,37 @@
1
+ require 'riak'
2
+
3
+ module Riak
4
+ module Util
5
+
6
+ module Decode
7
+ PLEN = (0..3)
8
+ PBMC = PLEN.count
9
+ POFF = (PBMC+1)
10
+
11
+ def decode_message(message)
12
+ pb_len = 0
13
+ pb_mc = ''
14
+ pb_msg = ''
15
+
16
+ until message.empty?
17
+ pb_len = message[PLEN].unpack('N')[0] # message[0..3]unpack('N')[0]
18
+ pb_mc = pb_mc + message[PBMC] # prior message codes + message[4]
19
+
20
+ prange = POFF..(pb_len+3) # range for the start->finish of the pb message
21
+ mrange = (pb_len+4)..(message.size-1) # range for any remaining portions of message
22
+
23
+ if(prange.count != message[prange].size)
24
+ raise FailedExchange.new(prange.count, message[prange].size, message[prange], "decode_error")
25
+ end
26
+
27
+ pb_msg = pb_msg + message[prange]
28
+ message = message[mrange] # message[(5+pb_len)..(message.size)]
29
+ end
30
+
31
+ [pb_msg, pb_mc.unpack("c" * pb_mc.size)]
32
+ end
33
+
34
+ end # module Decode
35
+ end
36
+ end
37
+
@@ -0,0 +1,31 @@
1
+ require 'riak'
2
+
3
+ module Riak
4
+ module Util
5
+
6
+ module Encode
7
+
8
+ # Construct a Request Message for Riak, which adheres to the following structure:
9
+ #
10
+ # 00 00 00 07 09 0A 01 62 12 01 6B
11
+ # |----Len---|MC|----Message-----|
12
+ #
13
+ # @raise [TypeError] if an invalid hostname is given
14
+ # @return [String] the assigned hostname
15
+ def assemble_request(mc, msg='')
16
+ raise TypeError, t("message_code_invalid") unless mc.is_a?(Fixnum)
17
+ raise TypeError, t("pb_message_invalid") unless msg.is_a?(String)
18
+
19
+ encode_message mc, msg
20
+ end
21
+
22
+ def encode_message(mc, msg='')
23
+ message = [mc].pack('c') + msg
24
+
25
+ message = [message.size].pack('N') + message
26
+ end
27
+
28
+ end
29
+ end
30
+ end
31
+