libmagellan 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|