aliyun_iot 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 45c97913444565a86a94b4a2fa7fc1361c880630
4
+ data.tar.gz: b18bc77902e154bb695414f1d11d8c7a3b230ccb
5
+ SHA512:
6
+ metadata.gz: 4e9f03e9e3621a6fc224ec4e0eb1564e4227fc9b33677c6379f4a5d3c40eec62b5a0e5e1f6226718980f75933bc053f147db99b55419f521f0ebe9c0a36ac434
7
+ data.tar.gz: 51d42f05edd550cc952d06facff889b21b9c11cdc25f91e7003b7fea721812d24f78fbe41bba0005b2dd9812b3b73d4fbc31f556b43cf7faf4e8d5c9efda6c73
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+ .gem
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4.1
5
+ before_install: gem install bundler -v 1.16.1
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at TODO: Write your email address. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in aliyun_iot.gemspec
6
+ gemspec
@@ -0,0 +1,68 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ aliyun_iot (0.1.0)
5
+ activesupport (>= 3.2, <= 5.2)
6
+ nokogiri (>= 1.6.0)
7
+ rest-client (>= 1.8.0)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ activesupport (5.1.4)
13
+ concurrent-ruby (~> 1.0, >= 1.0.2)
14
+ i18n (~> 0.7)
15
+ minitest (~> 5.1)
16
+ tzinfo (~> 1.1)
17
+ concurrent-ruby (1.0.5)
18
+ diff-lcs (1.3)
19
+ domain_name (0.5.20170404)
20
+ unf (>= 0.0.5, < 1.0.0)
21
+ http-cookie (1.0.3)
22
+ domain_name (~> 0.5)
23
+ i18n (0.9.3)
24
+ concurrent-ruby (~> 1.0)
25
+ mime-types (3.1)
26
+ mime-types-data (~> 3.2015)
27
+ mime-types-data (3.2016.0521)
28
+ mini_portile2 (2.3.0)
29
+ minitest (5.11.3)
30
+ netrc (0.11.0)
31
+ nokogiri (1.8.2)
32
+ mini_portile2 (~> 2.3.0)
33
+ rake (10.4.2)
34
+ rest-client (2.0.2)
35
+ http-cookie (>= 1.0.2, < 2.0)
36
+ mime-types (>= 1.16, < 4.0)
37
+ netrc (~> 0.8)
38
+ rspec (3.6.0)
39
+ rspec-core (~> 3.6.0)
40
+ rspec-expectations (~> 3.6.0)
41
+ rspec-mocks (~> 3.6.0)
42
+ rspec-core (3.6.0)
43
+ rspec-support (~> 3.6.0)
44
+ rspec-expectations (3.6.0)
45
+ diff-lcs (>= 1.2.0, < 2.0)
46
+ rspec-support (~> 3.6.0)
47
+ rspec-mocks (3.6.0)
48
+ diff-lcs (>= 1.2.0, < 2.0)
49
+ rspec-support (~> 3.6.0)
50
+ rspec-support (3.6.0)
51
+ thread_safe (0.3.6)
52
+ tzinfo (1.2.4)
53
+ thread_safe (~> 0.1)
54
+ unf (0.1.4)
55
+ unf_ext
56
+ unf_ext (0.0.7.4)
57
+
58
+ PLATFORMS
59
+ ruby
60
+
61
+ DEPENDENCIES
62
+ aliyun_iot!
63
+ bundler (~> 1.16)
64
+ rake (~> 10.0)
65
+ rspec (~> 3.0)
66
+
67
+ BUNDLED WITH
68
+ 1.16.1
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 TODO: Write your name
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,100 @@
1
+ AliyunIot
2
+ ======
3
+
4
+ AliyunIot gem 可以帮助开发者方便地在Rails环境中使用[阿里云物联网套件](https://help.aliyun.com/product/30520.html)提供的服务,包括
5
+
6
+ - [服务器端API](https://help.aliyun.com/document_detail/30557.html)
7
+ - [消息服务](https://help.aliyun.com/product/27412.html)
8
+
9
+ ## 安装
10
+
11
+ 使用 `gem install`
12
+
13
+ ```
14
+ gem install "wechat"
15
+ ```
16
+
17
+ 或者添加下面这行到 `Gemfile`:
18
+
19
+ ```
20
+ gem 'wechat'
21
+ ```
22
+
23
+ 运行下面这行代码来安装:
24
+
25
+ ```console
26
+ bundle install
27
+ ```
28
+
29
+ 运行下面这行代码来生成配置文件:
30
+
31
+ ```console
32
+ rails g aliyun_iot:install
33
+ ```
34
+
35
+ ## 配置
36
+
37
+ #### Rails 全局配置
38
+ Rails应用程序中,需要将配置文件放在`config/aliyun_iot.yml`,可以为不同environment创建不同的配置。
39
+
40
+ 公众号配置示例:
41
+
42
+ ```
43
+ development:
44
+ access_key_id: access_key_id
45
+ access_key_secret: access_key_secret
46
+ end_point: http(s)://{AccountId}.mns.cn-shanghai.aliyuncs.com
47
+ product_key: product_key
48
+ base_url: iot.cn-shanghai.aliyuncs.com
49
+
50
+ production:
51
+ access_key_id: access_key_id
52
+ access_key_secret: access_key_secret
53
+ end_point: http(s)://{AccountId}.mns.cn-shanghai.aliyuncs.com
54
+ product_key: product_key
55
+ base_url: iot.cn-shanghai.aliyuncs.com
56
+ ```
57
+
58
+ ## 命令
59
+
60
+ #### Queue
61
+
62
+ ```ruby
63
+ AliyunIot::Queue.queues ## 列出所有队列
64
+ AliyunIot::Queue[QueueName].receive_message(WaitSeconds) ## 消费消息
65
+ AliyunIot::Queue[QueueName].create({DelaySeconds, MaximumMessageSize, MessageRetentionPeriod, VisibilityTimeout, PollingWaitSeconds, LoggingEnabled}) ## 创建队列
66
+ AliyunIot::Queue[QueueName].delete ## 删除队列
67
+ AliyunIot::Queue[QueueName].send_message({MessageBody, DelaySeconds, Priority}) ## 发送消息
68
+ ```
69
+
70
+ #### Topic
71
+
72
+ ```ruby
73
+ AliyunIot::Topic.topics ## 列出所有主题
74
+ AliyunIot::Topic[TopicName].create({MaximumMessageSize, LoggingEnabled}) ## 创建主题
75
+ AliyunIot::Topic[TopicName].delete ## 删除主题
76
+ AliyunIot::Topic[TopicName].get_topic_attributes ## 获取主题属性
77
+ AliyunIot::Topic[TopicName].subscribe({Endpoint, FilterTag, NotifyStrategy, NotifyContentFormat}) ## 订阅主题
78
+ AliyunMns::Topic[TopicName, SubscriptionName].unsubscribe ## 取消订阅
79
+ ```
80
+
81
+ #### Product
82
+
83
+ ```ruby
84
+ AliyunIot::Product.create(Name) ## 创建产品
85
+ AliyunIot::Product.check_regist_state(ApplyId) ## 批量查询注册状态
86
+ AliyunIot::Product.list_regist_info(ApplyId, PageSize, CurrentPage) ## 批量查询注册状态
87
+ AliyunIot::Product[ProductKey].update({ProductName, ProductDesc}) ## 修改产品信息
88
+ AliyunIot::Product[ProductKey].list({PageSize, CurrentPage}) ## 查询产品的设备列表
89
+ AliyunIot::Product[ProductKey].regist_device({DeviceName}) ## 设备注册
90
+ AliyunIot::Product[ProductKey].regist_devices({DeviceName.1, DeviceName.2 ....}) ## 批量注册设备
91
+ AliyunIot::Product[ProductKey].pub({TopicFullName, MessageContent}) ## 发布消息到设备
92
+ AliyunIot::Product[ProductKey].rrpc({DeviceName, RequestBase64Byte, Timeout}) ## 发消息给设备并同步返回响应
93
+ ```
94
+
95
+ #### Message
96
+
97
+ 由 AliyunIot::Queue[QueueName].receive_message 接口获取的消息,在消费后需要及时删除
98
+ ```ruby
99
+ AliyunIot::Queue[QueueName].receive_message(3).delete
100
+ ```
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,39 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "aliyun_iot/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "aliyun_iot"
8
+ spec.version = AliyunIot::VERSION
9
+ spec.authors = ["CooCOccO"]
10
+ spec.email = ["garrus1118@qq.com"]
11
+
12
+ spec.summary = '阿里云物联网套件ruby sdk'
13
+ spec.description = 'Aliyun IoT sdk'
14
+ spec.homepage = "https://github.com/CooCOccO/aliyun_iot"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ if spec.respond_to?(:metadata)
20
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
21
+ else
22
+ raise "RubyGems 2.0 or newer is required to protect against " \
23
+ "public gem pushes."
24
+ end
25
+
26
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
27
+ f.match(%r{^(test|spec|features)/})
28
+ end
29
+ spec.bindir = "exe"
30
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ["lib"]
32
+
33
+ spec.add_runtime_dependency 'activesupport', '>= 3.2', '<= 5.2'
34
+ spec.add_runtime_dependency 'nokogiri', '>=1.6.0'
35
+ spec.add_runtime_dependency "rest-client", '>= 1.8.0'
36
+ spec.add_development_dependency "bundler", "~> 1.16"
37
+ spec.add_development_dependency "rake", "~> 10.0"
38
+ spec.add_development_dependency "rspec", "~> 3.0"
39
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "aliyun_iot"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,47 @@
1
+ require 'active_support'
2
+ require 'active_support/core_ext'
3
+ require 'rest-client'
4
+ require 'nokogiri'
5
+ require 'yaml'
6
+ require 'openssl'
7
+ require "aliyun_iot/version"
8
+ require "aliyun_iot/queue"
9
+ require "aliyun_iot/topic"
10
+ require "aliyun_iot/message"
11
+ require "aliyun_iot/product"
12
+
13
+ class Hash
14
+ def self.xml_array content, *path
15
+ o = xml_object(content, *path)
16
+ return (o.is_a?(Array) ? o : [o]).reject { |n| n.empty? }
17
+ end
18
+
19
+ def self.xml_object content, *path
20
+ h = from_xml(content)
21
+ path.reduce(h) { |memo, node| memo = memo[node] || {} }
22
+ end
23
+ end
24
+ module AliyunIot
25
+
26
+ class << self
27
+ def configuration
28
+ @configuration ||= begin
29
+ if defined? Rails
30
+ config_file = Rails.root.join("config/aliyun_iot.yml")
31
+ else
32
+ config_file = File.expand_path('../../config/aliyun_iot.yml', __FILE__)
33
+ end
34
+
35
+ if (File.exist?(config_file))
36
+ config = YAML.load(ERB.new(File.new(config_file).read).result)
37
+ config = config[Rails.env] if defined? Rails
38
+ end
39
+ OpenStruct.new(config || {access_id: "", key: "", region: "", product_key: "", owner_id: ""})
40
+ end
41
+ end
42
+
43
+ def configure
44
+ yield(configuration)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,61 @@
1
+ require "aliyun_iot/request/xml"
2
+ module AliyunIot
3
+ class Message
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 = 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
+ @dequeue_count = h["DequeueCount"].to_i
15
+ @priority = h["Priority"].to_i
16
+ @receipt_handle = h["ReceiptHandle"]
17
+ @next_visible_at = Time.at(h["NextVisibleTime"].to_i/1000.0)
18
+ end
19
+
20
+ #删除消息
21
+ def delete
22
+ check_receipt_handle
23
+ Request::Xml.delete(queue.messages_path, end_point, params: {:ReceiptHandle => receipt_handle})
24
+ end
25
+
26
+ #修改消息可见时间
27
+ def change_visibility(seconds)
28
+ check_receipt_handle
29
+ Request::Xml.put(queue.messages_path, end_point, params: {:ReceiptHandle => receipt_handle, :VisibilityTimeout => seconds})
30
+ end
31
+
32
+ def get_data
33
+ data = JSON.parse(Base64.decode64 body)
34
+ end
35
+
36
+ def to_s
37
+ s = {
38
+ "队列" => queue.name,
39
+ "ID" => id,
40
+ "MD5" => body_md5,
41
+ "Receipt handle" => receipt_handle,
42
+ "Enqueue at" => enqueue_at,
43
+ "First enqueue at" => first_enqueue_at,
44
+ "Next visible at" => next_visible_at,
45
+ "Dequeue count" => dequeue_count,
46
+ "Priority" => priority
47
+ }.collect { |k, v| "#{k}: #{v}" }
48
+
49
+ sep = "\n=============================================>"
50
+ s.unshift sep
51
+ s << sep
52
+ s << body
53
+ puts s.join("\n")
54
+ end
55
+
56
+ private
57
+ def check_receipt_handle
58
+ raise "No receipt handle for this operation" unless receipt_handle
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,77 @@
1
+ require "aliyun_iot/request/json"
2
+
3
+ module AliyunIot
4
+ include ERB::Util
5
+
6
+ class Product
7
+ attr_reader :key
8
+ delegate :to_s, to: :key
9
+
10
+ class << self
11
+ def [](key)
12
+ Product.new(key)
13
+ end
14
+
15
+ def create(name)
16
+ params = { Name: name }
17
+ execute params, 'CreateProduct'
18
+ end
19
+
20
+ def check_regist_state(apply_id)
21
+ params = { ApplyId: apply_id }
22
+ execute params, 'QueryApplyStatus'
23
+ end
24
+
25
+ def list_regist_info(apply_id, page_size, current_page)
26
+ params = { ApplyId: apply_id, PageSize: page_size, CurrentPage: current_page }
27
+ execute params, 'QueryPageByApplyId'
28
+ end
29
+
30
+ def execute(params = {}, actiont)
31
+ Request::Json.post(params.merge({ Action: actiont }))
32
+ end
33
+ end
34
+
35
+ def initialize(key)
36
+ @key = key
37
+ end
38
+
39
+ def update(params = {})
40
+ execute params, 'UpdateProduct'
41
+ end
42
+
43
+ def list(params = {})
44
+ execute params, 'QueryDevice'
45
+ end
46
+
47
+ def regist_device(params = {})
48
+ execute params, 'RegistDevice'
49
+ end
50
+
51
+ def regist_devices(params = {})
52
+ execute params, 'ApplyDeviceWithNames'
53
+ end
54
+
55
+ def pub(params = {})
56
+ raise RequestException.new(Exception.new("message MessageContent is empty!")) if params[:MessageContent].nil?
57
+ default_params = { Qos: '0' }
58
+ default_params.merge!({ Qos: '0' }) if params[:Qos].nil?
59
+ params[:MessageContent] = Base64.urlsafe_encode64(params[:MessageContent]).chomp
60
+ execute params.merge(default_params), 'Pub'
61
+ end
62
+
63
+ def sub(params = {})
64
+ execute params, 'Sub'
65
+ end
66
+
67
+ def rrpc(params = {})
68
+ execute params, 'RRpc'
69
+ end
70
+
71
+ private
72
+
73
+ def execute(res_params, action)
74
+ Request::Json.post(res_params.merge({ ProductKey: @key, Action: action }))
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,86 @@
1
+ require "aliyun_iot/request/xml"
2
+
3
+ module AliyunIot
4
+ class Queue
5
+ require_relative 'message'
6
+ attr_reader :name
7
+
8
+ delegate :to_s, to: :name
9
+ delegate :product_key, to: :configuration
10
+
11
+ class << self
12
+ def [](name)
13
+ Queue.new(name)
14
+ end
15
+
16
+ def queues(opts = {})
17
+ mqs_options = {query: "x-mns-prefix", offset: "x-mns-marker", size: "x-mns-ret-number"}
18
+ mqs_headers = opts.slice(*mqs_options.keys).reduce({}) { |mqs_headers, item| k, v = *item; mqs_headers.merge!(mqs_options[k] => v) }
19
+ response = Request::Xml.get("/queues", mqs_headers: mqs_headers.merge({"x-mns-version" => "2015-06-06"}))
20
+ Hash.xml_array(response, "Queues", "Queue").collect { |item| Queue.new(URI(item["QueueURL"]).path.sub!(/^\/queues\//, "")) }
21
+ end
22
+ end
23
+
24
+ def initialize(name)
25
+ @name = name
26
+ @pk = product_key
27
+ end
28
+
29
+ #创建队列
30
+ def create(opts = {})
31
+ Request::Xml.put(queue_path, mqs_headers: {"x-mns-version" => "2015-06-06"}) do |request|
32
+ msg_options = {
33
+ :VisibilityTimeout => 30,
34
+ :DelaySeconds => 0,
35
+ :MaximumMessageSize => 65536,
36
+ :MessageRetentionPeriod => 345600,
37
+ :PollingWaitSeconds => 0
38
+ }.merge(opts)
39
+ request.content_xml(:Queue, msg_options)
40
+ end
41
+ end
42
+
43
+ #删除队列
44
+ def delete
45
+ Request::Xml.delete(queue_path, mqs_headers: {"x-mns-version" => "2015-06-06"})
46
+ end
47
+
48
+ #发送消息
49
+ def send_message(message, opts = {})
50
+ Request::Xml.post(messages_path, mqs_headers: {"x-mns-version" => "2015-06-06"}) do |request|
51
+ msg_options = {
52
+ :DelaySeconds => 0,
53
+ :Priority => 8
54
+ }.merge(opts)
55
+ request.content_xml(:Message, msg_options.merge(:MessageBody => message.to_s))
56
+ end
57
+ end
58
+
59
+ #消费消息
60
+ def receive_message(wait_seconds = nil)
61
+ request_opts = {mqs_headers: {"x-mns-version" => "2015-06-06"}}
62
+ request_opts.merge!(query: {waitseconds: wait_seconds}) if wait_seconds
63
+ result = Request::Xml.get(messages_path, request_opts)
64
+ return nil if result.nil?
65
+ Message.new(self, result)
66
+ end
67
+
68
+ def queue_path
69
+ "/queues/#{name}"
70
+ end
71
+
72
+ def messages_path
73
+ "/queues/#{name}/messages"
74
+ end
75
+
76
+ def device_msg_path(device_name)
77
+ "/#{pk}/#{device_name}/get"
78
+ end
79
+
80
+ private
81
+ def configuration
82
+ AliyunIot.configuration
83
+ end
84
+
85
+ end
86
+ end
@@ -0,0 +1,26 @@
1
+ module AliyunIot
2
+ module Request
3
+ class HttpClient
4
+ attr_reader :base
5
+ def initialize(base)
6
+ @base = RestClient::Resource.new base
7
+ end
8
+
9
+ [:get, :delete, :put, :post].each do |m|
10
+ define_method m do |*args, &block|
11
+ begin
12
+ re = base.send *[m, args[0], args[1]].compact
13
+ rescue RestClient::NotFound => ex
14
+ return nil
15
+ rescue RestClient::Exception => ex
16
+ logger = Logger.new(STDOUT)
17
+ logger.error ex.message
18
+ logger.error ex.backtrace.join("\n")
19
+ raise ex
20
+ end
21
+ end
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,66 @@
1
+ require 'base64'
2
+ require 'securerandom'
3
+ require_relative 'http_client'
4
+
5
+ module AliyunIot
6
+ module Request
7
+ class Json
8
+ attr_reader :url, :method, :body, :params, :client
9
+ delegate :access_key_id, :access_key_secret, :base_url, :region_id, to: :configuration
10
+
11
+ class << self
12
+ [:get, :delete, :put, :post].each do |m|
13
+ define_method m do |*args, &block|
14
+ options = {method: m, params: args[0]}
15
+ request = Request::Json.new(options)
16
+ request.execute
17
+ end
18
+ end
19
+ end
20
+
21
+ def initialize(method: "post", params: {})
22
+ @params = params
23
+ @method = method
24
+ @client = HttpClient.new(base_url)
25
+ end
26
+
27
+ def execute
28
+ ts = Time.now.utc.strftime('%FT%TZ')
29
+ base_params = {
30
+ Format: 'JSON',
31
+ Version: '2017-04-20',
32
+ AccessKeyId: access_key_id,
33
+ SignatureMethod: 'HMAC-SHA1',
34
+ Timestamp: ts,
35
+ SignatureVersion: '1.0',
36
+ SignatureNonce: SecureRandom.uuid,
37
+ RegionId: region_id,
38
+ ServiceCode: 'iot',
39
+ }
40
+ exec_params = encode base_params.merge!(params)
41
+ begin
42
+ JSON.parse client.send(method, exec_params).body
43
+ rescue => e
44
+ logger = Logger.new(STDOUT)
45
+ logger.error e.message
46
+ logger.error e.backtrace.join("\n")
47
+ raise e
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def configuration
54
+ AliyunIot.configuration
55
+ end
56
+
57
+ def encode(encode_params)
58
+ str = ERB::Util.url_encode(encode_params.to_param)
59
+ string_to_sign = "#{method.upcase}&%2F&#{str}"
60
+ sign = Base64.encode64(OpenSSL::HMAC.digest("sha1", "#{access_key_secret}&", string_to_sign)).chop
61
+ encode_params.merge({ Signature: sign })
62
+ end
63
+
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,88 @@
1
+ require 'base64'
2
+ require_relative 'http_client'
3
+ module AliyunIot
4
+ module Request
5
+
6
+ class RequestException < Exception
7
+ attr_reader :content
8
+ delegate :[], to: :content
9
+
10
+ def initialize(ex)
11
+ @content = Hash.xml_object(ex.to_s, "Error")
12
+ rescue
13
+ @content = {"Message" => ex.message}
14
+ end
15
+ end
16
+
17
+ class Xml
18
+ attr_reader :uri, :method, :body, :content_md5, :content_type, :content_length, :mqs_headers, :client
19
+ delegate :access_key_id, :access_key_secret, :end_point, to: :configuration
20
+ class << self
21
+ [:get, :delete, :put, :post].each do |m|
22
+ define_method m do |*args, &block|
23
+ options = {method: m, path: args[0], mqs_headers: {}, query: {}}
24
+ options.merge!(args[1]) if args[1].is_a?(Hash)
25
+
26
+ request = Request::Xml.new(options)
27
+ block.call(request) if block
28
+ request.execute
29
+ end
30
+ end
31
+ end
32
+
33
+ def initialize(method: "get", path: "/", mqs_headers: {}, query: {})
34
+ conf = {
35
+ host: end_point,
36
+ path: path
37
+ }
38
+ conf.merge!(query: query.to_query) unless query.empty?
39
+ @uri = URI::HTTP.build(conf)
40
+ @method = method
41
+ @client = HttpClient.new(@uri.to_s)
42
+ @mqs_headers = mqs_headers.merge("x-mns-version" => "2015-06-06")
43
+ end
44
+
45
+ def content(type, values={})
46
+ ns = "http://mns.aliyuncs.com/doc/v1/"
47
+ builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
48
+ xml.send(type.to_sym, xmlns: ns) do |b|
49
+ values.each { |k, v| b.send k.to_sym, v }
50
+ end
51
+ end
52
+ @body = builder.to_xml
53
+ @content_md5 = Base64::encode64(Digest::MD5.hexdigest(body)).chop
54
+ @content_length = body.size
55
+ @content_type = "text/xml;charset=utf-8"
56
+ end
57
+
58
+ def execute
59
+ date = DateTime.now.httpdate
60
+ headers = {
61
+ "Authorization" => authorization(date),
62
+ "Content-Length" => content_length || 0,
63
+ "Content-Type" => content_type,
64
+ "Content-MD5" => content_md5,
65
+ "Date" => date,
66
+ "Host" => uri.host
67
+ }.merge(mqs_headers).reject { |k, v| v.nil? }
68
+ client.send *[method, body, headers].compact
69
+ end
70
+
71
+ private
72
+
73
+ def configuration
74
+ AliyunIot.configuration
75
+ end
76
+
77
+ def authorization(date)
78
+ canonical_resource = [uri.path, uri.query].compact.join("?")
79
+ canonical_mq_headers = mqs_headers.sort.collect { |k, v| "#{k.downcase}:#{v}" }.join("\n")
80
+ method = self.method.to_s.upcase
81
+ signature = [method, content_md5 || "", content_type || "", date, canonical_mq_headers, canonical_resource].join("\n")
82
+ sha1 = OpenSSL::HMAC.digest("sha1", access_key_secret, signature)
83
+ "MNS #{access_key_id}:#{Base64.encode64(sha1).chop}"
84
+ end
85
+
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,100 @@
1
+ require "aliyun_iot/request/xml"
2
+
3
+ module AliyunIot
4
+ include ERB::Util
5
+
6
+ class Topic
7
+ attr_reader :name, :subscription_name
8
+ delegate :to_s, to: :name
9
+
10
+ class << self
11
+ def [](name, subscription_name = nil)
12
+ Topic.new(name, subscription_name)
13
+ end
14
+
15
+ def topics(opts = {})
16
+ mqs_options = {query: "x-mns-prefix", offset: "x-mns-marker", size: "x-mns-ret-number"}
17
+ mqs_headers = opts.slice(*mqs_options.keys).reduce({}) { |mqs_headers, item| k, v = *item; mqs_headers.merge!(mqs_options[k] => v) }
18
+ response = Request::Xml.get("/topics", mqs_headers: mqs_headers.merge({"x-mns-version" => "2015-06-06"}))
19
+ Hash.xml_array(response, "Topics", "Topic").collect { |item| Topic.new(URI(item["TopicURL"]).path.sub!(/^\/topics\//, "")) }
20
+ end
21
+ end
22
+
23
+ def initialize(name, subscription_name = nil)
24
+ @name = name
25
+ @subscription_name = subscription_name
26
+ end
27
+
28
+ #创建topic
29
+ def create(opts={})
30
+ Request::Xml.put(topic_path, mqs_headers: {"x-mns-version" => "2015-06-06"}) do |request|
31
+ msg_options = {
32
+ MaximumMessageSize: 65536
33
+ }.merge(opts)
34
+ request.content :Topic, msg_options
35
+ end
36
+ end
37
+
38
+ # 删除topic
39
+ def delete
40
+ Request::Xml.delete(topic_path, mqs_headers: {"x-mns-version" => "2015-06-06"})
41
+ end
42
+
43
+ # 获取topic属性
44
+ def get_topic_attributes
45
+ topic_hash = Hash.from_xml(Request::Xml.get(topic_path, mqs_headers: {"x-mns-version" => "2015-06-06"}))
46
+ {
47
+ topic_name: topic_hash["Topic"]["TopicName"],
48
+ create_time: topic_hash["Topic"]["CreateTime"],
49
+ last_modify_time: topic_hash["Topic"]["LastModifyTime"],
50
+ maximum_message_size: topic_hash["Topic"]["MaximumMessageSize"],
51
+ message_retention_period: topic_hash["Topic"]["MessageRetentionPeriod"],
52
+ message_ount: topic_hash["Topic"]["MessageCount"],
53
+ logging_enabled: topic_hash["Topic"]["LoggingEnabled"]
54
+ }
55
+
56
+ end
57
+
58
+ #订阅topic
59
+ def subscribe(opts = {})
60
+ if opts[:Endpoint].nil? || opts[:Endpoint].blank?
61
+ raise Request::XmlException.new(Exception.new("subscribe parameters invalid"))
62
+ else
63
+ Request::Xml.put(subscribe_path, mqs_headers: {"x-mns-version" => "2015-06-06"}) do |request|
64
+ request.content(:Subscription, opts)
65
+ end
66
+ end
67
+ end
68
+
69
+ #退订topic
70
+ def unsubscribe
71
+ Request::Xml.delete(subscribe_path, mqs_headers: {"x-mns-version" => "2015-06-06"})
72
+ end
73
+
74
+ #发布消息
75
+ def publish_message(opts = {})
76
+ if opts[:MessageBody].nil? || opts[:MessageBody].blank?
77
+ raise Exception.new("publish message parameters invalid")
78
+ else
79
+ Request::Xml.post(message_path, mqs_headers: {"x-mns-version" => "2015-06-06"}) do |request|
80
+ request.content(:Message, opts)
81
+ end
82
+ end
83
+ end
84
+
85
+ private
86
+
87
+ def topic_path
88
+ "/topics/#{name}"
89
+ end
90
+
91
+ def subscribe_path
92
+ "/topics/#{name}/subscriptions/#{subscription_name}"
93
+ end
94
+
95
+ def message_path
96
+ "/topics/#{name}/messages"
97
+ end
98
+
99
+ end
100
+ end
@@ -0,0 +1,3 @@
1
+ module AliyunIot
2
+ VERSION = "0.1.1"
3
+ end
@@ -0,0 +1,13 @@
1
+ module AliyunIot
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ desc 'Install support files'
5
+ source_root File.expand_path('../templates', __FILE__)
6
+
7
+ def copy_config
8
+ template 'config/aliyun_iot.yml'
9
+ end
10
+
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ development:
2
+ access_key_id:
3
+ access_key_secret:
4
+ end_point:
5
+ product_key:
6
+ base_url:
7
+
8
+ production:
9
+ access_key_id:
10
+ access_key_secret:
11
+ end_point:
12
+ product_key:
13
+ base_url:
metadata ADDED
@@ -0,0 +1,158 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: aliyun_iot
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - CooCOccO
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-03-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '3.2'
20
+ - - "<="
21
+ - !ruby/object:Gem::Version
22
+ version: '5.2'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '3.2'
30
+ - - "<="
31
+ - !ruby/object:Gem::Version
32
+ version: '5.2'
33
+ - !ruby/object:Gem::Dependency
34
+ name: nokogiri
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: 1.6.0
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 1.6.0
47
+ - !ruby/object:Gem::Dependency
48
+ name: rest-client
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 1.8.0
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 1.8.0
61
+ - !ruby/object:Gem::Dependency
62
+ name: bundler
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.16'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '1.16'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rake
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '10.0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '10.0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: rspec
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '3.0'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '3.0'
103
+ description: Aliyun IoT sdk
104
+ email:
105
+ - garrus1118@qq.com
106
+ executables: []
107
+ extensions: []
108
+ extra_rdoc_files: []
109
+ files:
110
+ - ".gitignore"
111
+ - ".rspec"
112
+ - ".travis.yml"
113
+ - CODE_OF_CONDUCT.md
114
+ - Gemfile
115
+ - Gemfile.lock
116
+ - LICENSE.txt
117
+ - README.md
118
+ - Rakefile
119
+ - aliyun_iot.gemspec
120
+ - bin/console
121
+ - bin/setup
122
+ - lib/aliyun_iot.rb
123
+ - lib/aliyun_iot/message.rb
124
+ - lib/aliyun_iot/product.rb
125
+ - lib/aliyun_iot/queue.rb
126
+ - lib/aliyun_iot/request/http_client.rb
127
+ - lib/aliyun_iot/request/json.rb
128
+ - lib/aliyun_iot/request/xml.rb
129
+ - lib/aliyun_iot/topic.rb
130
+ - lib/aliyun_iot/version.rb
131
+ - lib/generators/aliyun_iot/install_generator.rb
132
+ - lib/generators/aliyun_iot/templates/config/aliyun_iot.yml
133
+ homepage: https://github.com/CooCOccO/aliyun_iot
134
+ licenses:
135
+ - MIT
136
+ metadata:
137
+ allowed_push_host: https://rubygems.org
138
+ post_install_message:
139
+ rdoc_options: []
140
+ require_paths:
141
+ - lib
142
+ required_ruby_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ required_rubygems_version: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ requirements: []
153
+ rubyforge_project:
154
+ rubygems_version: 2.6.12
155
+ signing_key:
156
+ specification_version: 4
157
+ summary: 阿里云物联网套件ruby sdk
158
+ test_files: []