diff --git a/bc.lua b/bc.lua index 3e9c75739aa8..ef5c4f8fea7d 100644 --- a/bc.lua +++ b/bc.lua @@ -1,5 +1,6 @@ local serialization = require("serialization") local uuid = require("uuid") +local computer = require("computer") local Version = {0, 1} @@ -153,6 +154,47 @@ function BaseControl:finalize(waits, timeout) verbs=self:verbs(true), } + if #(waits or {}) ~= 0 then + -- Wait for requested names + local remaining = {} -- Table with all remaining names as keys + local num_remaining = 0 -- Number of remaining names + for _, name in ipairs(waits) do + if not self:has_noun(name) and not self:has_verb(name) then + remaining[name] = true + num_remaining = num_remaining + 1 + end + end + + local tstart = computer.uptime() + local timeout_remaining = timeout + while num_remaining > 0 do + if timeout ~= nil then + timeout_remaining = timeout - (computer.uptime() - tstart) + if timeout_remaining <= 0 then + break + end + end + -- Wait until the next register arrives + local msg = self.network:pull(function(remote, msg) + return msg.ty == Message.Register + end, timeout_remaining) + if msg ~= nil then + for _, noun in ipairs(msg.nouns or {}) do + if remaining[noun] then + num_remaining = num_remaining - 1 + remaining[noun] = nil + end + end + for _, verb in ipairs(msg.verbs or {}) do + if remaining[verb] then + num_remaining = num_remaining - 1 + remaining[verb] = nil + end + end + end + end + end + self.live = true return self end diff --git a/computer.lua b/computer.lua new file mode 100644 index 000000000000..030cd0e5757f --- /dev/null +++ b/computer.lua @@ -0,0 +1,10 @@ +local socket = require("socket") +local computer = {} + +local start = socket.gettime() + +function computer.uptime() + return socket.gettime() - start +end + +return computer diff --git a/tests/timeout.lua b/tests/timeout.lua new file mode 100644 index 000000000000..6fcd245466f1 --- /dev/null +++ b/tests/timeout.lua @@ -0,0 +1,54 @@ +require("lunit") + +local network = require("network") +local serialization = require("serialization") +local BaseControl = require("bc") + +module("network", package.seeall, lunit.testcase) + +function test_timeout_get() + local bc = BaseControl:new() + local addr = network.get_scene() + + -- Fake-register a noun + network.register("TOG1", function() + end) + network.send( + addr, + BaseControl.Network.default_port, + serialization.serialize{ + ty=BaseControl.Message.Register, + nouns={"tog1"}, + } + ) + + assert_error_match("timeout", function() + bc:get("tog1", 0.1) + end) +end + +function test_timeout_call() + local bc = BaseControl:new() + local addr = network.get_scene() + + network.register("TOC1", function() + end) + network.send( + addr, + BaseControl.Network.default_port, + serialization.serialize{ + ty=BaseControl.Message.Register, + verbs={"toc1v"}, + } + ) + + assert_error_match("timeout", function() + bc:call_sync("toc1v", 0.1) + end) +end + +function test_timeout_finalize() + local bc1 = BaseControl:new() + local addr1 = network.get_scene() + bc1:finalize({"to_final1"}, 0.1) +end