gravitowl

Master Server

Mar 8th, 2021 (edited)
46
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.03 KB | None | 0 0
  1. -- GLOBALS
  2.  
  3. local routers = {}
  4. local servers = {}
  5. local side = "top"
  6. local myID = os.getComputerID()
  7. local w, h = term.getSize()
  8.  
  9. -- Functions & Stuff
  10.  
  11. function writeToFile(data, filename)
  12. local file = fs.open(filename, "w")
  13. file.write(textutils.serialise(data))
  14. file.close()
  15. end
  16.  
  17. function readFromFile(filename)
  18. if not fs.exists(filename) then
  19. return
  20. end
  21. local file = fs.open(filename, "r")
  22. local data = file.readAll()
  23. file.close()
  24. return data
  25. end
  26.  
  27. function split(str, pat)
  28. local t = { }
  29. local fpat = "(.-)"..pat
  30. local last_end = 1
  31. local s, e, cap = str:find(fpat, 1)
  32. while s do
  33. if s ~= 1 or cap ~= "" then
  34. table.insert(t,cap)
  35. end
  36. last_end = e+1
  37. s, e, cap = str:find(fpat, last_end)
  38. end
  39. if last_end <= #str then
  40. cap = str:sub(last_end)
  41. table.insert(t, cap)
  42. end
  43. return t
  44. end
  45.  
  46. function addConnector(newid, parentid, connections)
  47. -- If there are no connectors there is nothing to add to.
  48. if #connections == 0 then return false end
  49.  
  50. for i = 1, #connections, 1 do
  51. local child = connections[i]
  52.  
  53. -- Removing new connector if it already exists.
  54. for j = 1, #child.children, 1 do
  55. if child.children[j].id == newid then
  56. table.remove(child.children, j)
  57. end
  58. end
  59.  
  60. -- If parent connector is found, add new connector to children.
  61. if child.id == parentid then
  62. table.insert(child.children, {
  63. id = newid,
  64. children = {}
  65. })
  66.  
  67. return true
  68. end
  69.  
  70. -- If no parent connector is found, use recursion to go through all children of the the current connector.
  71. addConnector(newid, parentid, child.children)
  72. end
  73.  
  74. -- If no parent connector is found, return false.
  75. return false
  76. end
  77.  
  78. function removeConnector(oldid, connections)
  79. -- If there are no connections we can't remove any.
  80. if #connections == 0 then return false end
  81.  
  82. -- Looping over connections to find target id.
  83. for i = 1, #connections, 1 do
  84. local child = connections[i]
  85.  
  86. -- If current router's id matches the one we're looking for, remove it and return true.
  87. if child.id == oldid then
  88. table.remove(connections, i)
  89. return true
  90. end
  91.  
  92. -- Using recursion to search all children of the current router for the id we're looking for.
  93. if removeConnector(oldid, child.children) then return true end
  94. end
  95.  
  96. -- Returning false if we don't find the id we're looking for.
  97. return false
  98. end
  99.  
  100. function findConnector(id, connections)
  101. -- If no connections are found we have nothing to search for.
  102. if #connections == 0 then return "" end
  103.  
  104. -- Loop through all connections to find the id we're searching for.
  105. for i = 1, #connections, 1 do
  106. local child = connections[i]
  107.  
  108. -- If the current router's id matches the one we're searching for we return that.
  109. if child.id == id then return child.id end
  110.  
  111. -- Using recursion to search routers' childs.
  112. local path = findConnector(id, child.children)
  113.  
  114. -- If a path is found to the id we're searching for, we'll return the current router's id and that path.
  115. if path ~= "" then return child.id.."-"..path end
  116. end
  117.  
  118. return ""
  119. end
  120.  
  121. function findTopConnector(id)
  122. -- Loop over all top routers and check id's.
  123. for i = 1, #routers, 1 do
  124. local route = routers[i]
  125. -- If top router is the one we're searching for we don't return a path.
  126. if route.id == id then
  127. return route.id, ""
  128. end
  129.  
  130. -- Trying to find the id we're searching for in current routers children.
  131. local path = findConnector(id, route.children)
  132.  
  133. -- If a path is found to the id we're searching for, return the current router id and that path.
  134. if path ~= "" then return route.id, path end
  135. end
  136.  
  137. -- If no path at all is found, error.
  138. print("A network error has occured.")
  139. return -1, ""
  140. end
  141.  
  142. function printNetworkTree(connections, index)
  143. -- If no connections, we can't print the network tree.
  144. if #connections == 0 then return end
  145.  
  146. for i = 1, #connections, 1 do
  147. local child = connections[i]
  148. print(string.rep(" ", index)..child.id)
  149. printNetworkTree(child.children, index + 1)
  150. end
  151. end
  152.  
  153. function processRequest(request, senderId)
  154. -- Same in routers, simple responds to messages.
  155. if request == "$HELLO" then
  156. -- If we receive a network discovery message, we'll respond with $HELLO
  157. rednet.send(senderId, "$HELLO")
  158. return
  159.  
  160. elseif request == "$ADDME" then
  161. -- If we receive an add me request, we'll instantly add this router to the network.
  162. table.insert(routers, {
  163. id = senderId,
  164. children = {}
  165. })
  166. local file =
  167. rednet.send(senderId, "$ACK")
  168.  
  169. printNetworkTree(routers, 0)
  170. return
  171. end
  172.  
  173. -- If it's a client request, we'll funnel it down to the next router close to the target router.
  174. if string.find(request, "$CLIENT") then
  175. request = string.gsub(request, "$CLIENT", "")
  176. local values = split(request, "-")
  177.  
  178. -- Finding the path to the target router, to send it to the closest one.
  179. local routeId, dest = findTopConnector(tonumber(values[1]))
  180. if dest ~= "" then
  181. request = dest.."-"..values[2]
  182. else
  183. request = values[2]
  184. end
  185.  
  186. rednet.send(routeId, request)
  187.  
  188. -- If it's a server request, we'll send it to the right server.
  189. elseif string.find(request, "$SERVER") then
  190. local sent = false
  191.  
  192. request = string.gsub(request, "$SERVER", "")
  193.  
  194. -- Finding the server to forward the request to.
  195. for i = 1, #servers, 1 do
  196. local s, e = string.find(request, servers[i].name)
  197. if s == 2 then
  198. request = string.sub(request, e + 1)
  199. rednet.send(servers[i].id, request)
  200. sent = true
  201. break
  202. end
  203. end
  204.  
  205. -- If no server is found, we ignore it.
  206. if not sent then print("No server with the requested name is registered on the network. Requested server: "..request) end
  207.  
  208. -- If it's meant for the master server we'll process it ourselves.
  209. elseif string.find(request, "$MASTER") then
  210. request = string.gsub(request, "$MASTER", "")
  211.  
  212. -- If we receive an add router request, this means the request has been through more than just the original router.
  213. if string.find(request, "$ADDROUTER") then
  214. request = string.gsub(request, "$ADDROUTER", "")
  215. local values = split(request, "-")
  216.  
  217. -- We'll add the router to the children of the router we received the message from.
  218. addConnector(tonumber(values[1]), tonumber(values[2]), routers)
  219. print("Added new router.")
  220.  
  221. printNetworkTree(routers, 0)
  222.  
  223. -- We'll find the nearest router on the path to the newly added router, and send an ackowledged message back.
  224. local routeId, dest = findTopConnector(tonumber(values[1]))
  225. rednet.send(routeId, dest.."-$ACK")
  226.  
  227. -- Adding a new server when receiving this request.
  228. elseif string.find(request, "$ADDSERVER") then
  229. request = string.gsub(request, "$ADDSERVER", "")
  230. local values = split(request, "-")
  231.  
  232. table.insert(servers, {
  233. id = tonumber(values[1]),
  234. name = values[2]
  235. })
  236.  
  237. print("Added new server: "..values[2])
  238.  
  239. rednet.send(senderId, "$ACK")
  240. end
  241.  
  242. -- If the message isn't recognized we'll ignore it.
  243. else
  244. print("Unrecognizable message received.")
  245. end
  246. end
  247.  
  248. function printHeader()
  249. term.setCursorPos(1, 1)
  250. print(string.rep("-", w))
  251. term.setCursorPos(w/2 - #"MASTER SERVER"/2, 2)
  252. print("MASTER SERVER")
  253. term.setCursorPos(1, 3)
  254. print(string.rep("-", w))
  255. print("Open on ID "..myID)
  256. print("")
  257. end
  258.  
  259. -- Main Logic
  260.  
  261. if not fs.exists("gravinet/master/pref") then
  262. error("Master server not installed via installer, make sure to do that!")
  263. return
  264. end
  265.  
  266. local pref = textutils.unserialise(readFromFile("gravinet/master/pref"))
  267. side = pref.side
  268.  
  269. if fs.exists("gravinet/master/routers") then
  270. routers = textutils.unserialise(readFromFile("gravinet/master/routers"))
  271. end
  272.  
  273. if fs.exists("gravinet/master/servers") then
  274. servers = textutils.unserialise(readFromFile("gravinet/master/servers"))
  275. end
  276.  
  277. term.clear()
  278. rednet.open(side)
  279.  
  280. printHeader()
  281.  
  282. while true do
  283. local cx, cy = term.getCursorPos()
  284. printHeader()
  285. term.setCursorPos(cx, cy)
  286. print("Listening for request...")
  287. local requestID, request = rednet.receive()
  288. processRequest(request, requestID)
  289. end
  290. rednet.close()
Add Comment
Please, Sign In to add comment