Browse Source

Migrated GPS and EEPROM servers to use new server library

master
Chris Mahoney 1 year ago
parent
commit
962b1112c2
  1. 12
      README.md
  2. 185
      eeprom-server.lua
  3. 8
      eeprom-worker.lua
  4. 16
      eeproms/http_small.lua
  5. 64
      eeproms/lua_bios.lua
  6. 0
      eeproms/pixie_boot.lua
  7. 64
      gps-server.lua
  8. 44
      grab-run2.lua
  9. 37
      lib/http.lua
  10. 64
      lib/server.lua
  11. 105
      lib/socket.lua
  12. 8
      lib/webflashlib.lua
  13. 16
      webflash.lua

12
README.md

@ -1,3 +1,13 @@
# ocvn
OpenComputers Von Neumann Machine Programs
OpenComputers Von Neumann Machine Programs
## Port Allocation
| Port | Description |
| :---: | :--------------- |
| 21 | FTP |
| 30 | EEPROM Web Flash |
| 31 | EEPROM Worker |
| 53 | DNS |
| 67 | DHCP Server |
| 68 | DHCP Client |

185
eeprom-server.lua

@ -1,20 +1,24 @@
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 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
-- 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 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
@ -24,15 +28,13 @@ local function meetWorker(port)
end
-- Wait for a SYN
local pkt, err = net.recv{port, filter = syn}
local pkt, err = net.recv{WORKER_PORT, filter = syn}
-- ACK the worker
local s = Socket(pkt.raddr, port)
s:send("ACK")
print("Found worker " .. pkt.raddr)
net.send(pkt.raddr, WORKER_PORT, "ACK")
print("Found worker ", pkt.raddr)
return s
return pkt.raddr
end
-- Checks if the top chest is filled
@ -51,36 +53,32 @@ end
-- 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
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...")
print("LOADING")
-- Find largest inventory slot in the storage with an eeprom
local i = 1
@ -95,25 +93,27 @@ local function loadNewEEPROM()
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 " .. "...")
print("Send", worker, WORKER_PORT, "flash", label)
worker:send("flash", data, label)
net.send(worker, WORKER_PORT, "flash", data, label)
local function fromWorker(name, ...)
t = {...}
local pkt = worker:recieve(true)
for k, v in pairs(pkt) do print(k, v) end
print("Flash complete " .. pkt.msg)
return t[2] == worker
end
local pkt, error = net.recv{WORKER_PORT, filter=fromWorker}
if pkt.msg == "flash-good" then
return true
@ -122,92 +122,97 @@ local function flashEEPROM(worker, data, label)
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
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
-- Create a new socket
local client = Socket(pkt.raddr, port)
print("Autosave detected! Took " .. tostring(2.5 * i) .. " seconds")
computer.beep(1000)
end
-- "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
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
if isFilled() then client:send(500, "inventory filled") return 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"
-- 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)
if file == nil then respond(client, 400, "no file") return end
local res, err = loadNewEEPROM()
if res == nil then client:send(500, err) return end
computer.beep(100)
-- 4k is the largest an eeprom can hold
if #file > 4096 then
respond(client, 400, "file too large")
end
if pkt.data[3] == nil then
pkt.data[3] = "Flashed EEPROM"
end
if isFilled() then respond(client, 500, "inventory filled") return end
local res, err = flashEEPROM(worker, pkt.data[2], pkt.data[3])
if res == nil then client:send(500, err) 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)
-- 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
local res, err = loadNewEEPROM()
if res == nil then respond(client, 500, err) return end
computer.beep(100)
print("Autosave detected! Took " .. tostring(2.5 * i) .. " seconds")
computer.beep(1000)
local res, err = flashEEPROM(worker, file, title)
if res == nil then respond(worker, 500, err) return end
local location, err = removeEEPROM()
if location == nil then client:send(500, err) return end
computer.beep(100)
-- Now the NBT data of the eeprom will update on the next auto save
waitForAutosave(title)
-- Load the old EERPOM
transposer.transferItem(sides.top, sides.left, 1, 27, EEPROM_SLOT)
computer.beep(100)
local location, err = removeEEPROM()
if location == nil then respond(client, 500, err) return end
computer.beep(100)
client:send(200, location)
computer.beep(1000)
print("Success!")
else
client:send(404)
end
-- Load the old EERPOM
transposer.transferItem(sides.top, sides.left, 1, 27, EEPROM_SLOT)
computer.beep(100)
client:close()
respond(client, 200, location)
computer.beep(1000)
end
local function startServer(port)
local function startServer()
print("I am " .. net.addr)
local worker = meetWorker(port)
local interrupted = false
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
waitForJob(port, worker)
job = queue:pop()
if job ~= nil then
handleJob(job, worker)
end
os.sleep(1)
end
-- Don't forget to close sockets!
worker:close()
-- Don't forget to close the server
event.cancel(interruptID)
server:close()
end
startServer(10)
startServer()

