Spoiler
local tArgs = { ... }
local function opnmdm()
for i,v in pairs(rs.getSides()) do
if peripheral.getType(v) == "modem" then
if not rednet.isOpen(v) then rednet.open(v) end
return true end
end
return false end
local dmnlst,rlylst,hstID,sndr,mssg,dstnc,cmnd,prm1,xclst = {},{},os.computerID(),tonumber(tArgs[5])
local hstfnc = {
PING = function() rednet.send(sndr,textutils.serialize({xPos,yPos,zPos})) end,
access = function(acsdx) if dmnlst[sndr] then
local tp = {acsdx:match("(%S+)%s*(%S+)%s*(.*)")}
tp[4] = tonumber(tp[2])
if tp[1] == "add" then tp[5] = true elseif tp[1] ~= "ban" then acsdx = nil end
if tp[3] == "dmnlst" then tp[6] = dmnlst elseif tp[3] == "xclst" then
if not xclst then xclst = {} end tp[6] = xclst
else acsdx = nil end
if tp[4] and acsdx then tp[6][tp[4]] = tp[5]
tp[7] = fs.open(tp[3],"w") tp[7].writeLine(textutils.serialize(tp[6])) tp[7].close()
else rednet.send(sndr,"Usage 'access add/ban ID dmnlst/xclst'") end
end end,
bcst = function(bmssg) if dmnlst[sndr] then
if bmssg then rednet.send(nil,bmssg) end
end end,
del = function(flnm) if dmnlst[sndr] then
flnm = flnm:match("%S+")
if fs.exists(flnm) and not flnm == "/" then fs.delete(flnm) rednet.send(sndr,flnm.." deleted")
else rednet.send(sndr,"File not found") end
end end,
dir = function(flnm)
flnm = flnm:match("%S+")
local tdir = fs.list(flnm)
for i = 1,#tdir do rednet.send(sndr,tdir[i]) end
end,
drp = function()
local rID = rlylst[sndr]
rlylst[sndr],rlylst[rID] = nil
local hndl = fs.open("rlylst","w")
hndl.write(textutils.serialize(rlylst)) hndl.close()
rednet.send(sndr,"Relay to ID"..rID.." dropped")
end,
fwd = function(frwd)
local rID,fmssg = frwd:match("(%d+)%s*(.*)$")
rID = tonumber(rID)
if rID and fmssg then rednet.send(rID,fmssg) end
end,
hsts = function() if dmnlst[sndr] then
local ndx,hstlst = 0,{}
rednet.broadcast("PING")
repeat ndx = ndx+1
hstlst[ndx] = {rednet.receive(0.5)}
until not hstlst[ndx][1]
rednet.send(sndr,textutils.serialize(hstlst))
end end,
reboot = function() if dmnlst[sndr] then shell.run("reboot") end end,
rly = function(rlyID)
local rID = tonumber(rlyID)
rlylst[sndr],rlylst[rID] = rID,sndr
local hndl = fs.open("rlylst","w")
hndl.write(textutils.serialize(rlylst)) hndl.close()
rednet.send(sndr,"Relaying to ID"..rlylst[sndr])
end,
rcvfl = function(flnm) if dmnlst[sndr] then
local tp = {flnm:match("(%S+)%s*(.*)")}
tp[3] = fs.open(tp[1],"w") if tp[3] then tp[3].write(tp[2]) tp[3].close()
rednet.send(sndr,tp[1].." Updated")
else rednet.send(sndr,"File is Read Only") end
end end,
srvfl = function(flnm)
flnm = flnm:match("%S+")
local hndl = fs.open(flnm,"r")
if hndl then rednet.send(sndr,hndl.readAll()) hndl.close()
else rednet.send(sndr,"File not found") end
end,
}
if opnmdm() then
xPos,yPos,zPos = gps.locate(2,true )
if tArgs[1] == "host" then
if not xPos then xPos,yPos,zPos = tArgs[2],tArgs[3],tArgs[4]
local itr8 = 0
while not (xPos and yPos and zPos) do
write("Enter x coordinate: ") xPos = tonumber(read())
write("Enter y coordinate: ") yPos = tonumber(read())
write("Enter z coordinate: ") zPos = tonumber(read())
itr8 = itr8+1
if itr8 > 3 then print("Invalid input") return false end
end
end
print("GPS/Relay Node position "..xPos..","..yPos..","..zPos)
local hndl = fs.open("startup","w")
hndl.writeLine("shell.run("rnhst","host","..xPos..","..yPos..","..zPos..")")
hndl.close()
if sndr then hndl,xclst,dmnlst = fs.open("xclst","w"),{[sndr] = true},{[sndr] = true}
hndl.writeLine(textutils.serialize(xclst)) hndl.close()
elseif fs.exists("xclst") then hndl = fs.open("xclst","r")
xclst = textutils.unserialize(hndl.readAll()) hndl.close()
end
if fs.exists("rlylst") then hndl = fs.open("rlylst","r")
rlylst = textutils.unserialize(hndl.readAll()) hndl.close()
end
if fs.exists("dmnlst") then hndl = fs.open("dmnlst","r")
dmnlst = textutils.unserialize(hndl.readAll()) hndl.close()
else hndl = fs.open("dmnlst","w") hndl.writeLine(textutils.serialize(dmnlst)) hndl.close()end
repeat sndr,mssg,dstnc = rednet.receive()
if rlylst[hstID] then rednet.send(rlylst[hstID],sndr..":"..mssg) end
if xclst and not xclst[sndr] then cmnd = "none" else
cmnd,prm1 = mssg:match("^(%S+)%s*(.*)")
if prm1 == "" then prm1 = "/" end
if hstfnc[cmnd] then hstfnc[cmnd](prm1) end
end
if rlylst[sndr] and not hstfnc[cmnd] then rednet.send(rlylst[sndr],mssg) end
until not hstID
return true end
else print("could not open modem") return false
end
The program takes the same command line parameters as the existing gps program, with the addition of a single extra parameter (explained later). However, it differs in that it prefers consistency with an existing gps system and will override the provided parameters if it gets a valid location calculation based on pinging the area. Once it has established its posltion, it saves a startup file so that if it reboots it will have the old position to start from. It also saves the table of relays, and an optional table (which is initially filled with the ID in the aforementioned extra parameter) that restricts access to the functions (including "PING") to an explicit list of authorized IDs. Eventually, I may add a second list that restricts access to the bcst, hsts, rcvfl, and reboot commands (since these can be used to give away the node's position to untrusted rednet ID's or totally take over the relay node).
Feedback is much appreciated, particularly finding bugs. I am already planning to eventually add the "administrator" authorization level and to make it possible to have more than one relay per ID through a given node (there is already a special case when the relay ID is set to the ID of the node, it relays all received messages to the requesting ID).
Okay, fixed now. And now it should be a bit better.
Pastebin link for rnhst. Bugfix. Newest update. Added new commands: access, del, dir, and endhst. The rcvfl and srvfl commands have been renamed to flrcv and flsrv to avoid conflict with the clfn turtle versions (the conflict was originally planned, but deemed pointless on further consideration).