libmagellan 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/libmagellan.rb +5 -2
- data/lib/libmagellan/core.rb +109 -0
- data/lib/libmagellan/{base.rb → http.rb} +4 -1
- data/lib/libmagellan/mqtt.rb +248 -0
- data/lib/libmagellan/version.rb +1 -1
- data/libmagellan.gemspec +1 -0
- data/spec/libmagellan/http_spec.rb +116 -0
- data/spec/libmagellan/mqtt_spec.rb +85 -0
- metadata +23 -6
- data/spec/libmagellan/base_spec.rb +0 -72
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bedd53b1539db040b551014161d7032cd4d9a99d
|
4
|
+
data.tar.gz: 72f92926594578d22e69eee7c9e7e6ac85157898
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8b691e66274cb81dfcc18b5d5ff31d00d2d5e326494e1f6cd9c7c45f1f02f5514d9bb1ab97f93dded805d0e55de276f3884fdf264dff38b501285645dd8f70ce
|
7
|
+
data.tar.gz: 263eca336003094a605da01331eb8cf7a8a050322bc05be91bc18eb57486ca6e51cbc5c9fa40760d51540d682b3bb996889f1edac74b7433ba767de4337930f1
|
data/lib/libmagellan.rb
CHANGED
@@ -1,11 +1,14 @@
|
|
1
1
|
require "libmagellan/version"
|
2
2
|
|
3
3
|
module Libmagellan
|
4
|
-
autoload :
|
4
|
+
autoload :Core, "libmagellan/core"
|
5
|
+
autoload :HTTP, "libmagellan/http"
|
6
|
+
autoload :MQTT, "libmagellan/mqtt"
|
7
|
+
|
5
8
|
|
6
9
|
class << self
|
7
10
|
def new(*args, &block)
|
8
|
-
|
11
|
+
Core.new(*args, &block)
|
9
12
|
end
|
10
13
|
end
|
11
14
|
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'libmagellan'
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
|
6
|
+
module Libmagellan
|
7
|
+
|
8
|
+
class Core
|
9
|
+
|
10
|
+
DEFAULT_LOG_LEVEL = Logger::INFO
|
11
|
+
|
12
|
+
def initialize(*args)
|
13
|
+
# HTTP
|
14
|
+
@http = HTTP.new(*args.dup)
|
15
|
+
|
16
|
+
# MQTT
|
17
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
18
|
+
mqtt_options = options.dup
|
19
|
+
if mqtt_options[:mqtt_host].present? and mqtt_options[:mqtt_port].present?
|
20
|
+
mqtt_options[:host] = mqtt_options.delete(:mqtt_host)
|
21
|
+
mqtt_options[:port] = mqtt_options.delete(:mqtt_port)
|
22
|
+
@mqtt = MQTT.new(mqtt_options)
|
23
|
+
@mqtt.logger = logger
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
##
|
29
|
+
## HTTP
|
30
|
+
##
|
31
|
+
|
32
|
+
def request(*args, &block)
|
33
|
+
@http.request(*args, &block)
|
34
|
+
end
|
35
|
+
alias :req :request
|
36
|
+
|
37
|
+
def ping
|
38
|
+
@http.ping
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_ping(*args)
|
42
|
+
@http.test_ping(*args)
|
43
|
+
end
|
44
|
+
|
45
|
+
def test(*args, &block)
|
46
|
+
@http.test(*args, &block)
|
47
|
+
end
|
48
|
+
|
49
|
+
def json_body(r)
|
50
|
+
@http.json_body(r)
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
##
|
56
|
+
## MQTT
|
57
|
+
##
|
58
|
+
|
59
|
+
def mqtt_token(path, method=:get, body="", headers={})
|
60
|
+
r = request(path, method, body, headers)
|
61
|
+
if r.code.to_i >= 200 and r.code.to_i < 300
|
62
|
+
token = r['authorization']
|
63
|
+
@mqtt.token = token if @mqtt
|
64
|
+
token
|
65
|
+
else
|
66
|
+
r
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def publish(*args)
|
71
|
+
@mqtt.publish(*args)
|
72
|
+
end
|
73
|
+
alias :pub :publish
|
74
|
+
|
75
|
+
def subscribe(*args, &block)
|
76
|
+
@mqtt.subscribe(*args, &block)
|
77
|
+
end
|
78
|
+
alias :sub :subscribe
|
79
|
+
|
80
|
+
def disconnet
|
81
|
+
@mqtt.disconnect
|
82
|
+
end
|
83
|
+
|
84
|
+
def get_message(*args, &block)
|
85
|
+
@mqtt.get(*args, &block)
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
def logger
|
90
|
+
@logger ||= Proc.new {
|
91
|
+
logger = ::Logger.new(STDOUT)
|
92
|
+
logger.level = DEFAULT_LOG_LEVEL
|
93
|
+
logger
|
94
|
+
}.call
|
95
|
+
end
|
96
|
+
|
97
|
+
def logger=(logger_)
|
98
|
+
@logger = logger_
|
99
|
+
end
|
100
|
+
|
101
|
+
# Set logger log level
|
102
|
+
# @param [Integer] level Log level
|
103
|
+
def log_level=(level)
|
104
|
+
logger.level = level
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
@@ -6,7 +6,7 @@ require "signet/oauth_1/client"
|
|
6
6
|
require 'active_support/core_ext/object/blank'
|
7
7
|
|
8
8
|
module Libmagellan
|
9
|
-
class
|
9
|
+
class HTTP
|
10
10
|
|
11
11
|
DEFAULT_OPTIONS = {
|
12
12
|
consumer_key: "groovenauts-test",
|
@@ -36,6 +36,9 @@ module Libmagellan
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def request_without_oauth(path, method=:get, body="", headers={})
|
39
|
+
if body.is_a?(Hash)
|
40
|
+
body = URI.encode_www_form(body)
|
41
|
+
end
|
39
42
|
uri = URI.join(@base_uri.to_s, path)
|
40
43
|
http_client = Net::HTTP.new(uri.host, uri.port)
|
41
44
|
http_client.use_ssl = true if uri.scheme == 'https'
|
@@ -0,0 +1,248 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'libmagellan'
|
3
|
+
|
4
|
+
require 'base64'
|
5
|
+
require 'json'
|
6
|
+
require 'active_support/core_ext'
|
7
|
+
require 'signet/oauth_1/client'
|
8
|
+
require 'mqtt'
|
9
|
+
|
10
|
+
|
11
|
+
module Libmagellan
|
12
|
+
|
13
|
+
class MQTT
|
14
|
+
|
15
|
+
AUTH_BASE_URL = "mqtt://mqtt.magellanic-clouds.com".freeze
|
16
|
+
MQTT_METHOD = "mqtt".freeze
|
17
|
+
PROTOCOL = "mqtt".freeze
|
18
|
+
|
19
|
+
LOG_LEVELS = {
|
20
|
+
debug: Logger::DEBUG,
|
21
|
+
info: Logger::INFO,
|
22
|
+
warn: Logger::WARN,
|
23
|
+
error: Logger::ERROR,
|
24
|
+
fatal: Logger::FATAL,
|
25
|
+
}
|
26
|
+
DEFAULT_LOG_LEVEL = Logger::INFO
|
27
|
+
|
28
|
+
COLOURS = {
|
29
|
+
red: "\e[31m",
|
30
|
+
blue: "\e[34m",
|
31
|
+
green: "\e[32m",
|
32
|
+
yellow: "\e[33m",
|
33
|
+
white: "\e[37m",
|
34
|
+
}
|
35
|
+
|
36
|
+
OPTIONS = {
|
37
|
+
host: {required: true},
|
38
|
+
port: {required: true},
|
39
|
+
consumer_key: {required: true},
|
40
|
+
consumer_secret: {required: true},
|
41
|
+
client_version: {required: true},
|
42
|
+
}.freeze
|
43
|
+
|
44
|
+
attr_accessor :host, :port, :consumer_key, :consumer_secret, :client_version
|
45
|
+
attr_reader :client
|
46
|
+
attr_accessor :token
|
47
|
+
|
48
|
+
# MQTT Client
|
49
|
+
# @param [Hash] args MQTT Arguments
|
50
|
+
# @option args [String] :host MQTT server host address
|
51
|
+
# @option args [Integer] :port MQTT server port
|
52
|
+
# @option args [String] :consumer_key MQTT authorization consumer-key
|
53
|
+
# @option args [String] :consumer_key MQTT authorization consumer-secret
|
54
|
+
def initialize(args={})
|
55
|
+
args, errors = validate_args(args)
|
56
|
+
show_errors(errors, initialize_usage()) if errors.present?
|
57
|
+
|
58
|
+
@host = args.delete(:host)
|
59
|
+
@port = args.delete(:port)
|
60
|
+
@consumer_key = args.delete(:consumer_key)
|
61
|
+
@consumer_secret = args.delete(:consumer_secret)
|
62
|
+
@client_version = args.delete(:client_version)
|
63
|
+
|
64
|
+
@token = nil
|
65
|
+
@client = nil
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
# Publish message to MQTT server.
|
70
|
+
# @param [String] topic Topic name
|
71
|
+
# @param [String] payload Payload
|
72
|
+
def publish(topic, payload)
|
73
|
+
payload = payload.to_json unless payload.is_a?(::String)
|
74
|
+
with_connection do |c|
|
75
|
+
c.publish(topic, payload)
|
76
|
+
log("[PUBLISH] #{topic}: #{payload}", Logger::DEBUG)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
alias :pub :publish
|
80
|
+
|
81
|
+
# Subscribe topic(s)
|
82
|
+
# @param [String|Array] topics Subscribe topics
|
83
|
+
def subscribe(topics, &block)
|
84
|
+
topics = [topics] unless topics.is_a?(::Array)
|
85
|
+
topics = topics.select{|t| t.is_a?(::String) }
|
86
|
+
with_connection do |c|
|
87
|
+
c.subscribe(*topics)
|
88
|
+
topics.each {|t| log("[SUBSCRIBE] #{t}", Logger::DEBUG) }
|
89
|
+
end
|
90
|
+
if block_given?
|
91
|
+
get(nil, &block)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
alias :sub :subscribe
|
95
|
+
|
96
|
+
# Get message to me
|
97
|
+
# @param [String] topic Topic name
|
98
|
+
# @return [Array] topic and payload
|
99
|
+
def get(topic=nil)
|
100
|
+
with_connection do |c|
|
101
|
+
if block_given?
|
102
|
+
c.get(topic) do |topic_, message_|
|
103
|
+
yield(topic_, message_)
|
104
|
+
end
|
105
|
+
else
|
106
|
+
# return topic, payload
|
107
|
+
c.get(topic)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
# MQTT Disconnect
|
114
|
+
def disconect
|
115
|
+
connection.disconnect if connected?
|
116
|
+
end
|
117
|
+
|
118
|
+
# @return [Logger]
|
119
|
+
def logger
|
120
|
+
@logger_
|
121
|
+
end
|
122
|
+
|
123
|
+
def logger=(logger_)
|
124
|
+
@logger_ = logger_
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
|
132
|
+
# Send command to MQTT server.
|
133
|
+
# Connect MQTT server if it is not has connection.
|
134
|
+
def with_connection
|
135
|
+
yield(connection()) if block_given?
|
136
|
+
end
|
137
|
+
|
138
|
+
# Connect MQTT server
|
139
|
+
# @return [MQTT::Client] MQTT Client
|
140
|
+
def connection
|
141
|
+
if connected?
|
142
|
+
return @client
|
143
|
+
else
|
144
|
+
if @token.present?
|
145
|
+
# トークンによる認証
|
146
|
+
connect(@consumer_key, @token)
|
147
|
+
else
|
148
|
+
# OAuthによる認証
|
149
|
+
auth = generate_oauth_header(AUTH_BASE_URL, @consumer_key, @consumer_secret)
|
150
|
+
headers = "Authorization: #{auth}; Client-Version: #{@client_version}"
|
151
|
+
password = Base64.urlsafe_encode64(headers)
|
152
|
+
connect(@consumer_key, password)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Connect to MQTT Server
|
158
|
+
# @param [String] username Username
|
159
|
+
# @param [String] password Password
|
160
|
+
# @return [MQTT::Client] MQTT Client
|
161
|
+
def connect(username, password)
|
162
|
+
mqtt_host = "#{@host}:#{@port.to_s}"
|
163
|
+
uri = "#{PROTOCOL}://#{username}:#{password}@#{mqtt_host}"
|
164
|
+
@client = ::MQTT::Client.new(uri)
|
165
|
+
@client.connect
|
166
|
+
log("[CONNECTED] #{host}:#{port}", Logger::DEBUG)
|
167
|
+
return @client
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
# Check has connection.
|
172
|
+
# @return [Boolean]
|
173
|
+
def connected?
|
174
|
+
@client.present? and @client.connected?
|
175
|
+
end
|
176
|
+
|
177
|
+
# Generate OAuth header
|
178
|
+
# @param [String] uri Auth URI
|
179
|
+
# @param [String] consumer_key Auth consumer-key
|
180
|
+
# @param [String] consumer_secret Auth consumer-secret
|
181
|
+
# @param [Hash] options Auth options
|
182
|
+
def generate_oauth_header(uri, consumer_key, consumer_secret, options={})
|
183
|
+
init_opt = {client_credential_key: consumer_key, client_credential_secret: consumer_secret}
|
184
|
+
options[:uri] = uri if options[:uri].nil? or options[:uri].empty?
|
185
|
+
options[:method] = MQTT_METHOD
|
186
|
+
client = ::Signet::OAuth1::Client.new(init_opt)
|
187
|
+
client.two_legged = true
|
188
|
+
client, options = yield(client, options) if block_given?
|
189
|
+
req = client.generate_authenticated_request(options)
|
190
|
+
req["Authorization"]
|
191
|
+
end
|
192
|
+
|
193
|
+
|
194
|
+
# Validate arguments.
|
195
|
+
# @see initialize
|
196
|
+
def validate_args(args)
|
197
|
+
errors = []
|
198
|
+
args = args.symbolize_keys
|
199
|
+
OPTIONS.each do |key, val|
|
200
|
+
if val[:required]
|
201
|
+
errors << {field: key, message: "required param"} if args[key].blank?
|
202
|
+
end
|
203
|
+
if val[:default] and not args.key?(key)
|
204
|
+
args[key] = val[:default]
|
205
|
+
end
|
206
|
+
end
|
207
|
+
return args, errors
|
208
|
+
end
|
209
|
+
|
210
|
+
# Logging
|
211
|
+
# @param [String] message Logging message
|
212
|
+
# @param [Symbol|String] type Logging type
|
213
|
+
# @param [Symbol] colour Message color
|
214
|
+
def log(message="", lv=DEFAULT_LOG_LEVEL, colour=nil)
|
215
|
+
color = COLOURS[colour.to_s.downcase.to_sym]
|
216
|
+
m = ""
|
217
|
+
m << "#{color}" if color.present?
|
218
|
+
m << "#{message}"
|
219
|
+
m << "\e[0m" if color.present?
|
220
|
+
logger.log(lv, m) if logger
|
221
|
+
end
|
222
|
+
|
223
|
+
|
224
|
+
# Show errors and exit(0)
|
225
|
+
# @param [Array] errors Error messages
|
226
|
+
# @param [String] message Extra message
|
227
|
+
def show_errors(errors, message="")
|
228
|
+
errors.each do |e|
|
229
|
+
log("#{e[:field]}: #{e[:message]}", Logger::ERROR, :red)
|
230
|
+
end
|
231
|
+
log(message, Logger::INFO, :white) if message.present?
|
232
|
+
end
|
233
|
+
|
234
|
+
def initialize_usage
|
235
|
+
<<__USAGE__
|
236
|
+
|
237
|
+
usage:
|
238
|
+
|
239
|
+
c = Libmagellan::MQTT.new(host: "127.0.0.1", host: 1883, consumer_key: "groovenauts.app1", consumer_secret: "test", client_version: "0.0.1", log_level: :debug, commandline: true)
|
240
|
+
|
241
|
+
__USAGE__
|
242
|
+
end
|
243
|
+
|
244
|
+
class MqttError < StandardError
|
245
|
+
end
|
246
|
+
|
247
|
+
end
|
248
|
+
end
|
data/lib/libmagellan/version.rb
CHANGED
data/libmagellan.gemspec
CHANGED
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_runtime_dependency "signet", "~> 0.5.0"
|
22
22
|
spec.add_runtime_dependency "activesupport"
|
23
|
+
spec.add_runtime_dependency "mqtt", "~> 0.3.1"
|
23
24
|
|
24
25
|
spec.add_development_dependency "bundler", "~> 1.6"
|
25
26
|
spec.add_development_dependency "rake", "~> 10.0"
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Libmagellan::HTTP do
|
5
|
+
let(:lm){ Libmagellan::HTTP.new("http://localhost:3000", consumer_key: "foo", consumer_secret: "bar") }
|
6
|
+
|
7
|
+
describe :request do
|
8
|
+
|
9
|
+
let(:http){ double(:http) }
|
10
|
+
let(:res){ double(:res) }
|
11
|
+
|
12
|
+
before do
|
13
|
+
allow(Net::HTTP).to receive(:new).with("localhost", 3000).and_return(http)
|
14
|
+
allow(http).to receive(:start).and_yield(http)
|
15
|
+
end
|
16
|
+
|
17
|
+
describe :get do
|
18
|
+
it :success do
|
19
|
+
allow(http).to receive(:get).\
|
20
|
+
with("/ping", hash_including("Authorization" => an_instance_of(String), "Cache-Control" => "no-store", "Client-Version" => "0.0.1")).\
|
21
|
+
and_return(res)
|
22
|
+
r = lm.request("/ping")
|
23
|
+
expect(r).to eq res
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe :post do
|
28
|
+
it :success do
|
29
|
+
allow(http).to receive(:post).\
|
30
|
+
with("/ping", "param1=value1", hash_including("Authorization" => an_instance_of(String), "Cache-Control" => "no-store", "Client-Version" => "0.0.1")).\
|
31
|
+
and_return(res)
|
32
|
+
r = lm.request("/ping", :post, "param1=value1")
|
33
|
+
expect(r).to eq res
|
34
|
+
end
|
35
|
+
it "accept Hash as body parameter" do
|
36
|
+
allow(http).to receive(:post).\
|
37
|
+
with("/ping", "param1=value1¶m2=value2", hash_including("Authorization" => an_instance_of(String), "Cache-Control" => "no-store", "Client-Version" => "0.0.1")).\
|
38
|
+
and_return(res)
|
39
|
+
r = lm.request("/ping", :post, {param1: "value1", param2: "value2"})
|
40
|
+
expect(r).to eq res
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe :put do
|
45
|
+
it :success do
|
46
|
+
allow(http).to receive(:put).\
|
47
|
+
with("/ping", "param1=value1¶m2=value2", hash_including("Authorization" => an_instance_of(String), "Cache-Control" => "no-store", "Client-Version" => "0.0.1")).\
|
48
|
+
and_return(res)
|
49
|
+
r = lm.request("/ping", :put, {param1: "value1", param2: "value2"})
|
50
|
+
expect(r).to eq res
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe :delete do
|
55
|
+
it :success do
|
56
|
+
allow(http).to receive(:delete).\
|
57
|
+
with("/ping", hash_including("Authorization" => an_instance_of(String), "Cache-Control" => "no-store", "Client-Version" => "0.0.1")).\
|
58
|
+
and_return(res)
|
59
|
+
r = lm.request("/ping", :delete)
|
60
|
+
expect(r).to eq res
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe :ping do
|
66
|
+
|
67
|
+
let(:http){ double(:http) }
|
68
|
+
let(:res){ double(:res) }
|
69
|
+
|
70
|
+
before do
|
71
|
+
allow(Net::HTTP).to receive(:new).with("localhost", 3000).and_return(http)
|
72
|
+
allow(http).to receive(:start).and_yield(http)
|
73
|
+
end
|
74
|
+
|
75
|
+
it :success do
|
76
|
+
allow(res).to receive(:code).and_return("200")
|
77
|
+
allow(res).to receive(:body).and_return("pong\n")
|
78
|
+
allow(http).to receive(:get).\
|
79
|
+
with("/ping", hash_including("Authorization" => an_instance_of(String), "Cache-Control" => "no-store", "Client-Version" => "0.0.1")).\
|
80
|
+
and_return(res)
|
81
|
+
r = lm.test_ping
|
82
|
+
expect(r).to eq lm
|
83
|
+
end
|
84
|
+
|
85
|
+
it :connection_failure_1_time do
|
86
|
+
allow(http).to receive(:get).\
|
87
|
+
with("/ping", hash_including("Authorization" => an_instance_of(String), "Cache-Control" => "no-store", "Client-Version" => "0.0.1")).\
|
88
|
+
once.\
|
89
|
+
and_raise(Errno::ECONNREFUSED)
|
90
|
+
allow(res).to receive(:code).and_return("200")
|
91
|
+
allow(res).to receive(:body).and_return("pong\n")
|
92
|
+
allow(http).to receive(:get).\
|
93
|
+
with("/ping", hash_including("Authorization" => an_instance_of(String), "Cache-Control" => "no-store", "Client-Version" => "0.0.1")).\
|
94
|
+
and_return(res)
|
95
|
+
r = lm.test_ping
|
96
|
+
expect(r).to eq lm
|
97
|
+
end
|
98
|
+
|
99
|
+
it :connection_failure do
|
100
|
+
allow(http).to receive(:get).\
|
101
|
+
with("/ping", hash_including("Authorization" => an_instance_of(String), "Cache-Control" => "no-store", "Client-Version" => "0.0.1")).\
|
102
|
+
exactly(3).times.\
|
103
|
+
and_raise(Errno::ECONNREFUSED)
|
104
|
+
expect{ lm.test_ping(max_retry_count: 2, retry_interval: 0) }.to raise_error(Errno::ECONNREFUSED)
|
105
|
+
end
|
106
|
+
|
107
|
+
it :error_response do
|
108
|
+
allow(res).to receive(:code).and_return("500")
|
109
|
+
allow(res).to receive(:body).and_return("Something wrong!")
|
110
|
+
allow(http).to receive(:get).\
|
111
|
+
with("/ping", hash_including("Authorization" => an_instance_of(String), "Cache-Control" => "no-store", "Client-Version" => "0.0.1")).\
|
112
|
+
and_return(res)
|
113
|
+
expect{ lm.test_ping }.to raise_error(Libmagellan::InvalidResponse)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Libmagellan::MQTT do
|
5
|
+
|
6
|
+
let(:consumer_key) { "groovenauts.app1" }
|
7
|
+
let(:token){ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" }
|
8
|
+
let(:lm) {
|
9
|
+
lm = Libmagellan::MQTT.new({host: "127.0.0.1",
|
10
|
+
port: 1883,
|
11
|
+
consumer_key: consumer_key,
|
12
|
+
consumer_secret: "test",
|
13
|
+
client_version: "0.0.1"
|
14
|
+
})
|
15
|
+
lm.token = token
|
16
|
+
lm
|
17
|
+
}
|
18
|
+
let(:socket) do
|
19
|
+
socket = StringIO.new
|
20
|
+
if socket.respond_to?(:set_encoding)
|
21
|
+
socket.set_encoding("binary")
|
22
|
+
else
|
23
|
+
socket
|
24
|
+
end
|
25
|
+
end
|
26
|
+
let(:client){ MQTT::Client.new(:host => 'localhost') }
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
describe :publish do
|
31
|
+
before do
|
32
|
+
allow(TCPSocket).to receive(:new).and_return(socket)
|
33
|
+
allow(Thread).to receive(:new)
|
34
|
+
client.instance_variable_set('@socket', socket)
|
35
|
+
lm.instance_variable_set('@client', client)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "is success" do
|
39
|
+
lm.publish("topic", "payload")
|
40
|
+
expect(socket.string).to eq("\x30\x0e\x00\x05topicpayload".b)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
describe :subscribe do
|
46
|
+
before do
|
47
|
+
client.instance_variable_set('@socket', socket)
|
48
|
+
lm.instance_variable_set('@client', client)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "is success" do
|
52
|
+
lm.subscribe('a/b')
|
53
|
+
expect(socket.string).to eq("\x82\x08\x00\x01\x00\x03a/b\x00".b)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "is success" do
|
57
|
+
lm.subscribe(['a/b'])
|
58
|
+
expect(socket.string).to eq("\x82\x08\x00\x01\x00\x03a/b\x00".b)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
describe :get do
|
64
|
+
before do
|
65
|
+
client.instance_variable_set('@socket', socket)
|
66
|
+
lm.instance_variable_set('@client', client)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "is success" do
|
70
|
+
inject_packet(:topic => 'topic0', :payload => 'payload0', :qos => 0)
|
71
|
+
topic,payload = lm.get
|
72
|
+
expect(topic).to eq('topic0')
|
73
|
+
expect(payload).to eq('payload0')
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def inject_packet(opts={})
|
81
|
+
packet = MQTT::Packet::Publish.new(opts)
|
82
|
+
client.instance_variable_get('@read_queue').push(packet)
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: libmagellan
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- akima
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-12-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: signet
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: mqtt
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.3.1
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.3.1
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: bundler
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -97,10 +111,13 @@ files:
|
|
97
111
|
- Rakefile
|
98
112
|
- bin/libmagellan
|
99
113
|
- lib/libmagellan.rb
|
100
|
-
- lib/libmagellan/
|
114
|
+
- lib/libmagellan/core.rb
|
115
|
+
- lib/libmagellan/http.rb
|
116
|
+
- lib/libmagellan/mqtt.rb
|
101
117
|
- lib/libmagellan/version.rb
|
102
118
|
- libmagellan.gemspec
|
103
|
-
- spec/libmagellan/
|
119
|
+
- spec/libmagellan/http_spec.rb
|
120
|
+
- spec/libmagellan/mqtt_spec.rb
|
104
121
|
- spec/libmagellan_spec.rb
|
105
122
|
- spec/spec_helper.rb
|
106
123
|
homepage: ''
|
@@ -128,7 +145,7 @@ signing_key:
|
|
128
145
|
specification_version: 4
|
129
146
|
summary: ruby client for magellanic cloud
|
130
147
|
test_files:
|
131
|
-
- spec/libmagellan/
|
148
|
+
- spec/libmagellan/http_spec.rb
|
149
|
+
- spec/libmagellan/mqtt_spec.rb
|
132
150
|
- spec/libmagellan_spec.rb
|
133
151
|
- spec/spec_helper.rb
|
134
|
-
has_rdoc:
|
@@ -1,72 +0,0 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
require 'spec_helper'
|
3
|
-
|
4
|
-
describe Libmagellan::Base do
|
5
|
-
let(:lm){ Libmagellan.new("http://localhost:3000", consumer_key: "foo", consumer_secret: "bar") }
|
6
|
-
|
7
|
-
describe :request do
|
8
|
-
|
9
|
-
let(:http){ double(:http) }
|
10
|
-
let(:res){ double(:res) }
|
11
|
-
|
12
|
-
it :success do
|
13
|
-
allow(Net::HTTP).to receive(:start).with("localhost", 3000).and_yield(http)
|
14
|
-
allow(http).to receive(:get).\
|
15
|
-
with("/ping", hash_including("Authorization" => an_instance_of(String), "Cache-Control" => "no-store", "Client-Version" => "0.0.1")).\
|
16
|
-
and_return(res)
|
17
|
-
r = lm.request("/ping")
|
18
|
-
expect(r).to eq res
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
describe :ping do
|
23
|
-
|
24
|
-
let(:http){ double(:http) }
|
25
|
-
let(:res){ double(:res) }
|
26
|
-
|
27
|
-
it :success do
|
28
|
-
allow(Net::HTTP).to receive(:start).with("localhost", 3000).and_yield(http)
|
29
|
-
allow(res).to receive(:code).and_return("200")
|
30
|
-
allow(res).to receive(:body).and_return("pong\n")
|
31
|
-
allow(http).to receive(:get).\
|
32
|
-
with("/ping", hash_including("Authorization" => an_instance_of(String), "Cache-Control" => "no-store", "Client-Version" => "0.0.1")).\
|
33
|
-
and_return(res)
|
34
|
-
r = lm.test_ping
|
35
|
-
expect(r).to eq lm
|
36
|
-
end
|
37
|
-
|
38
|
-
it :connection_failure_1_time do
|
39
|
-
allow(Net::HTTP).to receive(:start).with("localhost", 3000).and_yield(http)
|
40
|
-
allow(http).to receive(:get).\
|
41
|
-
with("/ping", hash_including("Authorization" => an_instance_of(String), "Cache-Control" => "no-store", "Client-Version" => "0.0.1")).\
|
42
|
-
once.\
|
43
|
-
and_raise(Errno::ECONNREFUSED)
|
44
|
-
allow(res).to receive(:code).and_return("200")
|
45
|
-
allow(res).to receive(:body).and_return("pong\n")
|
46
|
-
allow(http).to receive(:get).\
|
47
|
-
with("/ping", hash_including("Authorization" => an_instance_of(String), "Cache-Control" => "no-store", "Client-Version" => "0.0.1")).\
|
48
|
-
and_return(res)
|
49
|
-
r = lm.test_ping
|
50
|
-
expect(r).to eq lm
|
51
|
-
end
|
52
|
-
|
53
|
-
it :connection_failure do
|
54
|
-
allow(Net::HTTP).to receive(:start).with("localhost", 3000).and_yield(http)
|
55
|
-
allow(http).to receive(:get).\
|
56
|
-
with("/ping", hash_including("Authorization" => an_instance_of(String), "Cache-Control" => "no-store", "Client-Version" => "0.0.1")).\
|
57
|
-
exactly(3).times.\
|
58
|
-
and_raise(Errno::ECONNREFUSED)
|
59
|
-
expect{ lm.test_ping(max_retry_count: 2, retry_interval: 0) }.to raise_error(Errno::ECONNREFUSED)
|
60
|
-
end
|
61
|
-
|
62
|
-
it :error_response do
|
63
|
-
allow(Net::HTTP).to receive(:start).with("localhost", 3000).and_yield(http)
|
64
|
-
allow(res).to receive(:code).and_return("500")
|
65
|
-
allow(res).to receive(:body).and_return("Something wrong!")
|
66
|
-
allow(http).to receive(:get).\
|
67
|
-
with("/ping", hash_including("Authorization" => an_instance_of(String), "Cache-Control" => "no-store", "Client-Version" => "0.0.1")).\
|
68
|
-
and_return(res)
|
69
|
-
expect{ lm.test_ping }.to raise_error(Libmagellan::InvalidResponse)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|