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