251 lines
6.5 KiB
Lua
251 lines
6.5 KiB
Lua
-- Network API v2.0.0
|
|
|
|
local createEventLoop = require('/apis/eventloop');
|
|
|
|
local DEFAULT_TIMEOUT_WAIT_MESSAGE = 0.5; -- in seconds
|
|
local DEFAULT_ROUTING_CHANNEL = 10;
|
|
|
|
-- Utilitaire pour savoir si un packet nous est destiné.
|
|
-- le parametre 'packet' est une table avec les champs suivants:
|
|
-- - sourceId: l'id de la machine qui a envoyé le message
|
|
-- - destId: l'id du destinataire, si l'id est nil le message est routé a tout le monde
|
|
-- - routerId: l'id du routeur qui s'est occupé de transmettre le message
|
|
-- - message: le contenu du message (qui sera le plus souvent une table)
|
|
-- return un boolean
|
|
local function isPacketOk(packet)
|
|
if type(packet) ~= "table" then
|
|
return false;
|
|
end
|
|
|
|
if not packet.routerId or not packet.sourceId then
|
|
return false;
|
|
end
|
|
|
|
if packet.sourceId == os.getComputerID() then
|
|
return false;
|
|
end
|
|
|
|
if packet.destId == nil then
|
|
return true;
|
|
end
|
|
|
|
if type(packet.destId) == 'number' and packet.destId == os.getComputerID() then
|
|
return true;
|
|
end
|
|
|
|
if type(packet.destId) == 'string' and packet.destId == os.getComputerLabel() then
|
|
return true;
|
|
end
|
|
|
|
return false;
|
|
end
|
|
|
|
-- Une simple fonction pour chercher une valeur dans une table
|
|
local function find(predicate, values)
|
|
for k, v in ipairs(values) do
|
|
if predicate(v, k) then
|
|
return v;
|
|
end
|
|
end
|
|
|
|
return nil;
|
|
end
|
|
|
|
-- Fonction utilitaire pour pouvoir pull plusieurs events (modem_message et timer par exemple)
|
|
local function pullMultipleEvents(...)
|
|
local eventNames = table.pack(...);
|
|
|
|
while true do
|
|
local payload = table.pack(os.pullEvent());
|
|
local eventName = payload[1]
|
|
|
|
-- TODO index events
|
|
if find(function(e) return e == eventName end, eventNames) then
|
|
return table.unpack(payload);
|
|
end
|
|
end
|
|
end
|
|
|
|
-- -- Example: implementation simple de ping
|
|
--
|
|
--
|
|
-- local createNet = require('apis/net');
|
|
-- net = createNet();
|
|
-- local net = createNet(nil, modem);
|
|
|
|
-- net.listenRequest(PING_CHANNEL, 'ping', function(message, reply)
|
|
-- if message == 'ping' then
|
|
-- reply('pong');
|
|
-- end
|
|
-- end)
|
|
--
|
|
local function createNetwork(el, modem, routingChannel, timeoutInSec)
|
|
el = el or createEventLoop();
|
|
modem = modem or peripheral.find("modem") or error("modem not found");
|
|
routingChannel = routingChannel or DEFAULT_ROUTING_CHANNEL;
|
|
timeoutInSec = timeoutInSec or DEFAULT_TIMEOUT_WAIT_MESSAGE;
|
|
|
|
local function openChannel(chan)
|
|
return modem.open(chan);
|
|
end
|
|
|
|
-- net.send function
|
|
local function sendRaw(channel, message, destId)
|
|
local packet = {
|
|
sourceId = os.getComputerID(),
|
|
sourceLabel = os.getComputerLabel(),
|
|
routerId = nil,
|
|
destId = destId,
|
|
message = message
|
|
}
|
|
|
|
return modem.transmit(routingChannel, channel, packet);
|
|
end
|
|
|
|
local function listenRaw(channel, handler)
|
|
openChannel(channel);
|
|
|
|
return el.register('modem_message', function(_, _, replyChannel, packet)
|
|
if isPacketOk(packet) and channel == replyChannel then
|
|
handler(packet.message, packet);
|
|
end
|
|
end)
|
|
end
|
|
|
|
local function send(channel, eventType, payload, destId)
|
|
local event = { type = eventType, payload = payload };
|
|
return sendRaw(channel, event, destId);
|
|
end
|
|
|
|
local function listen(channel, eventType, handler)
|
|
return listenRaw(channel, function(event, packet)
|
|
if event.type == eventType then
|
|
handler(event.payload, packet)
|
|
end
|
|
end)
|
|
end
|
|
|
|
local function listenRequest(channel, eventType, handler)
|
|
return listen(channel, eventType, function(payload, packet)
|
|
local reply = function(responsePayload)
|
|
send(channel, eventType .. "_response", responsePayload, packet.sourceId);
|
|
end
|
|
|
|
handler(payload, reply, packet);
|
|
end)
|
|
end
|
|
|
|
local function sendRequest(channel, eventType, payload, destId)
|
|
local ok = false;
|
|
local result = nil;
|
|
local packetResult = nil;
|
|
|
|
local privateEventLoop = createEventLoop();
|
|
local privateNet = createNetwork(privateEventLoop, modem, routingChannel, timeoutInSec);
|
|
|
|
privateNet.listen(channel, eventType .. "_response", function(responsePayload, packet)
|
|
ok = true;
|
|
result = responsePayload
|
|
packetResult = packet;
|
|
privateNet.stop();
|
|
end)
|
|
|
|
privateEventLoop.setTimeout(function()
|
|
result = "net.sendRequest timeout!"
|
|
privateNet.stop();
|
|
end, timeoutInSec);
|
|
|
|
privateNet.send(channel, eventType, payload, destId);
|
|
privateNet.start();
|
|
|
|
return ok, result, packetResult;
|
|
end
|
|
|
|
local function sendMultipleRequests(channel, eventType, payload, destId)
|
|
local ok = false;
|
|
local results = {};
|
|
local packetResults = {};
|
|
|
|
local privateEventLoop = createEventLoop();
|
|
local privateNet = createNetwork(privateEventLoop, modem, routingChannel, timeoutInSec);
|
|
|
|
privateNet.listen(channel, eventType .. "_response", function(responsePayload, packet)
|
|
ok = true;
|
|
table.insert(results, responsePayload)
|
|
table.insert(packetResults, packet);
|
|
end)
|
|
|
|
privateEventLoop.setTimeout(function()
|
|
if #results == 0 then
|
|
results = "net.sendRequest timeout!"
|
|
end
|
|
privateNet.stop();
|
|
end, timeoutInSec);
|
|
|
|
privateNet.send(channel, eventType, payload, destId);
|
|
privateNet.start();
|
|
|
|
return ok, results, packetResults;
|
|
end
|
|
|
|
local function createRequest(channel, eventType)
|
|
local requestApi = {};
|
|
|
|
function requestApi.send(payload, destId)
|
|
return sendRequest(channel, eventType, payload, destId);
|
|
end
|
|
|
|
function requestApi.sendMultiple(payload, destId)
|
|
return sendMultipleRequests(channel, eventType, payload, destId);
|
|
end
|
|
|
|
function requestApi.listen(handler)
|
|
return listenRequest(channel, eventType, handler)
|
|
end
|
|
|
|
return requestApi;
|
|
end
|
|
|
|
local function createEvent(channel, eventType)
|
|
local eventApi = {}
|
|
|
|
|
|
function eventApi.send(payload, destId)
|
|
return send(channel, eventType, payload, destId);
|
|
end
|
|
|
|
function eventApi.listen(handler)
|
|
return listen(channel, eventType, handler)
|
|
end
|
|
|
|
return eventApi;
|
|
end
|
|
|
|
local function start()
|
|
return el.startLoop();
|
|
end
|
|
|
|
local function stop()
|
|
return el.stopLoop();
|
|
end
|
|
|
|
return {
|
|
sendRaw = sendRaw,
|
|
listenRaw = listenRaw,
|
|
send = send,
|
|
listen = listen,
|
|
sendRequest = sendRequest,
|
|
sendMultipleRequests = sendMultipleRequests,
|
|
listenRequest = listenRequest,
|
|
createRequest = createRequest,
|
|
createEvent = createEvent,
|
|
isPacketOk = isPacketOk,
|
|
openChannel = openChannel,
|
|
events = el,
|
|
start = start,
|
|
stop = stop,
|
|
}
|
|
end
|
|
|
|
return createNetwork;
|