8
eeprom-worker.lua

@ -5,9 +5,11 @@ local component = component or require("component")
local sides = sides or require("sides")
local os = os or require("os")
local WORKER_PORT = 31
local function meet_server(port)
while true do
print("broadcast 10 SYN")
print("broadcast SYN")
net.broadcast(port, "SYN")
computer.beep(200)
@ -18,7 +20,7 @@ local function meet_server(port)
return t[5] == "ACK"
end
print("recv 10 ack")
print("recv ACK")
local pkt, err = net.recv{port, filter = ack, timeout = 5}
if pkt ~= nil then
print("found server " .. pkt.raddr)
@ -73,4 +75,4 @@ local function start_client(port)
end
end
start_client(10)
start_client(WORKER_PORT)

16
eeproms/http_small.lua

@ -0,0 +1,16 @@
local event = event or require("event") local modem = require("component").modem
local http = {handlers = setmetatable({}, { __index = function() return function() end end }),
handle = function(endpoint, f) http.handlers[endpoint] = f end,
listen = function(port)
modem.open(port)
local eventID = event.listen("modem_message", function (...)
if {...}[4] ~= port then return end
http.handlers[{...}[6]](...)
end)
return eventID
end,
}

64
eeproms/lua_bios.lua

@ -0,0 +1,64 @@
local init
do
local component_invoke = component.invoke
local function boot_invoke(address, method, ...)
local result = table.pack(pcall(component_invoke, address, method, ...))
if not result[1] then
return nil, result[2]
else
return table.unpack(result, 2, result.n)
end
end
-- backwards compatibility, may remove later
local eeprom = component.list("eeprom")()
computer.getBootAddress = function()
return boot_invoke(eeprom, "getData")
end
computer.setBootAddress = function(address)
return boot_invoke(eeprom, "setData", address)
end
do
local screen = component.list("screen")()
local gpu = component.list("gpu")()
if gpu and screen then
boot_invoke(gpu, "bind", screen)
end
end
local function tryLoadFrom(address)
local handle, reason = boot_invoke(address, "open", "/init.lua")
if not handle then
return nil, reason
end
local buffer = ""
repeat
local data, reason = boot_invoke(address, "read", handle, math.huge)
if not data and reason then
return nil, reason
end
buffer = buffer .. (data or "")
until not data
boot_invoke(address, "close", handle)
return load(buffer, "=init")
end
local reason
if computer.getBootAddress() then
init, reason = tryLoadFrom(computer.getBootAddress())
end
if not init then
computer.setBootAddress()
for address in component.list("filesystem") do
init, reason = tryLoadFrom(address)
if init then
computer.setBootAddress(address)
break
end
end
end
if not init then
error("no bootable medium found" .. (reason and (": " .. tostring(reason)) or ""), 0)
end
computer.beep(1000, 0.2)
end
init()

0
eeproms/pixie_boot.lua

64
gps-server.lua

