cc-libs/apis/net.lua

255 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,
open = openChannel,
events = el,
eventloop = el,
start = start,
startLoop = start,
stop = stop,
stopLoop = stop,
}
end
return createNetwork;