diff --git a/README.md b/README.md index e4cf64c92489..4a419721f44e 100644 --- a/README.md +++ b/README.md @@ -251,5 +251,11 @@ serialized using `OpenOS`'s `serialization` library. ### `Network:broadcast(msg_tbl)` Send a message to all connected nodes on the network. +### `Network:pull(filter_func, timeout)` +Block until a message arrives for which `filter_func` returns `true`. The signature +of `filter_func` is `function(addr, msg_tbl)`, similar to the callback given to +`Network:start`. If `timeout` is not `nil`, `pull` should return after the +timeout expired as well. + ### `Network:stop()` Close this connection and uninstall the message handler. diff --git a/bc-tests.lua b/bc-tests.lua index 0a2b98ef0e27..40febb270b11 100644 --- a/bc-tests.lua +++ b/bc-tests.lua @@ -216,4 +216,14 @@ function test_multinode_iters() assert_equal("miter2v", verbs[1], "verb-list incorrect") assert_equal("miter4v", verbs[2], "verb-list incorrect") end + +function test_get_network() + local bc1 = BaseControl:new() + bc1:register("getnw1", 123) + bc1:finalize() + + local bc2 = BaseControl:new() + + assert_equal(123, bc2:get("getnw1"), "wrong value") +end -- }}} diff --git a/bc.lua b/bc.lua index 1a9ea388e4a2..caa42afbbaef 100644 --- a/bc.lua +++ b/bc.lua @@ -41,6 +41,7 @@ function Network:new(modem, port) local self = { modem = modem or require("component").modem, port = port or Network.default_port, + event = require("event"), } setmetatable(self, {__index=Network}) @@ -56,7 +57,7 @@ function Network:start(callback) if port ~= self.port then return end callback(addr_remote, serialization.unserialize(msg)) end - require("event").listen("modem_message", self.listener) + self.event.listen("modem_message", self.listener) end function Network:send(addr, msg) @@ -67,8 +68,24 @@ function Network:broadcast(msg) self.modem.broadcast(self.port, serialization.serialize(msg)) end +function Network:pull(filter, timeout) + local last_msg + local ev = self.event.pullFiltered(timeout, function(ev, addr_lo, addr_remote, port, _, msg) + if ev ~= "modem_message" then return false end + if addr_lo ~= self.modem.address then return false end + if port ~= self.port then return false end + last_msg = serialization.unserialize(msg) + return filter(addr_remote, last_msg) + end) + if ev ~= "nil" then + return last_msg + else + return nil, "timeout" + end +end + function Network:stop() - require("event").ignore("modem_message", self.listener) + self.event.ignore("modem_message", self.listener) self.modem.close(self.port) end -- }}} @@ -163,8 +180,23 @@ function BaseControl:get(noun, timeout) return self.local_nouns[noun] elseif self.local_verbs[noun] ~= nil then error("\""..noun.."\" is not a noun") + elseif self.remote_nouns[noun] ~= nil then + self.network:send(self.remote_nouns[noun], { + ty=Message.NounRequest, + noun=noun, + }) + local answer, err = self.network:pull(function(remote, msg) + if remote ~= self.remote_nouns[noun] then return false end + if msg.ty ~= Message.NounResponse then return false end + if msg.noun ~= noun then return false end + end, timeout) + if answer == nil then + return nil, err + else + return answer.value + end else - return nil + return nil, "noun \""..noun.."\" unknown" end end @@ -232,8 +264,16 @@ function BaseControl:_network_handler(remote, msg) for _, verb in ipairs(msg.verbs or {}) do self.remote_verbs[verb] = remote end + elseif msg.ty == Message.NounRequest then + self.network:send(remote, { + ty=Message.NounResponse, + noun=msg.noun, + value=self.local_nouns[msg.noun], + }) + elseif msg.ty == Message.NounResponse then + -- Handled via pull else - error("TODO: Delet this") + error("TODO: MessageType Unknown") end end -- }}}