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.

213 lines
5.5 KiB

local Socket = Socket or require("socket")
local net = net or require("net")
local component = component or require("component")
local computer = computer or require("computer")
local event = event or require("event")
local sides = sides or require("sides")
local os = os or require("os")
-- location of eeprom in computer case
local EEPROM_SLOT = 10
local transposer = component.transposer
-- Waits for a SYN from the worker and responds with an ACK
-- Returns a socket connected to the worker
local function meetWorker(port)
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{port, filter = syn}
-- ACK the worker
local s = Socket(pkt.raddr, port)
s:send("ACK")
print("Found worker " .. pkt.raddr)
return s
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)
if sink_slot == nil then
local i = 1
for k in transposer.getAllStacks(sides.top) do
for m, n in pairs(k) do print(m, n) end
if k.size == nil then break end
i = i + 1
end
if i == 27 then
print("Inventory filled")
return nil, "Inventory filled"
end
sink_slot = i
end
print("Moving EEPROM to slot " .. tostring(sink_slot))
-- Remove the OpenOS Bios and store it in the top chest
transposer.transferItem(sides.left, sides.top, 1, EEPROM_SLOT, sink_slot)
print("Move complete")
return sink_slot
end
-- Moves a blank EEPROM from storage into the worker
local function loadNewEEPROM()
print("Loading new EEPROM...")
-- 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
print("No blank EEPROMS")
return nil, "No EEPROMS"
end
-- Move the new EEPROM into computer
print("Loading complete")
transposer.transferItem(sides.right, sides.left, 1, last, EEPROM_SLOT)
return true
end
local function flashEEPROM(worker, data, label)
print("Asking worker to flash " .. "...")
worker:send("flash", data, label)
local pkt = worker:recieve(true)
for k, v in pairs(pkt) do print(k, v) end
print("Flash complete " .. pkt.msg)
if pkt.msg == "flash-good" then
return true
else
return nil, pkt.msg
end
end
-- Waits to recv a message
local function waitForJob(port, worker)
local function ignore(_, _, raddr) return raddr ~= net.addr and raddr ~= worker.raddr end
local pkt, err = net.recv{port, filter=ignore}
if pkt == nil and err ~= "interrupted" then
return pkt
end
-- Create a new socket
local client = Socket(pkt.raddr, port)
-- "eeprom-flash file-contents label"
if pkt.msg == "webflash" then
-- 4k is the largest an eeprom can hold
if #pkt.data[2] > 4096 then
client:send(400, "file too large")
return pkt
end
if isFilled() then client:send(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 client:send(500, err) return end
computer.beep(100)
local res, err = loadNewEEPROM()
if res == nil then client:send(500, err) return end
computer.beep(100)
if pkt.data[3] == nil then
pkt.data[3] = "Flashed EEPROM"
end
local res, err = flashEEPROM(worker, pkt.data[2], pkt.data[3])
if res == nil then client:send(500, err) return end
-- Now the NBT data of the eeprom will update on the next auto save
-- 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 ~= pkt.data[3] 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)
local location, err = removeEEPROM()
if location == nil then client:send(500, err) return end
computer.beep(100)
-- Load the old EERPOM
transposer.transferItem(sides.top, sides.left, 1, 27, EEPROM_SLOT)
computer.beep(100)
client:send(200, location)
computer.beep(1000)
print("Success!")
else
client:send(404)
end
client:close()
end
local function startServer(port)
print("I am " .. net.addr)
local worker = meetWorker(port)
local interrupted = false
-- Soft interrupt
local interruptID = event.listen("interrupted", function() interrupted = true end)
while not interrupted do
waitForJob(port, worker)
end
-- Don't forget to close sockets!
worker:close()
event.cancel(interruptID)
end
startServer(10)