@ -1,16 +1,48 @@
local x = 1
local y = 1
local z = 1
local modem = component.proxy(component.list("modem")())
modem.open(20)
-- Just listen for modem messages and respond with it's location
while true do
local type, _, from, _, _, _ = computer.pullSignal("modem_message")
if type == "modem_message" then
modem.send(from, 20, x, y, z)
computer.beep(100)
end
end
local modem = require("component").modem
local Server = Server or require("server")
local computer = require("computer")
local event = require("event")
local os = require("os")
local gps = {}
gps.port = 20
gps.server = Server(gps.port, "gps")
function gps.startServer(x, y, z)
gps.x = x
gps.y = y
gps.z = z
gps.server:handle("/ping", function(...)
local tmp = {...}
computer.beep(500)
print(tmp[3])
modem.send(tmp[3], gps.port, "/location", tmp[7], x, y, z)
end)
end
function gps.closeServer()
gps.server:close()
end
function gps.getLocation()
gps.locator:handle("/location", function(...)
local tmp = {...}
end)
end
gps.startServer()
-- Soft interrupt
local interrupted = false
local interruptID = event.listen("interrupted", function() interrupted = true end)
while not interrupted do
os.sleep(1)
end
-- Don't forget to close the server
event.cancel(interruptID)
gps.closeServer()

44
grab-run2.lua

