ali_mns 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fd9393915492ec823696cde63dca99cd73244fa8
4
+ data.tar.gz: 3b5aca077545af61e26ef7c142a287fce5e87edf
5
+ SHA512:
6
+ metadata.gz: fd13f13453de709311d5cbf4a689cb09523690d1181969a83985c81227ad14f4116dd932eef1a274e4afe02f0b2fb8eece3ae7abcb97e2885103b1af2169e3be
7
+ data.tar.gz: 8f772403184b3ea1eaf76c79862930a617bba6861b7dbc6e68bf634eee27bb5c0736902c81f3b50210c611bcbdfc17dc2b368232ef72bb70bc2cfadb3de92b68
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ before_install:
2
+ - gem update --system 2.1.11
3
+ scripte: "CODECLIMATE_REPO_TOKEN=d9e569a99fb83321e72de3c22e73c4ef9536726a91d524d3e08d9d1b726dcc72 bundle exec rake"
4
+ language: ruby
5
+ rvm:
6
+ - "2.0.0"
7
+ - "2.1.0"
8
+ - "2.1.1"
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'http://ruby.taobao.org'
2
+
3
+ # Specify your gem's dependencies in mns.gemspec
4
+ gemspec
5
+ gem "codeclimate-test-reporter", group: :test, require: nil
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 MgaMPKAy
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,225 @@
1
+ # aliyun-mqs
2
+ [![Build Status](https://travis-ci.org/skinnyworm/aliyun-mqs.svg)](https://travis-ci.org/skinnyworm/aliyun-mqs) [![Code Climate](https://codeclimate.com/github/skinnyworm/aliyun-mqs.png)](https://codeclimate.com/github/skinnyworm/aliyun-mqs) [![Code Coverage](https://codeclimate.com/github/skinnyworm/aliyun-mqs/coverage.png)](https://codeclimate.com/github/skinnyworm/aliyun-mqs) [![Gem Version](https://badge.fury.io/rb/aliyun-mqs.svg)](http://badge.fury.io/rb/aliyun-mqs)
3
+
4
+ Talk to the mighty Aliyun MQS with charming ruby.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'aliyun-mqs'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ As this branch of the gem is not yet merged into the master branch, you can not install it via `gem install` for now.
19
+
20
+ ## Configuration
21
+
22
+ ### Command line configuration
23
+
24
+ The gem come with a command line tool `mqs`. It can help you easily manage the aliyun mqs within the terminal. In order to use this tool, you need to provide a configuration yaml file in your home directory which contains information about your mqs access_id and keys.
25
+
26
+ The configuration file should be stored at `~/.aliyun-mqs.yml`
27
+
28
+ ```
29
+
30
+ access_id: 'lUxxxxxxxx'
31
+ key: 'VWxxxxxxxxxxxxxxxxxxxxx'
32
+ region: 'cn-hangzhou'
33
+ owner_id: 'ckxxxxxxxx'
34
+
35
+ ```
36
+
37
+
38
+ ### Rails configuration
39
+
40
+ If you are going to use this gem in a rails environment. You need to create a configuration file at `<RAILS_ROOT>/config/aliyun-mqs.yml`. In this way, you can use different set of queues for your development or production environments.
41
+
42
+ ```
43
+
44
+ development:
45
+ access_id: 'lUxxxxxxxx'
46
+ key: 'VWxxxxxxxxxxxxxxxxxxxxx'
47
+ region: 'cn-hangzhou'
48
+ owner_id: 'ckxxxxxxxx'
49
+
50
+ production:
51
+ access_id: 'lUxxxxxxxx'
52
+ key: 'VWxxxxxxxxxxxxxxxxxxxxx'
53
+ region: 'cn-hangzhou'
54
+ owner_id: 'ckxxxxxxxx'
55
+
56
+ ```
57
+
58
+ ### Config in an application
59
+
60
+ At last you can also config the gem in place, by excute the following code before invoking and queue service.
61
+
62
+ ```ruby
63
+ AliMqs.configure do |config|
64
+ config.access_id = 'access-id'
65
+ config.key = "key"
66
+ config.region = 'region'
67
+ config.owner_id = 'owner-id'
68
+ end
69
+ ```
70
+
71
+
72
+ ## Commandline
73
+
74
+ This gem comes with a handy commandline tool `mqs` to help you manage your queue. Once the queue is installed. Execute 'mqs --help' to find out what commands are supported.
75
+
76
+ ```
77
+ $ mqs --help
78
+
79
+ Commands:
80
+ mqs consume [queue] -wait <wait_seconds> # 从[queue]队列接受消息并删除
81
+ mqs create [queue] # 创建一个消息队列
82
+ mqs delete [queue] # 删除一个消息队列
83
+ mqs peek [queue] # 从[queue]队列中peek消息
84
+ mqs queues # 列出所有消息队列列表
85
+ mqs send [queue] [message] # 往[queue]队列发送[message]消息
86
+ ```
87
+
88
+ Following are few examples.
89
+
90
+ #### 消息队列列表
91
+
92
+ ```
93
+ $ mqs queues
94
+ 消息队列列表
95
+ another
96
+ another1
97
+ another2
98
+ another3
99
+ another4
100
+ another5
101
+ ```
102
+
103
+ #### 往队列发送消息
104
+
105
+ ```
106
+ $ mqs send another "Test message"
107
+ 发送消息到another队列
108
+ <?xml version="1.0"?>
109
+ <Message xmlns="http://mqs.aliyuncs.com/doc/v1">
110
+ <MessageBodyMD5>82DFA5549EBC9AFC168EB7931EBECE5F</MessageBodyMD5>
111
+ <MessageId>55D5B01D1AE93D78-1-14979D45F33-200000001</MessageId>
112
+ </Message>
113
+ ```
114
+
115
+ #### Peek队列中的消息
116
+ ```
117
+ $ mqs peek another
118
+ Peek 队列another中的消息
119
+ =============================================
120
+ 队列: another
121
+ ID: 55D5B01D1AE93D78-1-14979D45F33-200000001
122
+ MD5: 82DFA5549EBC9AFC168EB7931EBECE5F
123
+ Enqueue at: 2014-11-04 16:03:21 +0800
124
+ First enqueue at: 2014-11-04 16:03:21 +0800
125
+ Dequeue count: 0
126
+ Priority: 10
127
+ =============================================
128
+ Test message
129
+ ```
130
+
131
+
132
+ #### 消费队列中的消息
133
+
134
+ Be careful, consume command will first receive the message and then delete the message within a time period specfied by the queue.
135
+
136
+ ```
137
+ $ mqs consume another
138
+ Consume 队列another中的消息
139
+ =============================================
140
+ 队列: another
141
+ ID: 55D5B01D1AE93D78-1-14979D45F33-200000001
142
+ MD5: 82DFA5549EBC9AFC168EB7931EBECE5F
143
+ Receipt handle: 1-ODU4OTkzNDU5My0xNDE1MDg4MzU2LTEtMTA=
144
+ Enqueue at: 2014-11-04 16:03:21 +0800
145
+ First enqueue at: 2014-11-04 16:05:26 +0800
146
+ Next visible at: 2014-11-04 16:05:56 +0800
147
+ Dequeue count: 1
148
+ Priority: 10
149
+ =============================================
150
+ Test message
151
+ ```
152
+
153
+
154
+
155
+ ## Usage
156
+
157
+ Following are some example useage of the gem. You can read the specs to understand the full features of this gem
158
+
159
+ ```ruby
160
+ #get a list of queue object
161
+ queues = AliMqs::Queue.queues
162
+
163
+ #get all queues start with name 'query'
164
+ queues =AliMqs::Queue.queues(query: "query")
165
+
166
+ #get all queues start with name 'query'
167
+ queues = AliMqs::Queue.queues(size: 5)
168
+
169
+ #Obtain a queue object with name "aQueue"
170
+ queue = AliMqs::Queue["aQueue"]
171
+
172
+ #Create a new queue
173
+ AliMqs::Queue["aQueue"].create
174
+
175
+ #Create a new queue with polling wait 30 seconds
176
+ AliMqs::Queue["aQueue"].create(:PollingWaitSeconds => 30)
177
+
178
+ #Delete an existing queue
179
+ AliMqs::Queue["aQueue"].delete
180
+
181
+ #Send a text message
182
+ AliMqs::Queue["aQueue"].send_message "text message"
183
+
184
+ #Send a text message with priority option
185
+ AliMqs::Queue["aQueue"].send_message "text message", :Priority=>1
186
+
187
+ #Receive a message
188
+ message = AliMqs::Queue["aQueue"].receive_message
189
+
190
+ #Sample rspec for a message
191
+ expect(message).not_to be_nil
192
+ expect(message.id).to eq("5fea7756-0ea4-451a-a703-a558b933e274")
193
+ expect(message.body).to eq("This is a test message")
194
+ expect(message.body_md5).to eq("fafb00f5732ab283681e124bf8747ed1")
195
+ expect(message.receipt_handle).to eq("MbZj6wDWli+QEauMZc8ZRv37sIW2iJKq3M9Mx/KSbkJ0")
196
+ expect(message.enqueue_at).to eq(Time.at(1250700979248000/1000.0))
197
+ expect(message.first_enqueue_at).to eq(Time.at(1250700779318000/1000.0))
198
+ expect(message.next_visible_at).to eq(Time.at(1250700799348000/1000.0))
199
+ expect(message.dequeue_count).to eq(1)
200
+ expect(message.priority).to eq(8)
201
+
202
+ #Receive a message with option to override the default poll wait time of the queue.
203
+ message = AliMqs::Queue["aQueue"].receive_message wait_seconds: 60
204
+
205
+ #Peek message in the queue
206
+ message = AliMqs::Queue["aQueue"].peek_message
207
+
208
+ #Delete received message
209
+ message = AliMqs::Queue["aQueue"].receive_message
210
+ message.delete
211
+
212
+ #Change message visibility
213
+ message = AliMqs::Queue["aQueue"].receive_message
214
+ message.change_visibility 10
215
+
216
+ ```
217
+
218
+
219
+ ## Contributing
220
+
221
+ 1. Fork it ( https://github.com/mgampkay/aliyun-mqs/fork )
222
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
223
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
224
+ 4. Push to the branch (`git push origin my-new-feature`)
225
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env rake
2
+ require File.join('bundler', 'gem_tasks')
3
+ require File.join('rspec', 'core', 'rake_task')
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
data/ali_mns.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ali_mns/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'ali_mns'
8
+ spec.version = AliMns::VERSION
9
+ spec.authors = ["Backkom"]
10
+ spec.email = ["99866770@qq.com"]
11
+ spec.summary = 'Ruby SDK for Aliyun MNS (non-official)'
12
+ spec.description = 'Non-official SDK for Aliyun MNS'
13
+ spec.homepage = 'https://github.com/zhaoxl/ali_mns'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency 'nokogiri', '>= 1.6'
22
+ spec.add_dependency 'activesupport', '>= 4.1'
23
+ spec.add_dependency "rest-client"
24
+ spec.add_dependency "thor"
25
+
26
+ spec.add_development_dependency "bundler"
27
+ spec.add_development_dependency "rake", "~> 10.0"
28
+ spec.add_development_dependency "rspec"
29
+ spec.add_development_dependency "pry"
30
+ end
data/bin/mqs ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require 'aliyun/mqs'
3
+
4
+ AliMqs::Cli.start(ARGV)
Binary file
@@ -0,0 +1,34 @@
1
+ module AliMns
2
+ class BatchMessage
3
+
4
+ attr_reader :queue, :messages
5
+
6
+ def initialize queue, content
7
+ @queue = queue
8
+ @messages = []
9
+ #先用Nokogiri转换成xml对象 再循环创建消息对象
10
+ xml = REXML::Document.new(content)
11
+ xml.elements[1].elements.each do |message_element|
12
+ @messages << Message.new(queue, message_element.to_s)
13
+ end
14
+ end
15
+
16
+ def delete_all
17
+ xml = REXML::Document.new
18
+ root_element = REXML::Element.new("ReceiptHandles")
19
+ root_element.add_namespace("xmlns", "http://mns.aliyuncs.com/doc/v1/")
20
+ @messages.each do |message|
21
+ message_element = REXML::Element.new("ReceiptHandle")
22
+ message_element.text = message.receipt_handle
23
+ root_element.add_element(message_element)
24
+ end
25
+ xml.add_element(root_element)
26
+
27
+ response = Request.delete(queue.messages_path) do |request|
28
+ request.xml_content xml
29
+ end
30
+ end
31
+
32
+
33
+ end
34
+ end
@@ -0,0 +1,54 @@
1
+ require 'thor'
2
+
3
+ module AliMns
4
+ class Cli < Thor
5
+
6
+ desc "queues", "列出 QueueOwnerId 下的消息队列列表"
7
+ def queues()
8
+ execute("消息队列列表"){ Queue.queues }
9
+ end
10
+
11
+ desc "delete [queue]", "删除一个消息队列"
12
+ def delete(name)
13
+ execute("删除消息队列'#{name}'"){ Queue[name].delete }
14
+ end
15
+
16
+ desc "create [queue]", "创建一个消息队列"
17
+ def create(name)
18
+ execute("创建消息队列'#{name}'"){ Queue[name].create }
19
+ end
20
+
21
+ desc "consume [queue] -wait <wait_seconds>", "从[queue]队列接受消息并删除"
22
+ option :wait
23
+ def consume(name)
24
+ execute("Consume 队列#{name}中的消息") do
25
+ message = Queue[name].receive_message(wait_seconds: options[:wait])
26
+ message.delete
27
+ message
28
+ end
29
+ end
30
+
31
+ desc "send [queue] [message]", "往[queue]队列发送[message]消息"
32
+ def send(name, content)
33
+ execute("发送消息到#{name}队列"){ Queue[name].send_message content }
34
+ end
35
+
36
+ desc "peek [queue]", "从[queue]队列中peek消息"
37
+ def peek(name)
38
+ execute("Peek 队列#{name}中的消息"){ Queue[name].peek_message }
39
+ end
40
+
41
+ private
42
+ def execute info=nil
43
+ begin
44
+ puts info
45
+ result = yield()
46
+ puts result
47
+ rescue RequestException => ex
48
+ puts "#{ex['Code']}: #{ex['Message']}"
49
+ end
50
+ puts "\n"
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,56 @@
1
+ module AliMns
2
+ class Message
3
+
4
+ attr_reader :queue, :id, :body_md5, :body, :receipt_handle, :enqueue_at, :first_enqueue_at, :next_visible_at, :dequeue_count, :priority
5
+
6
+ def initialize queue, content
7
+ h = Hash.xml_object(content, "Message")
8
+ @queue = queue
9
+ @id = h["MessageId"]
10
+ @body_md5 = h["MessageBodyMD5"]
11
+ @body = Base64.decode64(h["MessageBody"])
12
+ @enqueue_at = Time.at(h["EnqueueTime"].to_i/1000.0)
13
+ @first_enqueue_at = Time.at(h["FirstDequeueTime"].to_i/1000.0)
14
+ @next_visible_at = Time.at(h["NextVisibleTime"].to_i/1000.0) if h["NextVisibleTime"]
15
+ @dequeue_count = h["DequeueCount"].to_i
16
+ @priority = h["Priority"].to_i
17
+ @receipt_handle = h["ReceiptHandle"]
18
+ end
19
+
20
+ def delete
21
+ check_receipt_handle
22
+ AliMns::Request.delete(queue.messages_path, params:{:ReceiptHandle => receipt_handle})
23
+ end
24
+
25
+ def change_visibility seconds
26
+ check_receipt_handle
27
+ AliMns::Request.put(queue.messages_path, params:{:ReceiptHandle => receipt_handle, :VisibilityTimeout=>seconds})
28
+ end
29
+
30
+ def to_s
31
+ s = {
32
+ "队列"=> queue.name,
33
+ "ID"=>id,
34
+ "MD5"=>body_md5,
35
+ "Receipt handle"=>receipt_handle,
36
+ "Enqueue at"=>enqueue_at,
37
+ "First enqueue at"=>first_enqueue_at,
38
+ "Next visible at"=>next_visible_at,
39
+ "Dequeue count" => dequeue_count,
40
+ "Priority"=>priority
41
+ }.collect{|k,v| "#{k}: #{v}"}
42
+
43
+ sep = "============================================="
44
+ s.unshift sep
45
+ s << sep
46
+ s << body
47
+ s.join("\n")
48
+ end
49
+
50
+ private
51
+ def check_receipt_handle
52
+ raise "No receipt handle for this operation" unless receipt_handle
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,78 @@
1
+ module AliMns
2
+ class Queue
3
+ attr_reader :name
4
+
5
+ delegate :to_s, to: :name
6
+
7
+ class << self
8
+ def [] name
9
+ Queue.new(name)
10
+ end
11
+
12
+ def queues opts={}
13
+ mns_options = {query: "x-mns-prefix", offset: "x-mns-marker", size: "x-mns-ret-number"}
14
+ mns_headers = opts.slice(*mns_options.keys).reduce({}){|mns_headers, item| k, v = *item; mns_headers.merge!(mns_options[k]=>v)}
15
+ response = Request.get("/", mns_headers: mns_headers)
16
+ Hash.xml_array(response, "Queues", "Queue").collect{|item| Queue.new(URI(item["QueueURL"]).path.sub!(/^\//, ""))}
17
+ end
18
+ end
19
+
20
+ def initialize name
21
+ @name = name
22
+ end
23
+
24
+ def create opts={}
25
+ response = Request.put(queue_path) do |request|
26
+ msg_options = {
27
+ :VisibilityTimeout => 30,
28
+ :DelaySeconds => 0,
29
+ :MaximumMessageSize => 65536,
30
+ :MessageRetentionPeriod => 345600,
31
+ :PollingWaitSeconds => 0}.merge(opts)
32
+ request.content :Queue, msg_options
33
+ end
34
+ end
35
+
36
+ def delete
37
+ Request.delete(queue_path)
38
+ end
39
+
40
+ def send_message message, opts={}
41
+ Request.post(messages_path) do |request|
42
+ msg_options = {:DelaySeconds => 0, :Priority => 10}.merge(opts)
43
+ request.content :Message, msg_options.merge(:MessageBody => message.to_s)
44
+ end
45
+ end
46
+
47
+ def receive_message wait_seconds: nil
48
+ request_opts = {}
49
+ request_opts.merge!(params:{waitseconds: wait_seconds}) if wait_seconds
50
+ return nil unless result = Request.get(messages_path, request_opts)
51
+ Message.new(self, result)
52
+ end
53
+
54
+ # 批量获取消息
55
+ # 本接口用于消费者批量消费队列的消息,一次BatchReceiveMessage操作最多可以获取16条消息。该操作会将取得的消息状态变成Inactive,Inactive的时间长度由Queue属性VisibilityTimeout指定(详见CreateQueue接口)。 消费者在VisibilityTimeout时间内消费成功后需要调用DeleteMessage接口删除取得的消息,否则取得的消息将会被重新置为Active,又可被消费者重新消费。
56
+ def batch_receive_message limit: 16, wait_seconds: nil
57
+ request_opts = {params:{numOfMessages: limit}}
58
+ request_opts[:params].merge!({waitseconds: wait_seconds}) if wait_seconds
59
+
60
+ return nil unless result = Request.get(messages_path, request_opts)
61
+ BatchMessage.new(self, result)
62
+ end
63
+
64
+ def peek_message
65
+ result = Request.get(messages_path, params: {peekonly: true})
66
+ Message.new(self, result)
67
+ end
68
+
69
+ def queue_path
70
+ "/#{name}"
71
+ end
72
+
73
+ def messages_path
74
+ "/queues/#{name}/messages"
75
+ end
76
+
77
+ end
78
+ end
@@ -0,0 +1,105 @@
1
+ require 'base64'
2
+ module AliMns
3
+
4
+ class RequestException < Exception
5
+ attr_reader :content
6
+ delegate :[], to: :content
7
+
8
+ def initialize ex
9
+ @content = Hash.xml_object(ex.to_s, "Error")
10
+ rescue
11
+ @content = {"Message" => ex.message}
12
+ end
13
+ end
14
+
15
+ class Request
16
+ attr_reader :uri, :method, :date, :body, :content_md5, :content_type, :content_length, :mns_headers
17
+ delegate :access_id, :key, :host, to: :configuration
18
+
19
+ class << self
20
+ [:get, :delete, :put, :post].each do |m|
21
+ define_method m do |*args, &block|
22
+ options = {method: m, path: args[0], mns_headers: {}, params: {}, body: nil}
23
+ options.merge!(args[1]) if args[1].is_a?(Hash)
24
+
25
+ request = AliMns::Request.new(options)
26
+ block.call(request) if block
27
+ request.execute
28
+ end
29
+ end
30
+ end
31
+
32
+ def initialize method: "get", path: "/", mns_headers: {}, params: {}, body: nil
33
+ conf = {
34
+ host: host,
35
+ path: path
36
+ }
37
+ conf.merge!(query: params.to_query) unless params.empty?
38
+ @uri = URI::HTTP.build(conf)
39
+ @method = method
40
+ @mns_headers = mns_headers.merge("x-mns-version" => "2015-06-06")
41
+ end
42
+
43
+ def content type, values={}
44
+ ns = "http://mns.aliyuncs.com/doc/v1/"
45
+ builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
46
+ xml.send(type.to_sym, xmlns: ns) do |b|
47
+ values.each{|k,v| b.send k.to_sym, v}
48
+ end
49
+ end
50
+ @body = builder.to_xml
51
+ @content_md5 = Base64::encode64(Digest::MD5.hexdigest(body)).chop
52
+ @content_length = body.size
53
+ @content_type = "text/xml;charset=utf-8"
54
+ end
55
+
56
+ def xml_content(xml)
57
+ @body = xml.to_s
58
+ @content_md5 = Base64::encode64(Digest::MD5.hexdigest(body)).chop
59
+ @content_length = body.size
60
+ @content_type = "text/xml;charset=utf-8"
61
+ end
62
+
63
+ def execute
64
+ date = DateTime.now.httpdate
65
+ headers = {
66
+ "Authorization" => authorization(date),
67
+ "Content-Length" => content_length || 0,
68
+ "Content-Type" => content_type,
69
+ "Content-MD5" => content_md5,
70
+ "Date" => date,
71
+ "Host" => uri.host
72
+ }.merge(mns_headers).reject{|k,v| v.nil?}
73
+ begin
74
+ if method == :delete && body.present?
75
+ delete_with_body(uri.to_s, body, headers)
76
+ else
77
+ RestClient.send *[method, uri.to_s, body, headers].compact
78
+ end
79
+ rescue Exception => ex
80
+ puts ex.message
81
+ end
82
+ end
83
+
84
+ def delete_with_body(url, body, headers, &block)
85
+ response = RestClient::Request.execute(:method => :delete, :url => url, :payload => body, :headers => headers, &block)
86
+ response
87
+ binding.pry
88
+ end
89
+
90
+ private
91
+ def configuration
92
+ AliMns.configuration
93
+ end
94
+
95
+ def authorization date
96
+ canonical_resource = [uri.path, uri.query].compact.join("?")
97
+ canonical_mq_headers = mns_headers.sort.collect{|k,v| "#{k.downcase}:#{v}"}.join("\n")
98
+ method = self.method.to_s.upcase
99
+ signature = [method, content_md5 || "" , content_type || "" , date, canonical_mq_headers, canonical_resource].join("\n")
100
+ sha1 = Digest::HMAC.digest(signature, key, Digest::SHA1)
101
+ "MNS #{access_id}:#{Base64.encode64(sha1).chop}"
102
+ end
103
+
104
+ end
105
+ end
@@ -0,0 +1,3 @@
1
+ module AliMns
2
+ VERSION = "0.0.1"
3
+ end
data/lib/mns.rb ADDED
@@ -0,0 +1,58 @@
1
+ require 'active_support'
2
+ require 'active_support/core_ext'
3
+ require 'rest-client'
4
+ require 'nokogiri'
5
+ require 'yaml'
6
+ require 'ali_mns/version'
7
+ require 'rexml/document'
8
+ # RestClient.log=STDOUT
9
+
10
+ # Monkey patch hash to support xml array and xml object
11
+ class Hash
12
+ def self.xml_array content, *path
13
+ o = xml_object(content, *path)
14
+ return (o.is_a?(Array) ? o : [o]).reject{|n| n.empty?}
15
+ end
16
+
17
+ def self.xml_object content, *path
18
+ h = from_xml(content)
19
+ path.reduce(h){|memo, node| memo = memo[node] || {}}
20
+ end
21
+ end
22
+
23
+ module AliMns
24
+ require 'ali_mns/queue'
25
+ require 'ali_mns/batch_message'
26
+ require 'ali_mns/message'
27
+ require 'ali_mns/request'
28
+ require 'ali_mns/cli'
29
+
30
+ class << self
31
+ def configuration
32
+ @configuration ||= begin
33
+ if defined? Rails
34
+ config_file = Rails.root.join("config/aliyun-mns.yml")
35
+ else
36
+ config_file = File.expand_path("~/.aliyun-mns.yml")
37
+ end
38
+
39
+ if (File.exist?(config_file))
40
+ config = YAML.load(ERB.new(File.new(config_file).read).result)
41
+ config = config[Rails.env] if defined? Rails
42
+ end
43
+ OpenStruct.new(config || {access_id:"", key:"", region:"", owner_id:""})
44
+ end
45
+ end
46
+
47
+ def configure
48
+ yield(configuration)
49
+ end
50
+ end
51
+
52
+ end
53
+
54
+
55
+ =begin
56
+ AliMns::Queue['log-development'].receive_message
57
+ AliMns::Queue['log-development'].batch_receive_message
58
+ =end
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+
3
+ describe AliMqs::Queue do
4
+
5
+ let(:xml_message){
6
+ AliMqs::Message.new(AliMqs::Queue["aQueue"], <<-XML)
7
+ <?xml version="1.0" encoding="UTF-8" ?>
8
+ <Message xmlns="http://mqs.aliyuncs.com/doc/v1/">
9
+ <MessageId>5fea7756-0ea4-451a-a703-a558b933e274</MessageId>
10
+ <ReceiptHandle>MbZj6wDWli+QEauMZc8ZRv37sIW2iJKq3M9Mx/KSbkJ0</ReceiptHandle>
11
+ <MessageBodyMD5>fafb00f5732ab283681e124bf8747ed1</MessageBodyMD5>
12
+ <MessageBody>This is a test message</MessageBody>
13
+ <EnqueueTime>1250700979248000</EnqueueTime>
14
+ <NextVisibleTime>1250700799348000</NextVisibleTime>
15
+ <FirstDequeueTime>1250700779318000</FirstDequeueTime >
16
+ <DequeueCount>1</DequeueCount >
17
+ <Priority>8</Priority>
18
+ </Message>
19
+ XML
20
+ }
21
+
22
+ let(:peek_xml_message){
23
+ AliMqs::Message.new(AliMqs::Queue["aQueue"], <<-XML)
24
+ <?xml version="1.0" encoding="UTF-8" ?>
25
+ <Message xmlns="http://mqs.aliyuncs.com/doc/v1/">
26
+ <MessageId>5fea7756-0ea4-451a-a703-a558b933e274</MessageId>
27
+ <MessageBodyMD5>fafb00f5732ab283681e124bf8747ed1</MessageBodyMD5>
28
+ <MessageBody>This is a test message</MessageBody>
29
+ <EnqueueTime>1250700979248000</EnqueueTime>
30
+ <FirstDequeueTime>1250700979348000</FirstDequeueTime>
31
+ <DequeueCount>5</DequeueCount>
32
+ <Priority>8</Priority>
33
+ </Message>
34
+ XML
35
+ }
36
+
37
+ describe "#delete" do
38
+ specify "will delete the message from queue" do
39
+ expect(AliMqs::Request).to receive(:delete).with("/aQueue/messages", params:{:ReceiptHandle=>"MbZj6wDWli+QEauMZc8ZRv37sIW2iJKq3M9Mx/KSbkJ0"})
40
+ xml_message.delete
41
+ end
42
+
43
+ specify "won't delete message without receipt_handle" do
44
+ expect{peek_xml_message.delete}.to raise_exception
45
+ end
46
+ end
47
+
48
+ describe "#change_visibility" do
49
+ specify "will change message's visibility timeout" do
50
+ expect(AliMqs::Request).to receive(:put).with("/aQueue/messages", params:{
51
+ :ReceiptHandle=>"MbZj6wDWli+QEauMZc8ZRv37sIW2iJKq3M9Mx/KSbkJ0",
52
+ :VisibilityTimeout => 10
53
+ })
54
+
55
+ xml_message.change_visibility 10
56
+ end
57
+
58
+ specify "won't change message's visibility timeout given message has no receipt_handle" do
59
+ expect{peek_xml_message.change_visibility 10}.to raise_exception
60
+ end
61
+ end
62
+
63
+ end
@@ -0,0 +1,179 @@
1
+ require 'spec_helper'
2
+
3
+ describe AliMqs::Queue do
4
+
5
+ specify ".[] will create new queue instance" do
6
+ queue = AliMqs::Queue["aQueue"]
7
+ expect(queue).not_to be_nil
8
+ expect(queue.name).to eq("aQueue")
9
+ end
10
+
11
+ describe ".queues" do
12
+ let(:xml_response){
13
+ <<-XML
14
+ <?xml version="1.0"?>
15
+ <Queues xmlns="http://mqs.aliyuncs.com/doc/v1">
16
+ <Queue>
17
+ <QueueURL>http://xxxxx.mqs-cn-hangzhou.aliyuncs.com/test</QueueURL>
18
+ </Queue>
19
+ </Queues>
20
+ XML
21
+ }
22
+
23
+ specify "find all queues" do
24
+ expect(AliMqs::Request).to receive(:get).with("/", mqs_headers:{}).and_return xml_response
25
+ queues = AliMqs::Queue.queues
26
+ expect(queues.size).to eq(1)
27
+ expect(queues[0].name).to eq("test")
28
+ end
29
+
30
+ specify "query queues" do
31
+ expect(AliMqs::Request).to receive(:get).with("/", mqs_headers:{"x-mqs-prefix"=>"query"}).and_return xml_response
32
+ queues = AliMqs::Queue.queues(query: "query")
33
+ end
34
+
35
+ specify "find number of queues" do
36
+ expect(AliMqs::Request).to receive(:get).with("/", mqs_headers:{"x-mqs-ret-number"=>5}).and_return xml_response
37
+ queues = AliMqs::Queue.queues(size: 5)
38
+ end
39
+
40
+ specify "find of queues start at given position" do
41
+ expect(AliMqs::Request).to receive(:get).with("/", mqs_headers:{"x-mqs-marker"=>2}).and_return xml_response
42
+ queues = AliMqs::Queue.queues(offset: 2)
43
+ end
44
+ end
45
+
46
+
47
+ describe "#create" do
48
+ specify "will create a new queue with default options" do
49
+ expect(RestClient).to receive(:put) do |*args|
50
+ path, body, headers = *args
51
+ expect(path).to eq("http://owner-id.mqs-region.aliyuncs.com/aQueue")
52
+ xml = Hash.AliMqs(body)
53
+ expect(xml["Queue"]["VisibilityTimeout"]).to eq("30")
54
+ expect(xml["Queue"]["DelaySeconds"]).to eq("0")
55
+ expect(xml["Queue"]["MaximumMessageSize"]).to eq("65536")
56
+ expect(xml["Queue"]["MessageRetentionPeriod"]).to eq("345600")
57
+ expect(xml["Queue"]["PollingWaitSeconds"]).to eq("0")
58
+ expect(headers).not_to be_nil
59
+ end
60
+ AliMqs::Queue["aQueue"].create
61
+ end
62
+
63
+ specify "will create a new queue with customized options" do
64
+ expect(RestClient).to receive(:put) do |*args|
65
+ path, body, headers = *args
66
+ expect(Hash.AliMqs(body)["Queue"]["PollingWaitSeconds"]).to eq("30")
67
+ end
68
+ AliMqs::Queue["aQueue"].create(:PollingWaitSeconds => 30)
69
+ end
70
+ end
71
+
72
+ describe "#delete" do
73
+ specify "will delete existing queue" do
74
+ expect(AliMqs::Request).to receive(:delete).with("/aQueue")
75
+ AliMqs::Queue["aQueue"].delete
76
+ end
77
+ end
78
+
79
+ describe "#send_message" do
80
+ specify "will send a message to a queue with default options" do
81
+ expect(RestClient).to receive(:post) do |*args|
82
+ path, body, headers = *args
83
+ expect(path).to eq("http://owner-id.mqs-region.aliyuncs.com/aQueue/messages")
84
+ xml = Hash.AliMqs(body)
85
+ expect(xml["Message"]["MessageBody"]).to eq("text message")
86
+ expect(xml["Message"]["DelaySeconds"]).to eq("0")
87
+ expect(xml["Message"]["Priority"]).to eq("10")
88
+ expect(headers).not_to be_nil
89
+ end
90
+
91
+ AliMqs::Queue["aQueue"].send_message "text message"
92
+ end
93
+
94
+
95
+ specify "will send a message to a queue with customized options" do
96
+ expect(RestClient).to receive(:post) do |*args|
97
+ path, body, headers = *args
98
+ expect(Hash.AliMqs(body)["Message"]["Priority"]).to eq("1")
99
+ end
100
+
101
+ AliMqs::Queue["aQueue"].send_message "text message", :Priority=>1
102
+ end
103
+ end
104
+
105
+
106
+ describe "#receive_message" do
107
+ let(:xml_response){
108
+ <<-XML
109
+ <?xml version="1.0" encoding="UTF-8" ?>
110
+ <Message xmlns="http://mqs.aliyuncs.com/doc/v1/">
111
+ <MessageId>5fea7756-0ea4-451a-a703-a558b933e274</MessageId>
112
+ <ReceiptHandle>MbZj6wDWli+QEauMZc8ZRv37sIW2iJKq3M9Mx/KSbkJ0</ReceiptHandle>
113
+ <MessageBodyMD5>fafb00f5732ab283681e124bf8747ed1</MessageBodyMD5>
114
+ <MessageBody>This is a test message</MessageBody>
115
+ <EnqueueTime>1250700979248000</EnqueueTime>
116
+ <NextVisibleTime>1250700799348000</NextVisibleTime>
117
+ <FirstDequeueTime>1250700779318000</FirstDequeueTime >
118
+ <DequeueCount>1</DequeueCount >
119
+ <Priority>8</Priority>
120
+ </Message>
121
+ XML
122
+ }
123
+
124
+ specify "will receive message from a queue" do
125
+ expect(AliMqs::Request).to receive(:get).with("/aQueue/messages",{}).and_return xml_response
126
+
127
+ message = AliMqs::Queue["aQueue"].receive_message
128
+ expect(message).not_to be_nil
129
+ expect(message.id).to eq("5fea7756-0ea4-451a-a703-a558b933e274")
130
+ expect(message.body).to eq("This is a test message")
131
+ expect(message.body_md5).to eq("fafb00f5732ab283681e124bf8747ed1")
132
+ expect(message.receipt_handle).to eq("MbZj6wDWli+QEauMZc8ZRv37sIW2iJKq3M9Mx/KSbkJ0")
133
+ expect(message.enqueue_at).to eq(Time.at(1250700979248000/1000.0))
134
+ expect(message.first_enqueue_at).to eq(Time.at(1250700779318000/1000.0))
135
+ expect(message.next_visible_at).to eq(Time.at(1250700799348000/1000.0))
136
+ expect(message.dequeue_count).to eq(1)
137
+ expect(message.priority).to eq(8)
138
+ end
139
+
140
+ specify "will receive message from a queue with poll wait" do
141
+ expect(AliMqs::Request).to receive(:get).with("/aQueue/messages",params:{waitseconds: 60}).and_return xml_response
142
+ message = AliMqs::Queue["aQueue"].receive_message wait_seconds: 60
143
+ end
144
+ end
145
+
146
+ describe "#peek" do
147
+ let(:xml_response){
148
+ <<-XML
149
+ <?xml version="1.0" encoding="UTF-8" ?>
150
+ <Message xmlns="http://mqs.aliyuncs.com/doc/v1/">
151
+ <MessageId>5fea7756-0ea4-451a-a703-a558b933e274</MessageId>
152
+ <MessageBodyMD5>fafb00f5732ab283681e124bf8747ed1</MessageBodyMD5>
153
+ <MessageBody>This is a test message</MessageBody>
154
+ <EnqueueTime>1250700979248000</EnqueueTime>
155
+ <FirstDequeueTime>1250700979348000</FirstDequeueTime>
156
+ <DequeueCount>5</DequeueCount>
157
+ <Priority>8</Priority>
158
+ </Message>
159
+ XML
160
+ }
161
+
162
+ specify "will peek message of a queue" do
163
+ expect(AliMqs::Request).to receive(:get).with("/aQueue/messages",params:{peekonly: true}).and_return xml_response
164
+ message = AliMqs::Queue["aQueue"].peek_message
165
+
166
+ expect(message).not_to be_nil
167
+ expect(message.id).to eq("5fea7756-0ea4-451a-a703-a558b933e274")
168
+ expect(message.body).to eq("This is a test message")
169
+ expect(message.body_md5).to eq("fafb00f5732ab283681e124bf8747ed1")
170
+ expect(message.receipt_handle).to be_nil
171
+ expect(message.enqueue_at).to eq(Time.at(1250700979248000/1000.0))
172
+ expect(message.first_enqueue_at).to eq(Time.at(1250700979348000/1000.0))
173
+ expect(message.next_visible_at).to be_nil
174
+ expect(message.dequeue_count).to eq(5)
175
+ expect(message.priority).to eq(8)
176
+ end
177
+ end
178
+
179
+ end
@@ -0,0 +1,83 @@
1
+ require 'spec_helper'
2
+
3
+ describe AliMqs::Request do
4
+
5
+ describe "Reqest methods" do
6
+ specify "get" do
7
+ expect(RestClient).to receive(:get) do |*args|
8
+ path, headers = *args
9
+ expect(path).to eq("http://owner-id.mqs-region.aliyuncs.com/path")
10
+ expect(headers).to be_a(Hash)
11
+ end
12
+
13
+ AliMqs::Request.get("/path")
14
+ end
15
+
16
+ specify "get with params" do
17
+ expect(RestClient).to receive(:get) do |*args|
18
+ path, headers = *args
19
+ expect(path).to eq("http://owner-id.mqs-region.aliyuncs.com/path?a=1")
20
+ expect(headers).to be_a(Hash)
21
+ end
22
+
23
+ AliMqs::Request.get("/path", params:{a:1})
24
+ end
25
+
26
+ specify "get with mqs_headers" do
27
+ expect(RestClient).to receive(:get) do |*args|
28
+ path, headers = *args
29
+ expect(path).to eq("http://owner-id.mqs-region.aliyuncs.com/path")
30
+ expect(headers.slice("x-mqs-1")).to eq("x-mqs-1"=>"1")
31
+ end
32
+
33
+ AliMqs::Request.get("/path", mqs_headers:{"x-mqs-1"=>"1"})
34
+ end
35
+
36
+ specify "delete" do
37
+ expect(RestClient).to receive(:delete) do |*args|
38
+ path, headers = *args
39
+ expect(path).to eq("http://owner-id.mqs-region.aliyuncs.com/path")
40
+ expect(headers).to be_a(Hash)
41
+ end
42
+
43
+ AliMqs::Request.delete("/path")
44
+ end
45
+
46
+ specify "post with content" do
47
+ expect(RestClient).to receive(:post) do |*args|
48
+ path, body, headers = *args
49
+ expect(path).to eq("http://owner-id.mqs-region.aliyuncs.com/path")
50
+ expect(body).not_to be_empty
51
+ expect(headers).to be_a(Hash)
52
+ end
53
+
54
+ AliMqs::Request.post("/path"){|request| request.content "content"}
55
+ end
56
+
57
+ specify "put with content" do
58
+ expect(RestClient).to receive(:put) do |*args|
59
+ path, body, headers = *args
60
+ expect(path).to eq("http://owner-id.mqs-region.aliyuncs.com/path")
61
+ expect(body).not_to be_empty
62
+ expect(headers).to be_a(Hash)
63
+ end
64
+
65
+ AliMqs::Request.put("/path"){|request| request.content "content"}
66
+ end
67
+ end
68
+
69
+ specify "has default x-mqs-version header" do
70
+ expect(subject.mqs_headers).to eq("x-mqs-version" => "2014-07-08")
71
+ end
72
+
73
+ specify "has default content namespace when content is set" do
74
+ subject.content("content", attr1: 1, attr2: 2)
75
+ xml = Hash.AliMqs(subject.body)
76
+
77
+ expect(subject.content_type).to eq("text/xml;charset=utf-8")
78
+ expect(xml["content"]["xmlns"]).to eq("http://mqs.aliyuncs.com/doc/v1/")
79
+ expect(subject.content_length).not_to be_nil
80
+ expect(subject.content_md5).not_to be_nil
81
+ end
82
+
83
+ end
@@ -0,0 +1,17 @@
1
+ require 'rspec'
2
+ require "codeclimate-test-reporter"
3
+ CodeClimate::TestReporter.start
4
+ require 'aliyun/mqs'
5
+
6
+ Dir[File.join(File.dirname(__FILE__), "../spec/support/**/*.rb")].sort.each {|f| require f}
7
+ RSpec.configure do |config|
8
+ config.color = true
9
+ config.mock_with :rspec
10
+ end
11
+
12
+ AliMqs.configure do |config|
13
+ config.access_id = 'access-id'
14
+ config.key = "key"
15
+ config.region = 'region'
16
+ config.owner_id = 'owner-id'
17
+ end
metadata ADDED
@@ -0,0 +1,180 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ali_mns
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Backkom
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-09-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nokogiri
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '4.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '4.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rest-client
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: thor
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '10.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '10.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: pry
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: Non-official SDK for Aliyun MNS
126
+ email:
127
+ - 99866770@qq.com
128
+ executables:
129
+ - mqs
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - ".travis.yml"
134
+ - Gemfile
135
+ - LICENSE.txt
136
+ - README.md
137
+ - Rakefile
138
+ - ali_mns.gemspec
139
+ - bin/mqs
140
+ - lib/ali_mns/.request.rb.swp
141
+ - lib/ali_mns/batch_message.rb
142
+ - lib/ali_mns/cli.rb
143
+ - lib/ali_mns/message.rb
144
+ - lib/ali_mns/queue.rb
145
+ - lib/ali_mns/request.rb
146
+ - lib/ali_mns/version.rb
147
+ - lib/mns.rb
148
+ - spec/lib/aliyun/mqs/message_spec.rb
149
+ - spec/lib/aliyun/mqs/queue_spec.rb
150
+ - spec/lib/aliyun/mqs/request_spec.rb
151
+ - spec/spec_helper.rb
152
+ homepage: https://github.com/zhaoxl/ali_mns
153
+ licenses:
154
+ - MIT
155
+ metadata: {}
156
+ post_install_message:
157
+ rdoc_options: []
158
+ require_paths:
159
+ - lib
160
+ required_ruby_version: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - ">="
163
+ - !ruby/object:Gem::Version
164
+ version: '0'
165
+ required_rubygems_version: !ruby/object:Gem::Requirement
166
+ requirements:
167
+ - - ">="
168
+ - !ruby/object:Gem::Version
169
+ version: '0'
170
+ requirements: []
171
+ rubyforge_project:
172
+ rubygems_version: 2.4.8
173
+ signing_key:
174
+ specification_version: 4
175
+ summary: Ruby SDK for Aliyun MNS (non-official)
176
+ test_files:
177
+ - spec/lib/aliyun/mqs/message_spec.rb
178
+ - spec/lib/aliyun/mqs/queue_spec.rb
179
+ - spec/lib/aliyun/mqs/request_spec.rb
180
+ - spec/spec_helper.rb