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.

218 lines
5.4 KiB

local component = component or require("component")
local computer = computer or require("computer")
local sides = sides or require("sides")
local event = event or require("event")
local os = os or require("os")
local net = net or require("net")
local Server = Server or require("server")
local Queue = Queue or require("queue")
-- location of eeprom in computer case
local EEPROM_SLOT = 10
local transposer = component.transposer
local WEB_FLASH_PORT = 30
local WORKER_PORT = 31
-- Waits for a SYN from a worker and responds with an ACK
-- Returns the workers address
local function meetWorker()
print("Waiting for worker")
local function syn(name, ...)
-- local addr, remote addr, port, distance, msg
local t = {...}
return t[5] == "SYN"
end
-- Wait for a SYN
local pkt, err = net.recv{WORKER_PORT, filter = syn}
-- ACK the worker
net.send(pkt.raddr, WORKER_PORT, "ACK")
print("Found worker ", pkt.raddr)
return pkt.raddr
end
-- Checks if the top chest is filled
local function isFilled()
local i = 1
for k in transposer.getAllStacks(sides.top) do
if k.size == nil then break end
i = i + 1
end
return i >= 27
end
-- Moves the EEPROM from the worker into the top chest
-- Optionally include the slot
-- Returns the slot the eeprom was moved to
local function removeEEPROM(sink_slot)
print("REMOVING - ", sink_slot)
if sink_slot == nil then
local i = 1
for k in transposer.getAllStacks(sides.top) do
if k.size == nil then break end
i = i + 1
end
if i == 27 then
return nil, "Inventory filled"
end
sink_slot = i
end
-- Remove the OpenOS Bios and store it in the top chest
transposer.transferItem(sides.left, sides.top, 1, EEPROM_SLOT, sink_slot)
return sink_slot
end
-- Moves a blank EEPROM from storage into the worker
local function loadNewEEPROM()
print("LOADING")
-- Find largest inventory slot in the storage with an eeprom
local i = 1
local last = nil
for k in transposer.getAllStacks(sides.right) do
if k.size ~= nil then
last = i
end
i = i + 1
end
if last == nil then
return nil, "No EEPROMS"
end
-- Move the new EEPROM into computer
transposer.transferItem(sides.right, sides.left, 1, last, EEPROM_SLOT)
return true
end
local function flashEEPROM(worker, data, label)
print("Send", worker, WORKER_PORT, "flash", label)
net.send(worker, WORKER_PORT, "flash", data, label)
local function fromWorker(name, ...)
t = {...}
return t[2] == worker
end
local pkt, error = net.recv{WORKER_PORT, filter=fromWorker}
if pkt.msg == "flash-good" then
return true
else
return nil, pkt.msg
end
end
local function waitForAutosave(label)
-- To detect this we're going to check the item stack every few seconds until the labels match
local i = 0
while transposer.getStackInSlot(sides.left, EEPROM_SLOT).label ~= label do
print("Checking for autosave...")
computer.beep(500)
os.sleep(2.5)
i = i + 1
end
print("Autosave detected! Took " .. tostring(2.5 * i) .. " seconds")
computer.beep(1000)
end
local function respond(addr, code, error)
print("SEND", addr, WEB_FLASH_PORT, code, error)
net.send(addr, WEB_FLASH_PORT, code, error)
computer.beep(200)
end
-- Waits to recv a message
local function handleJob(job, worker)
-- "/flash", file
local client = job[3]
local file = job[7]
local title = job[8] or "Flashed EEPROM"
if file == nil then respond(client, 400, "no file") return end
-- 4k is the largest an eeprom can hold
if #file > 4096 then
respond(client, 400, "file too large")
end
if isFilled() then respond(client, 500, "inventory filled") return end
-- Remove the OpenOS Bios and store it in the last slot of top chest
local res, err = removeEEPROM(27)
if res == nil then respond(client, 500, err) return end
computer.beep(100)
local res, err = loadNewEEPROM()
if res == nil then respond(client, 500, err) return end
computer.beep(100)
local res, err = flashEEPROM(worker, file, title)
if res == nil then respond(worker, 500, err) return end
-- Now the NBT data of the eeprom will update on the next auto save
waitForAutosave(title)
local location, err = removeEEPROM()
if location == nil then respond(client, 500, err) return end
computer.beep(100)
-- Load the old EERPOM
transposer.transferItem(sides.top, sides.left, 1, 27, EEPROM_SLOT)
computer.beep(100)
respond(client, 200, location)
computer.beep(1000)
end
local function startServer()
print("I am " .. net.addr)
local worker = meetWorker()
local queue = Queue()
local server = Server(WEB_FLASH_PORT)
-- Queue requests as they come in
server:handle("/flash", function(...) queue:push({...}) end)
-- Soft interrupt
local interrupted = false
local interruptID = event.listen("interrupted", function() interrupted = true end)
while not interrupted do
job = queue:pop()
if job ~= nil then
handleJob(job, worker)
end
os.sleep(1)
end
-- Don't forget to close the server
event.cancel(interruptID)
server:close()
end
startServer()