From 9c0f7a79dca06775f03a05f8fb5565b2f6cafdc3 Mon Sep 17 00:00:00 2001 From: Guillaume ARM Date: Fri, 15 Jul 2022 10:25:29 +0200 Subject: [PATCH] chore: init base --- apis/net.lua | 139 ++++++++++++++++++++++++++++++++++++++++++++ ping-server.lua | 30 ++++++++++ ping.lua | 33 +++++++++++ router.lua | 71 ++++++++++++++++++++++ startup/servers.lua | 41 +++++++++++++ 5 files changed, 314 insertions(+) create mode 100644 apis/net.lua create mode 100644 ping-server.lua create mode 100644 ping.lua create mode 100644 router.lua create mode 100644 startup/servers.lua diff --git a/apis/net.lua b/apis/net.lua new file mode 100644 index 0000000..f70d01f --- /dev/null +++ b/apis/net.lua @@ -0,0 +1,139 @@ +-- Network API v1.0.1 + +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: +-- - 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 + return false; + end + + if not payload.routerId or not payload.sourceId then + return false; + end + + if payload.sourceId == os.getComputerID() then + return false; + end + + if payload.destId == nil then + return true; + end + + if type(payload.destId) == 'number' and payload.destId == os.getComputerID() then + return true; + end + + if type(payload.destId) == 'string' and payload.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(); +-- +-- -- 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) + modem = modem or peripheral.find("modem") or error("modem not found"); + routingChannel = routingChannel or DEFAULT_ROUTING_CHANNEL; + timeoutInSec = timeoutInSec or DEFAULT_TIMEOUT_WAIT_MESSAGE; + + -- net.send function + local function send(channel, message, destId) + local payload = { + sourceId = os.getComputerID(), + sourceLabel = os.getComputerLabel(), + routerId = nil, + destId = destId, + message = message + } + + modem.transmit(routingChannel, channel, payload); + end + + -- net.waitMessage function + local function waitMessage(channelToListen) + local receivedPayload; + + 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; + end + until channelOk and payloadOk or timedOut + + if timedOut then + return nil; + end + + if receivedPayload then + return receivedPayload.message, receivedPayload; + end + + return nil; + end + + return { + send = send, + waitMessage = waitMessage + } +end + +return createNetwork; diff --git a/ping-server.lua b/ping-server.lua new file mode 100644 index 0000000..c0aa4d1 --- /dev/null +++ b/ping-server.lua @@ -0,0 +1,30 @@ +-- ping-server v1.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 modem = peripheral.find('modem'); + +if not modem then + print("Warning: modem not found!"); +end + +-- on attend le modem +while not modem do + modem = peripheral.find('modem'); + os.sleep(MODEM_DETECTION_TIME); +end + +local net = createNet(modem); + +while true do + local message, payload = net.waitMessage(PING_CHANNEL); + + 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); + end +end diff --git a/ping.lua b/ping.lua new file mode 100644 index 0000000..1b4f7b6 --- /dev/null +++ b/ping.lua @@ -0,0 +1,33 @@ +-- ping v1.2.0 +local PING_CHANNEL = 9; + +local createNet = require('apis/net'); +local net = createNet(); + +local args = table.pack(...); +local targetComputerId = tonumber(args[1]) or args[1]; + + +local sourceId = os.getComputerID() +local sourceLabel = os.getComputerLabel(); + +-- gérer les pongs locales +if targetComputerId == nil or targetComputerId == sourceId or targetComputerId == sourceLabel then + print("=> local pong from " .. tostring(sourceId) + .. (sourceLabel and " (label=" .. tostring(sourceLabel) .. ")" or "")); +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); + + if message == "pong" then + print("=> pong from " .. tostring(payload.sourceId) + .. (payload.sourceLabel and " (label=" .. tostring(payload.sourceLabel) .. ")" or "")); + elseif message == nil then + break + end +end diff --git a/router.lua b/router.lua new file mode 100644 index 0000000..5c509a1 --- /dev/null +++ b/router.lua @@ -0,0 +1,71 @@ +-- router v1.1.0 + +local ROUTER_CHANNEL = 10; +local VERBOSE = true; + +local modem = peripheral.find("modem") or error("modem not found"); +modem.open(ROUTER_CHANNEL); + +local routerId = os.getComputerID(); + +local function isPingForServer(payload) + if payload.message ~= 'ping' then + return false; + end + + if payload.destId == routerId or payload.destId == os.getComputerLabel() then + return true; + end + + if payload.destId == nil then + return true; + end + + return false; +end + +while true do + local channel, replyChannel, payload, pingForServer; + + repeat + _, _, channel, replyChannel, payload = os.pullEvent("modem_message"); + pingForServer = isPingForServer(payload) + + local channelOk = channel == ROUTER_CHANNEL; + local payloadOk = type(payload) == 'table' and not payload.routerId or pingForServer; + local loopFinished = channelOk and payloadOk; + until loopFinished + + + if payload and not payload.routerId then + if pingForServer then + local responseRouterPayload = { + sourceId = os.getComputerID(), + sourceLabel = os.getComputerLabel(), + routerId = routerId, + destId = payload.sourceId, + message = 'pong' + } + modem.transmit(replyChannel, replyChannel, responseRouterPayload) + end + if not pingForServer or payload.destId == nil then + payload.routerId = routerId; + modem.transmit(replyChannel, replyChannel, payload); + end + end + + if VERBOSE then + if payload.destId then + if pingForServer then + print('ping for server received!'); + else + print("Routed message from " .. tostring(payload.sourceId) + .. " to " .. tostring(payload.destId) + .. " using channel " .. tostring(replyChannel)); + end + else + print("Broadcasted message from " .. tostring(payload.sourceId) + .. " using channel " .. tostring(replyChannel)); + end + end +end diff --git a/startup/servers.lua b/startup/servers.lua new file mode 100644 index 0000000..ed62ab9 --- /dev/null +++ b/startup/servers.lua @@ -0,0 +1,41 @@ +-- Server Launcher v1.0.0 + +local SERVERS = { + "ping-server", +}; + +local function shellFn() + os.sleep(0.1); + shell.run("shell"); +end + +local function getServerFns(serverList) + local servers = {}; + + for k, v in ipairs(serverList) do + local serverName = serverList[k]; + + servers[k] = function() + if serverName then + shell.run(serverName); + end + end + end + + return servers; +end + +local servers = getServerFns(SERVERS); + +print("\nStarting servers..."); + +for _, v in ipairs(SERVERS) do + print("\t\t" .. v) +end + +parallel.waitForAny(shellFn, table.unpack(servers)); + +print("Servers stopped, reboot the machine..."); + +os.sleep(1); +os.reboot();