@ -0,0 +1,44 @@
local shell = require("shell")
local internet = require("internet")
local fs = require("filesystem")
local ll = require("liblua")
local args = {...}
-- Error checking
if args[1] == nil then
print("URL must exist")
return
end
args[1] = "http://bacon.cosi.clarkson.edu:60005/"..args[1]
-- Get local filename
local fileName = ""
if args[2] == nil then
local t = ll.split(args[1], "/")
fileName = t[#t]
else
fileName = args[2]
end
local newArgs = ll.slice(args, 3, #args-2)
-- Sandbox so we don't write to the screen
sandbox_env = {
assert = assert,
require = require,
pairs = pairs,
pcall = pcall,
tostring = tostring,
string = string,
io = {write = function(...) end, read = io.read, open = io.open, stderr = io.stderr}
}
pcall(fs.remove, fileName)
shell.execute("wget -f "..args[1].." "..fileName, sandbox_env)
-- Run downloaded file
local c = fileName
for _, i in ipairs(newArgs) do c = c.." "..i end
shell.execute(c)
-- wget -f http://mc.bashed.rocks:13699/grab-run.lua

37
lib/http.lua

@ -1,37 +0,0 @@
local computer = computer or require("computer")
local event = event or require("event")
local modem = component.proxy(component.list("modem")())
local function unknown()
-- do nothing
end
local http = {}
local http.handlers = setmetatable({}, { __index = function() return unknown end })
local function http.example()
http.handlers["/example"] = function (...)
-- "modem_message", local addr, remote addr, port, distance, "/example"
tmp = {...}
modem.send(tmp[3], tmp[4], "hello world")
end
end
local function http.listen(port)
modem.open(port)
eventID = event.listen("modem_message", function (_, ...)
-- event type, local addr, remote addr, port, distance, msg
tmp = {...}
-- Filter out messages coming from the wrong port
if tmp[3] ~= port then return end
-- Forward message to the correct handler
http.handlers[tmp[5]](tmp)
end)
return eventID
end

64
lib/server.lua

@ -0,0 +1,64 @@
local event = event or require("event")
local component = comonent or require("component")
local modem = component.modem
local Server = {}
Server.__index = Server
setmetatable(Server, {
__call = function (cls, ...) return cls.new(...) end,
})
-- Creates a new server object listening on a port
-- Optionally include a "marker" string to find event listener
function Server.new(port, marker)
local self = setmetatable({}, Server)
self.port = port
self.marker = marker
self.handlers = setmetatable({}, { __index = function() return function() end end })
-- Remove any handlers with this marker
if marker ~= nil then
for i, _ in pairs(event.handlers) do
if marker == event.handlers[i].marker then
event.cancel(i)
end
end
end
self.eventID = event.listen("modem_message", function (...)
-- event type, local addr, remote addr, port, distance, msg
local tmp = {...}
-- Filter out messages coming from the wrong port
if tmp[4] ~= self.port then return end
-- Forward message to the correct handler
self.handlers[tmp[6]](...)
end)
modem.open(self.port)
return self
end
-- Adds a new endpoint event handler
function Server:handle(endpoint, f)
self.handlers[endpoint] = f
end
function Server:close()
event.cancel(self.eventID)
modem.close(self.port)
end
--[[
function Server.example()
Server.handlers["/example"] = function (pkt)
modem.send(pkt.raddr, pkt.port, "hello world")
end
end
]]
return Server

105
lib/socket.lua

@ -1,105 +0,0 @@
local computer = computer or require("computer")
local event = event or require("event")
local Queue = require("queue")
local net = require("net")
-- Sockets allow for simplier 2 way communicatation
-- An event listener is created to recieve incoming messages and automatically queue them
-- You should probably remember to close the socket when your done
-- You don't _nessacrily_ have to create a socket on both sides
local Socket = {}
Socket.__index = Socket
setmetatable(Socket, {
__call = function (cls, ...)
return cls.new(...)
end,
})
function Socket.new(raddr, port)
local self = setmetatable({}, Socket)
self.raddr = net.checkAddr(raddr)
self.port = port
self._queue = Queue()
-- name, local addr, remote addr, port, distance, msg
listener = function(...)
tmp = {...}
for k, v in pairs(tmp) do print(k, v) end
-- Check if port and raddr match
if tmp[3] ~= self.raddr or tmp[4] ~= self.port then
print("denied")
return
end
print("accepted")
pkt = {}
pkt.laddr, pkt.raddr, pkt.port, pkt.distance, pkt.msg = tmp[2], tmp[3], tmp[4], tmp[5], tmp[6]
self._queue:push(pkt)
end
net.open(port)
-- Create modem_message listener
self._listener = event.listen("modem_message", listener)
-- Close socket on interrupt
self._interrupter = event.listen("interrupted", function() self:close() end)
return self
end
function Socket:close()
net.close(self.port)
event.cancel(self._listener)
event.cancel(self._interrupter)
-- Mark for garbage collection. Maybe this isn't needed?
self._queue = nil
self = nil
end
-- Send along msg, data
function Socket:send(msg, ...)
t = {...}
if t ~= nil then
print("Sending " .. self.raddr .. " " .. tostring(self.port) .. " " .. msg .. " ")
else
print("Sending " .. self.raddr .. " " .. tostring(self.port) .. " " .. msg .. " ")
end
net.send(self.raddr, self.port, msg, ...)
end
-- Pop off the queue
-- blocking true if you want to block main execution until we recieve a message
-- if blocking is true you can also optionally add a timeout
function Socket:recieve(blocking, timeout)
if blocking == nil then blocking = false end
-- Get the result from the queue
local result = self._queue:pop()
-- If there is not a result and we're blocking then wait until we recieve one
if result == nil and blocking then
print("blocking")
if timeout == nil then
pkt, err = net.recv{self.port, self.raddr}
else
pkt, err = net.recv{self.port, self.raddr, timeout=timeout}
end
result = pkt
print("Some reason we got : " .. pkt.laddr .. " " .. pkt.raddr)
end
return result
end
return Socket

8
lib/webflashlib.lua

@ -1,14 +1,16 @@
local computer = computer or require("computer")
local net = net or require("net")
local WEB_FLASH_PORT = 30
local function webflash(bytes, label)
if label == nil then
net.broadcast(10, "webflash", bytes)
net.broadcast(WEB_FLASH_PORT, "/flash", bytes)
else
net.broadcast(10, "webflash", bytes, label)
net.broadcast(WEB_FLASH_PORT, "/flash", bytes, label)
end
local pkt, err = net.recv{10}
local pkt, err = net.recv{WEB_FLASH_PORT}
return pkt.data[1], tostring(pkt.data[2])
end

16
webflash.lua

@ -2,7 +2,21 @@
-- it will ask the local eeprom machine to flash it to an eeprom
local computer = computer or require("computer")
local webflash = require("webflashlib")
local net = net or require("net")
local WEB_PORT = 30
local function webflash(bytes, label)
if label == nil then
net.broadcast(WEB_PORT, "/flash", bytes)
else
net.broadcast(WEB_PORT, "/flash", bytes, label)
end
local pkt, err = net.recv{WEB_PORT}
return pkt.data[1], tostring(pkt.data[2])
end
local args = {...}

Loading…
Cancel
Save