MqttAgent: Ignore a retained message previously received.

This should fix the problem where MqttAgent creates an event from the
same last message every time it runs if it is retained by the server.
This commit is contained in:
Akinori MUSHA 2014-10-14 19:50:04 +09:00
parent fd991f7eb5
commit ca05d40498
3 changed files with 57 additions and 17 deletions

View file

@ -115,15 +115,26 @@ module Agents
def check
last_message = memory['last_message']
mqtt_client.connect do |c|
begin
Timeout.timeout((interpolated['max_read_time'].presence || 15).to_i) {
c.get(interpolated['topic']) do |topic, message|
c.get_packet(interpolated['topic']) do |packet|
topic, payload = message = [packet.topic, packet.payload]
# A lot of services generate JSON. Try that first
payload = JSON.parse(message) rescue message
# Ignore a message if it is previously received
next if (packet.retain || packet.duplicate) && message == last_message
create_event :payload => {
last_message = message
# A lot of services generate JSON, so try that.
begin
payload = JSON.parse(payload)
rescue
end
create_event payload: {
'topic' => topic,
'message' => payload,
'time' => Time.now.to_i
@ -133,6 +144,10 @@ module Agents
rescue Timeout::Error
end
end
# Remember the last original (non-retain, non-duplicate) message
self.memory['last_message'] = last_message
save!
end
end

View file

@ -8,7 +8,6 @@ describe Agents::MqttAgent do
@error_log = StringIO.new
@server = MQTT::FakeServer.new(41234, '127.0.0.1')
@server.just_one = true
@server.logger = Logger.new(@error_log)
@server.logger.level = Logger::DEBUG
@server.start
@ -34,7 +33,14 @@ describe Agents::MqttAgent do
end
describe "#check" do
it "should check that initial run creates an event" do
it "should create events in the initial run" do
expect { @checker.check }.to change { Event.count }.by(2)
end
it "should ignore retained messages that are previously received" do
expect { @checker.check }.to change { Event.count }.by(2)
expect { @checker.check }.to change { Event.count }.by(1)
expect { @checker.check }.to change { Event.count }.by(1)
expect { @checker.check }.to change { Event.count }.by(2)
end
end

View file

@ -52,7 +52,9 @@ class MQTT::FakeServer
@port = @socket.addr[1]
@thread ||= Thread.new do
logger.info "Started a fake MQTT server on #{@address}:#{@port}"
@times = 0
loop do
@times += 1
# Wait for a client to connect
client = @socket.accept
@pings_received = 0
@ -103,16 +105,33 @@ class MQTT::FakeServer
:granted_qos => 0
)
topic = packet.topics[0][0]
client.write MQTT::Packet::Publish.new(
:topic => topic,
:payload => "hello #{topic}",
:retain => true
)
client.write MQTT::Packet::Publish.new(
:topic => topic,
:payload => "did you know about #{topic}",
:retain => true
)
case @times
when 1, ->x { x >= 3 }
# Deliver retained messages
client.write MQTT::Packet::Publish.new(
:topic => topic,
:payload => "did you know about #{topic}",
:retain => true
)
client.write MQTT::Packet::Publish.new(
:topic => topic,
:payload => "hello #{topic}",
:retain => true
)
when 2
# Deliver a still retained message
client.write MQTT::Packet::Publish.new(
:topic => topic,
:payload => "hello #{topic}",
:retain => true
)
# Deliver a fresh message
client.write MQTT::Packet::Publish.new(
:topic => topic,
:payload => "did you know about #{topic}",
:retain => false
)
end
when MQTT::Packet::Pingreq
client.write MQTT::Packet::Pingresp.new
@ -134,4 +153,4 @@ if __FILE__ == $0
server = MQTT::FakeServer.new(MQTT::DEFAULT_PORT)
server.logger.level = Logger::DEBUG
server.run
end
end