Advertisement
Guest User

Untitled

a guest
Nov 22nd, 2019
138
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.42 KB | None | 0 0
  1. --file formatting:
  2. --name size(1), name([1]), address(16), size of size (1), size([3]), file([4])
  3. --this file is designed to be require()ed
  4. --implements raid4 array on unmanaged drives
  5. --this version is for use with the server drive group stuff, rather than accessing its own drives
  6. local comp = require("component")
  7. local network = comp.modem
  8. local event = require("event")
  9. local raidmanager = {} --for holding the methods and such
  10. _G.driveServerTbl = _G.driveServerTbl or {}
  11. if _G.driveServerCount == nil then
  12. error("No global driveServerCount found")
  13. goto exit
  14. elseif type(_G.driveServerCount) ~= "number" then
  15. error("Global driveServerCount found but it is not a number")
  16. goto exit
  17. elseif _G.driveServerCount ~= math.floor(_G.driveServerCount) or _G.driveServerCount < 1 then
  18. error("Global driveServerCount found but it is an invalid number (" .. _G.driveServerCount .. ")")
  19. goto exit
  20. end
  21. serverCount = _G.driveServerCount
  22. network.open(12345)
  23. if #(_G.driveServerTbl) == 0 then --set _G.driveServerTbl to {} or nil to reset. Or 0, I guess?
  24. network.broadcast(12345, "raidConnectionCheck")
  25. for i=1,serverCount do
  26. local _, _, server, _, _, confirm = event.pull("modem_message")
  27. _G.driveServerTbl[i] = server
  28. print(server)
  29. end
  30. end
  31. raidmanager.getFileSize = function(driveDex, startLoc)
  32. local drive =_G.driveServerTbl[driveDex]
  33. local currLoc = startLoc
  34. network.send(drive, 12345, "readByte", currLoc)
  35. local _, _, _, _, _, nameSize = event.pull("modem_message")
  36. currLoc = currLoc + 1 + nameSize --nameSize and name
  37. currLoc = currLoc + 16 --address
  38. network.send(drive, 12345, "readByte", currLoc)
  39. local _, _, _, _, _, sizeSize = event.pull("modem_message")
  40. --would add 1 but do that later
  41. local size = 1
  42. for i=1, sizeSize do
  43. network.send(drive, 12345, "readByte", currLoc + i)
  44. local _, _, _, _, _, thisbyte = event.pull("modem_message")
  45. size = 256*size + string.byte(thisbyte)
  46. end
  47. return 1 + nameSize + 16 + 1 + sizeSize + size --namesize, name, address, sizesize, size, data
  48. end
  49. --simplifies a little so we don't need 3 of the same code in each of these
  50. local sendReceive = function(address, arg1, arg2, arg3, arg4)
  51. network.send(address, 12345, arg1, arg2, arg3, arg4)
  52. local results = table.pack(event.pull("modem_message"))
  53. print(table.unpack(results))
  54. if #results == 6 then
  55. return results[6]
  56. end
  57. local subResults = {}
  58. for i=6, #results do
  59. subResults[i-5] = results[i]
  60. end
  61. return subResults
  62. end
  63. --this gets the size the given data's file would be rather than the size of an existing file on the drive
  64. raidmanager.getDataSize = function(name, data)
  65. local nameSize = string.len(name)
  66. local size = string.len(data)
  67. local sizeSize = math.ceil(math.log(size+1)/math.log(256))
  68. return 1 + nameSize + 16 + 1 + sizeSize + size
  69. end
  70. raidmanager.nextEmptySpace = function(driveDex)
  71. local drive =_G.driveServerTbl[driveDex]
  72. local currLoc = 1
  73. --no file can have an empty name so a 0 in nameSize indicates no file
  74. while currLoc < sendReceive(drive, "getCapacity") and sendReceive(drive, "readByte", currLoc) do
  75. currLoc = currLoc + raidmanager.getFileSize(driveDex, currLoc)
  76. end
  77. return currLoc
  78. end
  79. raidmanager.getMinCapacity = function()
  80. local minSize = math.huge
  81. for i=2,#_G.driveServerTbl do --skip 1 since that's parity
  82. minSize = math.min(minSize, tonumber(sendReceive(_G.driveServerTbl[i], "getCapacity")))
  83. end
  84. return minSize
  85. end
  86. raidmanager.getRemainingSpaces = function()
  87. local caps = {}
  88. local minSize = raidmanager.getMinCapacity()
  89. for i=2,#_G.driveServerTbl do --skip 1 since that's parity
  90. caps[i-1] = raidmanager.nextEmptySpace(i)
  91. end
  92. for i=1, #caps do
  93. caps[i] = minSize - caps[i]
  94. print(caps[i])
  95. end
  96. return caps
  97. end
  98. raidmanager.refreshParity = function()
  99. local minSize = raidmanager.getMinCapacity()
  100. for i=1,minSize do
  101. local thisByte = 0
  102. for j=2,#_G.driveServerTbl do
  103. thisByte = bit32.bxor(thisByte, sendReceive(_G.driveServerTbl[j], "readByte" , i))
  104. end
  105. network.send(_G.driveServerTbl[1], "writeByte", i, thisByte)
  106. end
  107. end
  108. raidmanager.readFile = function(driveDex, startLoc, userAddress)
  109. local drive =_G.driveServerTbl[driveDex]
  110. local currLoc = startLoc
  111. local nameSize = sendReceive(drive, "readByte", currLoc)
  112. currLoc = currLoc + 1
  113. local name = ""
  114. for i=0,nameSize-1 do
  115. name = name .. string.char(sendReceive(drive, "readByte", currLoc + i))
  116. end
  117. currLoc = currLoc + nameSize
  118. local address = ""
  119. for i=0, 15 do
  120. address = address .. string.char(sendReceive(drive, "readByte", currLoc + i))
  121. end
  122. currLoc = currLoc + 16
  123. local sizeSize = sendReceive(drive, "readByte", currLoc)
  124. currLoc = currLoc + 1
  125. local size = 0
  126. for i=0,sizeSize-1 do
  127. size = 256*size + sendReceive(drive, "readByte", currLoc+i)
  128. currLoc = currLoc + 1
  129. end
  130. local data = ""
  131. for i=0,size-1 do
  132. data = data .. string.char(sendReceive(drive, "readByte", currLoc + i))
  133. currLoc = currLoc + 1
  134. end
  135. if address == userAddress then
  136. return name, address, data, currLoc --next byte, useful for iterating
  137. else
  138. return "Not Allowed"
  139. end
  140. end
  141. raidmanager.findFile = function(name, address)
  142. local cap = raidmanager.getMinCapacity()
  143. for i=2,#_G.driveServerTbl do
  144. local drive =_G.driveServerTbl[i]
  145. local stop = raidmanager.nextEmptySpace(i)
  146. local loc = 1
  147. local last
  148. local curName
  149. local addr
  150. local found = false
  151. repeat
  152. last = loc
  153. curName, addr, _, loc = raidmanager.readFile(i, loc)
  154. if name == currName then
  155. found = true
  156. end
  157. until found or loc >= stop --shouldn't go above stop but better to avoid infinite loops
  158. if found then
  159. if addr == address then
  160. return drive,last --returning the drive index as well as the index of its position
  161. else
  162. return "Not allowed"
  163. end
  164. else
  165. return "Not found"
  166. end
  167. end
  168. end
  169. raidmanager.writeFile = function(name, address, data)
  170. --find a drive it will fit on
  171. local drive, dex = raidmanager.findFile(name, address)
  172. local driveDex = 0
  173. local currLoc = 0
  174. local insert = false
  175. if drive == "Not found" then
  176. local fullSize = raidmanager.getDataSize(name, address, data)
  177. if fullSize > raidmanager.getMinCapacity() then
  178. return 0
  179. end
  180. local caps = raidmanager.getRemainingSpaces()
  181.  
  182. for i=1,#caps do
  183. if fullSize <= caps[i] then
  184. driveDex = i+1
  185. break
  186. end
  187. end
  188. elseif type(drive) == "number" then --found and allowed
  189. driveDex = drive
  190. currLoc = dex
  191. insert = true
  192. end
  193. if driveDex > 0 then
  194. if insert then
  195. --read current file, compare to this size, slide bytes around as needed
  196. end
  197. local drive =_G.driveServerTbl[driveDex]
  198. if currLoc == 0 then
  199. currLoc = raidmanager.nextEmptySpace(driveDex)
  200. end
  201. local nameSize = string.len(name)
  202. network.send(drive, "writeByte", currLoc, nameSize)
  203. currLoc = currLoc + 1
  204. for i=1,nameSize do
  205. network.send(drive, 12345, "writeByte", currLoc, string.byte(name, i))
  206. currLoc = currLoc + 1
  207. end
  208. for i=1,16 do
  209. network.send(drive, 12345, "writeByte", currLoc, string.byte(address, i))
  210. currLoc = currLoc + 1
  211. end
  212. local size = string.len(data)
  213. local sizeSize = math.ceil(math.log(1+size)/math.log(256))
  214. network.send(drive, writeByte, currLoc, sizeSize)
  215. currLoc = currLoc + 1
  216. local cur = size
  217. local mod
  218. for i=sizeSize-1,0,-1 do
  219. mod = cur % 256
  220. network.send(drive, "writeByte", currLoc + i, mod)
  221. cur = math.floor(cur / 256)
  222. end
  223. currLoc = currLoc + sizeSize
  224. for i=1,size do
  225. network.send(drive, "writeByte", currLoc, string.byte(data, i))
  226. currLoc = currLoc + 1
  227. end
  228. raidmanager.refreshParity()
  229. return drive, startLoc
  230. else
  231. return "No space"
  232. end
  233. end
  234. raidmanager.readByName = function(name, address)
  235. local drive, loc = raidmanager.findFile(name, address)
  236. if type(drive) == "string" then
  237. return drive --either "Not allowed" or "Not found", just pass it along
  238. end
  239. return raidmanager.readFile(drive, loc, address)
  240. end
  241. --appends data to end of existing file. Good for files too large to pass at once (particularly useful for use with networks)
  242. raidmanager.appendFile = function(name, address, newData)
  243. local driveOrMsg, dex = raidmanager.findFile(name, address)
  244. if type(driveOrMsg) == "string" then --"Not allowed" or "Not found"
  245. return driveOrMsg
  246. end
  247. local _, _, data, _ = raidmanager.readFile(driveOrMsg, dex, address)
  248. local data = oldData .. newData
  249. raidmanager.writeFile(name, address, data)
  250. end
  251. return raidmanager
  252. ::exit:: --if it can't load, no point trying to return anything
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement