From c33fdd41a6b04d49d6e063d4dc13e9e713829a68 Mon Sep 17 00:00:00 2001 From: Rahix Date: Wed, 17 Apr 2019 02:46:24 +0200 Subject: [PATCH] Implement listen cancelling Signed-off-by: Rahix --- README.md | 4 +-- bc.lua | 26 ++++++++++++++++--- tests/listening.lua | 61 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 25ca0d788412..80f90a4e8564 100644 --- a/README.md +++ b/README.md @@ -184,7 +184,7 @@ bc:listen("some_noun", bc.Query.Below(0), function(value) end) ``` -### `BaseControl:cancel(id)` +### `BaseControl:cancel(noun, id)` Cancel a previously installed listener. The id will be invalid after this call. ```lua local listenid = bc:listen("some_noun", bc.Query.Change, function(value) @@ -192,7 +192,7 @@ local listenid = bc:listen("some_noun", bc.Query.Change, function(value) end) -- Later ... -bc:cancel(listenid) +bc:cancel("some_noun", listenid) ``` ### `BaseControl:close()` diff --git a/bc.lua b/bc.lua index 99a250c16b71..40d0fc82c385 100644 --- a/bc.lua +++ b/bc.lua @@ -390,7 +390,7 @@ function BaseControl:listen(noun, query, callback) callback=callback, } if self.local_nouns[noun] ~= nil then - return true + return id, true elseif self.remote_nouns[noun] ~= nil then self.network:send(self.remote_nouns[noun], { ty=Message.ListenRequest, @@ -398,10 +398,24 @@ function BaseControl:listen(noun, query, callback) id=id, query=query, }) - return true + return id, true else - return false + return id, false + end +end + +function BaseControl:cancel(noun, id) + if self.listeners[noun] == nil or self.listeners[noun][id] == nil then + error("can't cancel unknown listener on \""..noun.."\"") + end + if self.local_nouns[noun] == nil and self.remote_nouns[noun] ~= nil then + self.network:send(self.remote_nouns[noun], { + ty=Message.ListenCancel, + noun=noun, + id=id, + }) end + self.listeners[noun][id] = nil end -- }}} @@ -469,6 +483,12 @@ function BaseControl:_network_handler(remote, msg) if self.listeners[msg.noun][msg.id] ~= nil then self.listeners[msg.noun][msg.id].callback(msg.value) end + elseif msg.ty == Message.ListenCancel then + if self.listeners[msg.noun][msg.id] ~= nil then + if self.listeners[msg.noun][msg.id].addr == remote then + self.listeners[msg.noun][msg.id] = nil + end + end else error("TODO: MessageType Unknown") end diff --git a/tests/listening.lua b/tests/listening.lua index 0115bf44cd8e..dbe0948efaf0 100644 --- a/tests/listening.lua +++ b/tests/listening.lua @@ -134,3 +134,64 @@ do end end end + +function test_listen_cancel() + local bc = BaseControl:new() + bc:register("lcan1", 123) + bc:finalize() + + local n = 0 + local id = bc:listen("lcan1", BaseControl.Query.Change, function() + n = n + 1 + end) + + + assert_equal(0, n, "wrong number of listener invokations") + bc:set("lcan1", 321) + assert_equal(1, n, "wrong number of listener invokations") + + -- Cancel the listener + bc:cancel("lcan1", id) + + bc:set("lcan1", 12) + assert_equal(1, n, "wrong number of listener invokations") + + assert_error_match("unknown", function() + bc:cancel("lcan1", id) + end) + + assert_error_match("unknown", function() + bc:cancel("lcan2", "fooid") + end) +end + +function test_listen_cancel_remote() + local bc1 = BaseControl:new() + local addr1 = network.get_scene() + bc1:register("lcanr1", 123) + bc1:finalize() + + local bc2 = BaseControl:new() + local addr2 = network.get_scene() + + local n = 0 + local id, ok = bc2:listen("lcanr1", BaseControl.Query.Change, function() + n = n + 1 + end) + assert_true(ok, "failed installing") + + network.set_scene(addr1) + assert_equal(0, n, "wrong number of listener invokations") + bc1:set("lcanr1", 34) + assert_equal(1, n, "wrong number of listener invokations") + + -- Dirty hack to get the test working + local save = bc2.listeners["lcanr1"][id] + network.set_scene(addr2) + bc2:cancel("lcanr1", id) + bc2.listeners["lcanr1"][id] = save + + network.set_scene(addr1) + bc1:set("lcanr1", 21) + assert_equal(1, n, "wrong number of listener invokations") +end