MtnMCG

ndisk

Sep 6th, 2024 (edited)
45
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.16 KB | None | 0 0
  1. -- ndisk.lua
  2.  
  3. local modem = peripheral.find("modem") or error("No modem found")
  4. modem.open(1) -- Open channel 1 for communication
  5.  
  6. local nodes = {}
  7. local chunkMap = {}
  8.  
  9. -- Function to save the node IDs
  10. local function saveNodeIds()
  11. local file = fs.open("ids.txt", "w")
  12. for hierarchicalNum, nodeId in pairs(nodes) do
  13. file.writeLine(nodeId .. " " .. hierarchicalNum)
  14. end
  15. file.close()
  16. end
  17.  
  18. -- Function to load the node IDs
  19. local function loadNodeIds()
  20. nodes = {}
  21. if fs.exists("ids.txt") then
  22. local file = fs.open("ids.txt", "r")
  23. for line in file.readLine do
  24. local nodeId, hierarchicalNum = line:match("(%d+)%s+(%d+)")
  25. if nodeId and hierarchicalNum then
  26. nodes[tonumber(hierarchicalNum)] = tonumber(nodeId)
  27. end
  28. end
  29. file.close()
  30. end
  31. end
  32.  
  33. -- Function to save the chunk map
  34. local function saveChunkMap()
  35. local file = fs.open("chunklocation.txt", "w")
  36. for filename, chunks in pairs(chunkMap) do
  37. for chunkNum, nodeId in pairs(chunks) do
  38. file.writeLine(filename .. " chunk" .. chunkNum .. " " .. nodeId)
  39. end
  40. end
  41. file.close()
  42. end
  43.  
  44. -- Function to load the chunk map
  45. local function loadChunkMap()
  46. chunkMap = {}
  47. if fs.exists("chunklocation.txt") then
  48. local file = fs.open("chunklocation.txt", "r")
  49. for line in file.readLine do
  50. local filename, chunk, nodeId = line:match("(%S+)%s+(%S+)%s+(%S+)")
  51. if filename and chunk and nodeId then
  52. chunkMap[filename] = chunkMap[filename] or {}
  53. local chunkNum = tonumber(chunk:match("chunk(%d+)"))
  54. chunkMap[filename][chunkNum] = tonumber(nodeId)
  55. end
  56. end
  57. file.close()
  58. end
  59. end
  60.  
  61. -- Function to discover storage nodes
  62. local function discoverNodes()
  63. print("Discovering storage nodes...")
  64. modem.transmit(1, 1, {type = "discovery"})
  65. local timer = os.startTimer(5)
  66. local discoveredNodes = {}
  67. local nextHierarchicalNum = 1
  68. for num, _ in pairs(nodes) do
  69. if num > nextHierarchicalNum then
  70. nextHierarchicalNum = num + 1
  71. end
  72. end
  73. while true do
  74. local event, param1, param2, param3, param4, param5 = os.pullEvent()
  75. if event == "modem_message" and param4.type == "discovery_response" then
  76. local nodeId = param4.id
  77. local hierarchicalNum = nil
  78. for num, id in pairs(nodes) do
  79. if id == nodeId then
  80. hierarchicalNum = num
  81. break
  82. end
  83. end
  84. if not hierarchicalNum then
  85. hierarchicalNum = nextHierarchicalNum
  86. nodes[hierarchicalNum] = nodeId
  87. nextHierarchicalNum = nextHierarchicalNum + 1
  88. print("Discovered new node: " .. nodeId .. " (Hierarchical #" .. hierarchicalNum .. ")")
  89. else
  90. print("Rediscovered node: " .. nodeId .. " (Hierarchical #" .. hierarchicalNum .. ")")
  91. end
  92. discoveredNodes[nodeId] = hierarchicalNum
  93. elseif event == "timer" and param1 == timer then
  94. break
  95. end
  96. end
  97. saveNodeIds()
  98. return nodes
  99. end
  100.  
  101. -- Function to send a request to a node
  102. local function sendRequest(nodeId, request)
  103. request.targetNode = nodeId
  104. modem.transmit(1, 1, request)
  105. local timer = os.startTimer(5)
  106. while true do
  107. local event, param1, param2, param3, param4, param5 = os.pullEvent()
  108. if event == "modem_message" and param4.id == request.id then
  109. return param4.response
  110. elseif event == "timer" and param1 == timer then
  111. error("Request timed out for node: " .. nodeId)
  112. end
  113. end
  114. end
  115.  
  116. -- Function to distribute a file across nodes
  117. local function distributeFile(path, content)
  118. local nodeCount = 0
  119. for _ in pairs(nodes) do nodeCount = nodeCount + 1 end
  120. local chunkSize = math.ceil(#content / nodeCount)
  121. chunkMap[path] = {}
  122. local chunkNum = 1
  123. for hierarchicalNum, nodeId in pairs(nodes) do
  124. local start = (chunkNum - 1) * chunkSize + 1
  125. local chunk = content:sub(start, math.min(start + chunkSize - 1, #content))
  126. local response = sendRequest(nodeId, {
  127. id = os.getComputerID() .. "_" .. os.clock(),
  128. action = "write",
  129. path = path,
  130. chunk = chunkNum,
  131. content = chunk
  132. })
  133. if not response.success then
  134. error("Failed to write chunk " .. chunkNum .. " to node " .. nodeId)
  135. end
  136. chunkMap[path][chunkNum] = nodeId
  137. chunkNum = chunkNum + 1
  138. end
  139. saveChunkMap()
  140. end
  141.  
  142. -- Function to read a file from nodes
  143. local function readFile(path)
  144. if not chunkMap[path] then
  145. error("File not found: " .. path)
  146. end
  147. local content = {}
  148. for chunkNum, nodeId in pairs(chunkMap[path]) do
  149. local response = sendRequest(nodeId, {
  150. id = os.getComputerID() .. "_" .. os.clock(),
  151. action = "read",
  152. path = path,
  153. chunk = chunkNum
  154. })
  155. if response.success then
  156. content[chunkNum] = response.content
  157. else
  158. error("Failed to read chunk " .. chunkNum .. " from node " .. nodeId)
  159. end
  160. end
  161. return table.concat(content)
  162. end
  163.  
  164. -- Function to delete a file from nodes
  165. local function deleteFile(path)
  166. if not chunkMap[path] then
  167. error("File not found: " .. path)
  168. end
  169. for chunkNum, nodeId in pairs(chunkMap[path]) do
  170. local response = sendRequest(nodeId, {
  171. id = os.getComputerID() .. "_" .. os.clock(),
  172. action = "delete",
  173. path = path,
  174. chunk = chunkNum
  175. })
  176. if not response.success then
  177. error("Failed to delete chunk " .. chunkNum .. " from node " .. nodeId)
  178. end
  179. end
  180. chunkMap[path] = nil
  181. saveChunkMap()
  182. end
  183.  
  184. -- Function to list files
  185. local function listFiles()
  186. local files = {}
  187. for file, _ in pairs(chunkMap) do
  188. table.insert(files, file)
  189. end
  190. return files
  191. end
  192.  
  193. -- Function to get total storage space
  194. local function getTotalStorage()
  195. local total = 0
  196. for _, nodeId in pairs(nodes) do
  197. local response = sendRequest(nodeId, {
  198. id = os.getComputerID() .. "_" .. os.clock(),
  199. action = "getSpace"
  200. })
  201. if response.success then
  202. total = total + response.space
  203. end
  204. end
  205. return total
  206. end
  207.  
  208. -- Main program
  209. loadNodeIds()
  210. nodes = discoverNodes()
  211. if next(nodes) == nil then
  212. error("No storage nodes found. Make sure the storage nodes are running and connected.")
  213. end
  214. print("Found " .. #nodes .. " storage node(s)")
  215. loadChunkMap()
  216.  
  217. -- Command loop
  218. while true do
  219. write("ndisk> ")
  220. local input = read()
  221. local command = {}
  222. for word in input:gmatch("%S+") do
  223. table.insert(command, word)
  224. end
  225.  
  226. if command[1] == "list" then
  227. local files = listFiles()
  228. for _, file in ipairs(files) do
  229. print(file)
  230. end
  231. elseif command[1] == "read" and command[2] then
  232. local content = readFile(command[2])
  233. print(content)
  234. elseif command[1] == "write" and command[2] then
  235. print("Enter file content (press Enter twice to finish):")
  236. local content = ""
  237. while true do
  238. local line = read()
  239. if line == "" then break end
  240. content = content .. line .. "\n"
  241. end
  242. distributeFile(command[2], content)
  243. print("File written successfully.")
  244. elseif command[1] == "delete" and command[2] then
  245. deleteFile(command[2])
  246. print("File deleted successfully.")
  247. elseif command[1] == "space" then
  248. local space = getTotalStorage()
  249. print("Total storage space: " .. space .. " bytes")
  250. elseif command[1] == "exit" then
  251. break
  252. else
  253. print("Unknown command. Available commands: list, read <filename>, write <filename>, delete <filename>, space, exit")
  254. end
  255. end
  256.  
  257. print("Exiting ndisk.")
Advertisement
Add Comment
Please, Sign In to add comment