OpenComputers Von Neumann Machine Programs
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

217 lines
5.4 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. local component = component or require("component")
  2. local computer = computer or require("computer")
  3. local sides = sides or require("sides")
  4. local event = event or require("event")
  5. local os = os or require("os")
  6. local net = net or require("net")
  7. local Server = Server or require("server")
  8. local Queue = Queue or require("queue")
  9. -- location of eeprom in computer case
  10. local EEPROM_SLOT = 10
  11. local transposer = component.transposer
  12. local WEB_FLASH_PORT = 30
  13. local WORKER_PORT = 31
  14. -- Waits for a SYN from a worker and responds with an ACK
  15. -- Returns the workers address
  16. local function meetWorker()
  17. print("Waiting for worker")
  18. local function syn(name, ...)
  19. -- local addr, remote addr, port, distance, msg
  20. local t = {...}
  21. return t[5] == "SYN"
  22. end
  23. -- Wait for a SYN
  24. local pkt, err = net.recv{WORKER_PORT, filter = syn}
  25. -- ACK the worker
  26. net.send(pkt.raddr, WORKER_PORT, "ACK")
  27. print("Found worker ", pkt.raddr)
  28. return pkt.raddr
  29. end
  30. -- Checks if the top chest is filled
  31. local function isFilled()
  32. local i = 1
  33. for k in transposer.getAllStacks(sides.top) do
  34. if k.size == nil then break end
  35. i = i + 1
  36. end
  37. return i >= 27
  38. end
  39. -- Moves the EEPROM from the worker into the top chest
  40. -- Optionally include the slot
  41. -- Returns the slot the eeprom was moved to
  42. local function removeEEPROM(sink_slot)
  43. print("REMOVING - ", sink_slot)
  44. if sink_slot == nil then
  45. local i = 1
  46. for k in transposer.getAllStacks(sides.top) do
  47. if k.size == nil then break end
  48. i = i + 1
  49. end
  50. if i == 27 then
  51. return nil, "Inventory filled"
  52. end
  53. sink_slot = i
  54. end
  55. -- Remove the OpenOS Bios and store it in the top chest
  56. transposer.transferItem(sides.left, sides.top, 1, EEPROM_SLOT, sink_slot)
  57. return sink_slot
  58. end
  59. -- Moves a blank EEPROM from storage into the worker
  60. local function loadNewEEPROM()
  61. print("LOADING")
  62. -- Find largest inventory slot in the storage with an eeprom
  63. local i = 1
  64. local last = nil
  65. for k in transposer.getAllStacks(sides.right) do
  66. if k.size ~= nil then
  67. last = i
  68. end
  69. i = i + 1
  70. end
  71. if last == nil then
  72. return nil, "No EEPROMS"
  73. end
  74. -- Move the new EEPROM into computer
  75. transposer.transferItem(sides.right, sides.left, 1, last, EEPROM_SLOT)
  76. return true
  77. end
  78. local function flashEEPROM(worker, data, label)
  79. print("Send", worker, WORKER_PORT, "flash", label)
  80. net.send(worker, WORKER_PORT, "flash", data, label)
  81. local function fromWorker(name, ...)
  82. t = {...}
  83. return t[2] == worker
  84. end
  85. local pkt, error = net.recv{WORKER_PORT, filter=fromWorker}
  86. if pkt.msg == "flash-good" then
  87. return true
  88. else
  89. return nil, pkt.msg
  90. end
  91. end
  92. local function waitForAutosave(label)
  93. -- To detect this we're going to check the item stack every few seconds until the labels match
  94. local i = 0
  95. while transposer.getStackInSlot(sides.left, EEPROM_SLOT).label ~= label do
  96. print("Checking for autosave...")
  97. computer.beep(500)
  98. os.sleep(2.5)
  99. i = i + 1
  100. end
  101. print("Autosave detected! Took " .. tostring(2.5 * i) .. " seconds")
  102. computer.beep(1000)
  103. end
  104. local function respond(addr, code, error)
  105. print("SEND", addr, WEB_FLASH_PORT, code, error)
  106. net.send(addr, WEB_FLASH_PORT, code, error)
  107. computer.beep(200)
  108. end
  109. -- Waits to recv a message
  110. local function handleJob(job, worker)
  111. -- "/flash", file
  112. local client = job[3]
  113. local file = job[7]
  114. local title = job[8] or "Flashed EEPROM"
  115. if file == nil then respond(client, 400, "no file") return end
  116. -- 4k is the largest an eeprom can hold
  117. if #file > 4096 then
  118. respond(client, 400, "file too large")
  119. end
  120. if isFilled() then respond(client, 500, "inventory filled") return end
  121. -- Remove the OpenOS Bios and store it in the last slot of top chest
  122. local res, err = removeEEPROM(27)
  123. if res == nil then respond(client, 500, err) return end
  124. computer.beep(100)
  125. local res, err = loadNewEEPROM()
  126. if res == nil then respond(client, 500, err) return end
  127. computer.beep(100)
  128. local res, err = flashEEPROM(worker, file, title)
  129. if res == nil then respond(worker, 500, err) return end
  130. -- Now the NBT data of the eeprom will update on the next auto save
  131. waitForAutosave(title)
  132. local location, err = removeEEPROM()
  133. if location == nil then respond(client, 500, err) return end
  134. computer.beep(100)
  135. -- Load the old EERPOM
  136. transposer.transferItem(sides.top, sides.left, 1, 27, EEPROM_SLOT)
  137. computer.beep(100)
  138. respond(client, 200, location)
  139. computer.beep(1000)
  140. end
  141. local function startServer()
  142. print("I am " .. net.addr)
  143. local worker = meetWorker()
  144. local queue = Queue()
  145. local server = Server(WEB_FLASH_PORT)
  146. -- Queue requests as they come in
  147. server:handle("/flash", function(...) queue:push({...}) end)
  148. -- Soft interrupt
  149. local interrupted = false
  150. local interruptID = event.listen("interrupted", function() interrupted = true end)
  151. while not interrupted do
  152. job = queue:pop()
  153. if job ~= nil then
  154. handleJob(job, worker)
  155. end
  156. os.sleep(1)
  157. end
  158. -- Don't forget to close the server
  159. event.cancel(interruptID)
  160. server:close()
  161. end
  162. startServer()