feat: net and eventloop v2
This commit is contained in:
parent
dab6e0011e
commit
280a28777c
@ -6,7 +6,8 @@ wget run https://raw.githubusercontent.com/guillaumearm/cc-libs/master/install.l
|
||||
```
|
||||
|
||||
## Apis
|
||||
- `apis/net`: api to simplify sending and receiving routed messages
|
||||
- `apis/eventloop`: a simple eventloop library
|
||||
- `apis/net`: api to simplify sending and receiving routed messages (based on eventloop library)
|
||||
|
||||
## Servers
|
||||
- `router`: route messages (you need to setup a router to be able to use `apis/net`)
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
-- eventloop 2.0.0
|
||||
|
||||
-- Basic event loop library for computer craft
|
||||
--
|
||||
-- Example usage:
|
||||
@ -23,7 +25,7 @@ end
|
||||
|
||||
local STOP = '@libeventloop/STOP_HANDLER_SUBSCRIPTION';
|
||||
|
||||
local function createEventLoop(net) -- TODO listenMessages
|
||||
local function createEventLoop()
|
||||
local api = {}
|
||||
|
||||
local runningLoop = false;
|
||||
@ -358,16 +360,6 @@ local function createEventLoop(net) -- TODO listenMessages
|
||||
end
|
||||
end
|
||||
|
||||
function api.listenMessages(givenChannel, handler)
|
||||
net.openChannel(givenChannel)
|
||||
|
||||
return api.register("modem_message", function(_, channel, _, payload)
|
||||
if net.isPayloadOk(payload) and channel == givenChannel then
|
||||
handler(payload.message);
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- onStop
|
||||
function api.onStop(handler)
|
||||
assert(type(handler) == 'function', 'bad argument #1 (function expected)')
|
||||
|
||||
217
apis/net.lua
217
apis/net.lua
@ -1,37 +1,39 @@
|
||||
-- Network API v1.0.1
|
||||
-- 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 payload nous est destiné.
|
||||
-- le parametre 'payload' est une table avec les champs suivants:
|
||||
-- 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 isPayloadOk(payload)
|
||||
if type(payload) ~= "table" then
|
||||
local function isPacketOk(packet)
|
||||
if type(packet) ~= "table" then
|
||||
return false;
|
||||
end
|
||||
|
||||
if not payload.routerId or not payload.sourceId then
|
||||
if not packet.routerId or not packet.sourceId then
|
||||
return false;
|
||||
end
|
||||
|
||||
if payload.sourceId == os.getComputerID() then
|
||||
if packet.sourceId == os.getComputerID() then
|
||||
return false;
|
||||
end
|
||||
|
||||
if payload.destId == nil then
|
||||
if packet.destId == nil then
|
||||
return true;
|
||||
end
|
||||
|
||||
if type(payload.destId) == 'number' and payload.destId == os.getComputerID() then
|
||||
if type(packet.destId) == 'number' and packet.destId == os.getComputerID() then
|
||||
return true;
|
||||
end
|
||||
|
||||
if type(payload.destId) == 'string' and payload.destId == os.getComputerLabel() then
|
||||
if type(packet.destId) == 'string' and packet.destId == os.getComputerLabel() then
|
||||
return true;
|
||||
end
|
||||
|
||||
@ -69,24 +71,27 @@ end
|
||||
--
|
||||
-- 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)
|
||||
--
|
||||
-- -- envoyer un message sur le canal 9
|
||||
-- net.send(9, 'ping');
|
||||
--
|
||||
-- -- recevoir et afficher un message sur le canal 9
|
||||
-- local message = net.waitMessage(9);
|
||||
-- if message == 'pong' then
|
||||
-- print('pong recu');
|
||||
-- end
|
||||
--
|
||||
local function createNetwork(modem, routingChannel, timeoutInSec)
|
||||
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 send(channel, message, destId)
|
||||
local payload = {
|
||||
local function sendRaw(channel, message, destId)
|
||||
local packet = {
|
||||
sourceId = os.getComputerID(),
|
||||
sourceLabel = os.getComputerLabel(),
|
||||
routerId = nil,
|
||||
@ -94,51 +99,151 @@ local function createNetwork(modem, routingChannel, timeoutInSec)
|
||||
message = message
|
||||
}
|
||||
|
||||
modem.transmit(routingChannel, channel, payload);
|
||||
return modem.transmit(routingChannel, channel, packet);
|
||||
end
|
||||
|
||||
-- net.waitMessage function
|
||||
local function waitMessage(channelToListen)
|
||||
local receivedPayload;
|
||||
local function listenRaw(channel, handler)
|
||||
openChannel(channel);
|
||||
|
||||
modem.open(channelToListen);
|
||||
|
||||
local timerId = os.startTimer(timeoutInSec);
|
||||
local timedOut = false;
|
||||
|
||||
repeat
|
||||
local messageType, timerIdOrSide, channel, _, payload = pullMultipleEvents("modem_message", "timer");
|
||||
local channelOk, payloadOk;
|
||||
|
||||
if messageType == "modem_message" then
|
||||
receivedPayload = payload;
|
||||
channelOk = channel == channelToListen;
|
||||
payloadOk = isPayloadOk(payload);
|
||||
elseif messageType == 'timer' and timerIdOrSide == timerId then
|
||||
timedOut = true;
|
||||
return el.register('modem_message', function(_, _, replyChannel, packet)
|
||||
if isPacketOk(packet) and channel == replyChannel then
|
||||
handler(packet.message, packet);
|
||||
end
|
||||
until channelOk and payloadOk or timedOut
|
||||
|
||||
if timedOut then
|
||||
return nil;
|
||||
end
|
||||
|
||||
if receivedPayload then
|
||||
return receivedPayload.message, receivedPayload;
|
||||
end
|
||||
|
||||
return nil;
|
||||
end)
|
||||
end
|
||||
|
||||
local function openChannel(chan)
|
||||
modem.open(chan);
|
||||
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,
|
||||
waitMessage = waitMessage,
|
||||
isPayloadOk = isPayloadOk,
|
||||
listen = listen,
|
||||
sendRequest = sendRequest,
|
||||
sendMultipleRequests = sendMultipleRequests,
|
||||
listenRequest = listenRequest,
|
||||
createRequest = createRequest,
|
||||
createEvent = createEvent,
|
||||
isPacketOk = isPacketOk,
|
||||
openChannel = openChannel,
|
||||
events = el,
|
||||
start = start,
|
||||
stop = stop,
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
@ -1,12 +1,15 @@
|
||||
local LIST_FILES = {
|
||||
'ping.lua',
|
||||
'ping-server.lua',
|
||||
'router.lua',
|
||||
'startup/servers.lua',
|
||||
'servers/ping-server.lua',
|
||||
'ping.lua',
|
||||
'router.lua',
|
||||
'apis/net.lua',
|
||||
'apis/eventloop.lua',
|
||||
};
|
||||
|
||||
-- remove old files
|
||||
fs.delete('ping-server.lua')
|
||||
|
||||
local REPO_PREFIX = 'https://raw.githubusercontent.com/guillaumearm/cc-libs/master/'
|
||||
|
||||
local previousDir = shell.dir()
|
||||
|
||||
25
ping.lua
25
ping.lua
@ -1,4 +1,4 @@
|
||||
-- ping v1.2.0
|
||||
-- ping v2.0.0
|
||||
local PING_CHANNEL = 9;
|
||||
|
||||
local createNet = require('apis/net');
|
||||
@ -7,7 +7,6 @@ local net = createNet();
|
||||
local args = table.pack(...);
|
||||
local targetComputerId = tonumber(args[1]) or args[1];
|
||||
|
||||
|
||||
local sourceId = os.getComputerID()
|
||||
local sourceLabel = os.getComputerLabel();
|
||||
|
||||
@ -18,16 +17,20 @@ if targetComputerId == nil or targetComputerId == sourceId or targetComputerId =
|
||||
end
|
||||
|
||||
-- envoyer un message sur le canal 9 à la machine cible
|
||||
net.send(PING_CHANNEL, "ping", targetComputerId);
|
||||
|
||||
-- recevoir et afficher un message sur le canal 9
|
||||
while true do
|
||||
local message, payload = net.waitMessage(PING_CHANNEL);
|
||||
local ok, results, packets = net.sendMultipleRequests(PING_CHANNEL, 'ping', 'ping', targetComputerId);
|
||||
|
||||
if message == "pong" then
|
||||
print("=> pong from " .. tostring(payload.sourceId)
|
||||
.. (payload.sourceLabel and " (label=" .. tostring(payload.sourceLabel) .. ")" or ""));
|
||||
elseif message == nil then
|
||||
break
|
||||
if not ok then
|
||||
error(results)
|
||||
end
|
||||
|
||||
for k, message in ipairs(results) do
|
||||
if message == 'pong' then
|
||||
local packet = packets[k];
|
||||
|
||||
-- if targetComputerId == nil or targetComputerId == packet.sourceId or targetComputerId == packet.sourceLabel then
|
||||
print("=> pong from " .. tostring(packet.sourceId)
|
||||
.. (packet.sourceLabel and " (label=" .. tostring(packet.sourceLabel) .. ")" or ""));
|
||||
-- end
|
||||
end
|
||||
end
|
||||
|
||||
13
router.lua
13
router.lua
@ -1,4 +1,4 @@
|
||||
-- router v1.1.0
|
||||
-- router v1.2.0
|
||||
|
||||
local ROUTER_CHANNEL = 10;
|
||||
local VERBOSE = true;
|
||||
@ -6,10 +6,17 @@ local VERBOSE = true;
|
||||
local modem = peripheral.find("modem") or error("modem not found");
|
||||
modem.open(ROUTER_CHANNEL);
|
||||
|
||||
print('started router on port ' .. tostring(ROUTER_CHANNEL) .. '...')
|
||||
|
||||
local routerId = os.getComputerID();
|
||||
|
||||
local function isPingForServer(payload)
|
||||
if payload.message ~= 'ping' then
|
||||
|
||||
if not payload.message then
|
||||
return false;
|
||||
end
|
||||
|
||||
if payload.message.type ~= 'ping' then
|
||||
return false;
|
||||
end
|
||||
|
||||
@ -44,7 +51,7 @@ while true do
|
||||
sourceLabel = os.getComputerLabel(),
|
||||
routerId = routerId,
|
||||
destId = payload.sourceId,
|
||||
message = 'pong'
|
||||
message = { type = "ping_response", payload = "pong" }
|
||||
}
|
||||
modem.transmit(replyChannel, replyChannel, responseRouterPayload)
|
||||
end
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
-- ping-server v1.0.0
|
||||
-- ping-server v2.0.0
|
||||
|
||||
-- -- Example: implementation simple de ping-server
|
||||
local PING_CHANNEL = 9;
|
||||
local MODEM_DETECTION_TIME = 3; -- in seconds
|
||||
|
||||
local createNet = require('apis/net');
|
||||
local createNet = require('/apis/net');
|
||||
|
||||
local modem = peripheral.find('modem');
|
||||
|
||||
@ -18,13 +18,13 @@ while not modem do
|
||||
os.sleep(MODEM_DETECTION_TIME);
|
||||
end
|
||||
|
||||
local net = createNet(modem);
|
||||
|
||||
while true do
|
||||
local message, payload = net.waitMessage(PING_CHANNEL);
|
||||
local net = createNet(nil, modem);
|
||||
|
||||
net.listenRequest(PING_CHANNEL, 'ping', function(message, reply)
|
||||
if message == 'ping' then
|
||||
-- le troisième parametre de la fonction `net.send` est pour router un message a une machine specifique
|
||||
net.send(PING_CHANNEL, 'pong', payload.sourceId);
|
||||
reply('pong');
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
net.start();
|
||||
@ -1,7 +1,7 @@
|
||||
-- Server Launcher v1.0.0
|
||||
|
||||
local SERVERS = {
|
||||
"ping-server",
|
||||
"servers/ping-server",
|
||||
};
|
||||
|
||||
local function shellFn()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user