-
Notifications
You must be signed in to change notification settings - Fork 19
/
mqtt-http-bridge.rb
120 lines (105 loc) · 2.58 KB
/
mqtt-http-bridge.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#!/usr/bin/env ruby
#
# MQTT to HTTP bridge
#
# Copyright 2012 Nicholas Humfrey <[email protected]>
#
require 'rubygems'
require 'mqtt'
require 'sinatra'
require 'timeout'
class MqttHttpBridge < Sinatra::Base
MQTT_OPTS = {
:remote_host => 'test.mosquitto.org',
:keep_alive => 4,
:clean_session => true
}
def mqtt_get(topic)
MQTT::Client.connect(MQTT_OPTS) do |client|
client.subscribe(topic)
begin
Timeout.timeout(2.5) do
topic,message = client.get
client.disconnect
return message
end
rescue Timeout::Error
not_found("No retained data on topic")
end
end
end
def mqtt_topics
topics = []
MQTT::Client.connect(MQTT_OPTS) do |client|
client.subscribe('$SYS/#')
client.subscribe('#')
begin
Timeout.timeout(1.0) do
client.get { |topic,message| topics << topic }
end
rescue Timeout::Error
end
end
return topics.uniq
end
def topic
unescape(
request.path_info.slice(1..-1)
)
end
helpers do
# Escape ampersands, brackets and quotes to their HTML/XML entities.
# (Rack::Utils.escape_html is overly enthusiastic)
def h(string)
mapping = {
"&" => "&",
"<" => "<",
">" => ">",
"'" => "'",
'"' => """
}
pattern = /#{Regexp.union(*mapping.keys)}/
# Clean up invalid UTF-8 characters
utf16 = string.to_s.encode('UTF-16', :undef => :replace, :invalid => :replace, :replace => "")
clean = utf16.encode('UTF-8');
# Now perform escaping
clean.gsub(pattern){|c| mapping[c] }
end
def link_to(title, url=nil, attr={})
url = title if url.nil?
attr.merge!('href' => url.to_s)
attr_str = attr.keys.map {|k| "#{h k}=\"#{h attr[k]}\""}.join(' ')
"<a #{attr_str}>#{h title}</a>"
end
end
get '/' do
headers 'Cache-Control' => 'public,max-age=60'
@topics = mqtt_topics.sort
erb :index
end
get '/*' do
content_type('text/plain')
mqtt_get(topic)
end
post '/*' do
content_type('text/plain')
MQTT::Client.connect(MQTT_OPTS) do |client|
client.publish(topic, request.body.read, retain=false)
end
"OK"
end
put '/*' do
content_type('text/plain')
MQTT::Client.connect(MQTT_OPTS) do |client|
client.publish(topic, request.body.read, retain=true)
end
"OK"
end
delete '/*' do
content_type('text/plain')
MQTT::Client.connect(MQTT_OPTS) do |client|
client.publish(topic, '', retain=true)
end
"OK"
end
end