@@ -0,0 +1,7 @@ | |||
#!/usr/bin/env bash | |||
mkdir build | |||
cd module | |||
cat sched.lua vt100.lua fs.lua loadfile.lua vt-task.lua io.lua microtel-3.lua init.lua > ../build/psychos.lua | |||
cd .. | |||
echo '_OSVERSION="PsychOS 2.0a0"' >> build/* | |||
echo sched\(\) >> build/* |
@@ -0,0 +1,432 @@ | |||
tTasks,nPid,nTimeout,cPid = {},1,1,0 | |||
function os.spawn(f,n) | |||
tTasks[nPid] = {["c"]=coroutine.create(f),["n"]=n,["p"]=nPid} | |||
for k,v in pairs(tTasks[cPid] or {}) do | |||
tTasks[nPid][k] = tTasks[nPid][k] or v | |||
end | |||
nPid = nPid + 1 | |||
return nPid - 1 | |||
end | |||
function sched() | |||
while #tTasks > 0 do | |||
local tEv = {computer.pullSignal(nTimeout)} | |||
for k,v in pairs(tTasks) do | |||
if coroutine.status(v.c) ~= "dead" then | |||
cPid = k | |||
coroutine.resume(v.c,table.unpack(tEv)) | |||
else | |||
tTasks[k] = nil | |||
end | |||
end | |||
end | |||
end | |||
function vt100emu(gpu) | |||
local mx, my = gpu.maxResolution() | |||
local cx, cy = 1, 1 | |||
local pc = " " | |||
local lc = "" | |||
local mode = "n" | |||
local lw = true | |||
local sx, sy = 1,1 | |||
local cs = "" | |||
-- setup | |||
gpu.setResolution(mx,my) | |||
gpu.fill(1,1,mx,my," ") | |||
function termwrite(s) | |||
s=s:gsub("\8","\27[D") | |||
pc = gpu.get(cx,cy) | |||
gpu.setForeground(0xFFFFFF) | |||
gpu.setBackground(0) | |||
gpu.set(cx,cy,pc) | |||
for i = 1, s:len() do | |||
local cc = s:sub(i,i) | |||
if mode == "n" then | |||
if cc == "\n" then -- line feed | |||
cx, cy = 1, cy+1 | |||
elseif cc == "\r" then -- cursor home | |||
cx = 1 | |||
elseif cc == "\27" then -- escape | |||
mode = "e" | |||
elseif string.byte(cc) > 31 and string.byte(cc) < 127 then -- printable, I guess | |||
gpu.set(cx, cy, cc) | |||
cx = cx + 1 | |||
end | |||
elseif mode == "e" then | |||
if cc == "[" then | |||
mode = "v" | |||
cs = "" | |||
elseif cc == "D" then -- scroll down | |||
gpu.copy(1,2,mx,my-1,0,-1) | |||
gpu.fill(1,my,mx,1," ") | |||
cy=cy+1 | |||
mode = "n" | |||
elseif cc == "M" then -- scroll up | |||
gpu.copy(1,1,mx,my-1,0,1) | |||
gpu.fill(1,1,mx,1," ") | |||
mode = "n" | |||
end | |||
elseif mode == "v" then -- save cursor | |||
local n = cs:sub(cs:len(),cs:len()) | |||
if n == "" then n = "\1" end | |||
if cc == "s" then | |||
sx, sy = cx, cy | |||
mode = "n" | |||
elseif cc == "u" then -- restore cursor | |||
cx, cy = sx, sy | |||
mode = "n" | |||
elseif cc == "H" then -- cursor home or to | |||
local tx, ty = cs:match("(.);(.)") | |||
tx, ty = tx or "\1", ty or "\1" | |||
cx, cy = string.byte(tx), string.byte(ty) | |||
mode = "n" | |||
elseif cc == "A" then -- cursor up | |||
cy = cy - string.byte(n) | |||
mode = "n" | |||
elseif cc == "B" then -- cursor down | |||
cy = cy + string.byte(n) | |||
mode = "n" | |||
elseif cc == "C" then -- cursor right | |||
cx = cx + string.byte(n) | |||
mode = "n" | |||
elseif cc == "D" then -- cursor left | |||
cx = cx - string.byte(n) | |||
mode = "n" | |||
elseif cc == "h" and lc == "7" then -- enable line wrap | |||
lw = true | |||
elseif cc == "l" and lc == "7" then -- disable line wrap | |||
lw = false | |||
end | |||
cs = cs .. cc | |||
end | |||
if cx > mx and lw then | |||
cx, cy = 1, cy+1 | |||
end | |||
if cy > my then | |||
gpu.copy(1,2,mx,my-1,0,-1) | |||
gpu.fill(1,my,mx,1," ") | |||
cy=my | |||
end | |||
if cy < 1 then cy = 1 end | |||
if cx < 1 then cx = 1 end | |||
lc = cc | |||
end | |||
pc = gpu.get(cx,cy) | |||
gpu.setForeground(0) | |||
gpu.setBackground(0xFFFFFF) | |||
gpu.set(cx,cy,pc) | |||
gpu.setForeground(0xFFFFFF) | |||
gpu.setBackground(0) | |||
end | |||
return termwrite | |||
end | |||
fs = {} | |||
fs.mounts = {} | |||
-- basics | |||
function fs.segments(path) | |||
local segments = {} | |||
for segment in path:gmatch("[^/]+") do | |||
segments[#segments+1] = segment | |||
end | |||
return segments | |||
end | |||
function fs.resolve(path) | |||
local segments, rpath = fs.segments(path), "/" | |||
for i = 2, #segments do | |||
rpath = rpath .. segments[i] .. "/" | |||
end | |||
rpath = rpath:match("(.+)/") or rpath | |||
return segments[1] or "root",rpath | |||
end | |||
-- generate some simple functions | |||
for k,v in pairs({"makeDirectory","exists","isDirectory","list","lastModified","remove","size","spaceUsed","isReadOnly","getLabel"}) do | |||
fs[v] = function(path) | |||
local fsi,path = fs.resolve(path) | |||
return fs.mounts[fsi][v](path) | |||
end | |||
end | |||
local function fread(self,length) | |||
if length == "*a" then | |||
length = math.huge | |||
end | |||
local rstr, lstr = "", "" | |||
repeat | |||
lstr = fs.mounts[self.fs].read(self.fid,math.min(2^16,length-rstr:len())) or "" | |||
rstr = rstr .. lstr | |||
until rstr:len() == length or lstr == "" | |||
return rstr | |||
end | |||
local function fwrite(self,data) | |||
fs.mounts[self.fs].write(self.fid,data) | |||
end | |||
local function fclose(self) | |||
fs.mounts[self.fs].close(self.fid) | |||
end | |||
function fs.open(path,mode) | |||
mode = mode or "rb" | |||
local fsi,path = fs.resolve(path) | |||
if not fs.mounts[fsi] then return false end | |||
local fid = fs.mounts[fsi].open(path,mode) | |||
if fid then | |||
local fobj = {["fs"]=fsi,["fid"]=fid,["close"]=fclose} | |||
if mode:sub(1,1) == "r" then | |||
fobj.read = fread | |||
else | |||
fobj.write = fwrite | |||
end | |||
return fobj | |||
end | |||
return false | |||
end | |||
function fs.copy(from,to) | |||
local of = fs.open(from,"rb") | |||
local df = fs.open(to,"wb") | |||
if not of or not df then | |||
return false | |||
end | |||
df:write(of:read("*a")) | |||
df:close() | |||
of:close() | |||
end | |||
function fs.rename(from,to) | |||
local ofsi, opath = fs.resolve(from) | |||
local dfsi, dpath = fs.resolve(to) | |||
if ofsi == dfsi then | |||
fs.mounts[ofsi].rename(opath,dpath) | |||
return true | |||
end | |||
fs.copy(from,to) | |||
fs.remove(from) | |||
return true | |||
end | |||
fs.mounts.temp = component.proxy(computer.tmpAddress()) | |||
if computer.getBootAddress then | |||
fs.mounts.boot = component.proxy(computer.getBootAddress()) | |||
end | |||
for addr, _ in component.list("filesystem") do | |||
fs.mounts[addr:sub(1,3)] = component.proxy(addr) | |||
end | |||
local function rf() | |||
return false | |||
end | |||
fs.mounts.root = {} | |||
for k,v in pairs(fs.mounts.temp) do | |||
fs.mounts.root[k] = rf | |||
end | |||
function fs.mounts.root.list() | |||
local t = {} | |||
for k,v in pairs(fs.mounts) do | |||
t[#t+1] = k | |||
end | |||
t.n = #t | |||
return t | |||
end | |||
function fs.mounts.root.isReadOnly() | |||
return true | |||
end | |||
function loadfile(p) | |||
local f = fs.open(p,"rb") | |||
local c = f:read("*a") | |||
f:close() | |||
return load(c,p,"t") | |||
end | |||
function runfile(p,...) | |||
loadfile(p)(...) | |||
end | |||
function spawnfile(p,n) | |||
os.spawn(loadfile(p),n) | |||
end | |||
function vtemu(gpua,scra) | |||
local gpu,scr = component.proxy(gpua),component.proxy(scra) | |||
gpu.bind(scra) | |||
local write = vt100emu(gpu) | |||
local kba = {} | |||
for k,v in ipairs(scr.getKeyboards()) do | |||
kba[v]=true | |||
end | |||
local buf = "" | |||
os.spawn(function() | |||
while true do | |||
local ty,ka,ch = coroutine.yield() | |||
if ty == "key_down" and kba[ka] then | |||
if ch == 13 then ch = 10 end | |||
if ch == 8 and buf:len() > 0 then | |||
write("\8 \8") | |||
buf = buf:sub(1,-2) | |||
elseif ch > 0 then | |||
write(string.char(ch)) | |||
buf = buf .. string.char(ch) | |||
end | |||
end | |||
end | |||
end,"keyboard daemon for "..gpua:sub(1,8)..":"..scra:sub(1,8)) | |||
local function read(n) | |||
n = n or "\n" | |||
local rdata = "" | |||
if type(n) == "number" then | |||
rdata = buf:sub(1,n) | |||
return rdata | |||
else | |||
if n == "*a" then | |||
rdata = buf | |||
buf = "" | |||
return rdata | |||
end | |||
local pr,po = buf:match("(.-)"..n.."(.*)") | |||
buf = po or buf | |||
return pr | |||
end | |||
end | |||
return read,write | |||
end | |||
_G.fd,_G.io = {},{} | |||
do | |||
function io.write(d) | |||
fd[tTasks[cPid].t or 1].w(d) | |||
end | |||
function io.read(d,b) | |||
local r = "" | |||
repeat | |||
r=fd[tTasks[cPid].t or 1].r(d) | |||
coroutine.yield() | |||
until r or b | |||
return r | |||
end | |||
function print(...) | |||
for k,v in pairs({...}) do | |||
io.write(tostring(v).."\n") | |||
end | |||
end | |||
local ts = {} | |||
for a,_ in component.list("screen") do | |||
ts[#ts+1] = a | |||
end | |||
for a,_ in component.list("gpu") do | |||
local r,w = vtemu(a,table.remove(ts,1)) | |||
fd[#fd+1] = {["r"]=r,["w"]=w,["t"]="t"} | |||
end | |||
end | |||
_G.net={} | |||
do | |||
local modems,packetQueue,packetCache,routeCache,C,Y = {},{},{},{},COMPUTER,UNPACK | |||
net.port,net.hostname,net.route,net.hook,U=4096,computer.address():sub(1,8),true,{},UPTIME | |||
for a in component.list("modem") do | |||
modems[a] = component.proxy(a) | |||
modems[a].open(net.port) | |||
end | |||
local function genPacketID() | |||
local packetID = "" | |||
for i = 1, 16 do | |||
packetID = packetID .. string.char(math.random(32,126)) | |||
end | |||
return packetID | |||
end | |||
local function rawSendPacket(packetID,packetType,to,from,vport,data) | |||
if routeCache[to] then | |||
modems[routeCache[to][1]].send(routeCache[to][2],net.port,packetID,packetType,to,from,vport,data) | |||
else | |||
for k,v in pairs(modems) do | |||
v.broadcast(net.port,packetID,packetType,to,from,vport,data) | |||
end | |||
end | |||
end | |||
local function sendPacket(packetID,packetType,to,vport,data) | |||
packetCache[packetID] = computer.uptime() | |||
rawSendPacket(packetID,packetType,to,net.hostname,vport,data) | |||
end | |||
function net.send(to,vport,data,packetType,packetID) | |||
packetType,packetID = packetType or 1, packetID or genPacketID() | |||
packetQueue[packetID] = {packetType,to,vport,data,0} | |||
sendPacket(packetID,packetType,to,vport,data) | |||
end | |||
local function checkCache(packetID) | |||
for k,v in pairs(packetCache) do | |||
if k == packetID then | |||
return false | |||
end | |||
end | |||
return true | |||
end | |||
os.spawn(function() | |||
while true do | |||
local eventTab = {coroutine.yield()} | |||
if eventTab[1] == "modem_message" and (eventTab[4] == net.port or eventTab[4] == 0) and checkCache(eventTab[6]) then | |||
for k,v in pairs(packetCache) do | |||
if computer.uptime() > v+30 then | |||
packetCache[k] = nil | |||
end | |||
end | |||
for k,v in pairs(routeCache) do | |||
if computer.uptime() > v[3]+30 then | |||
routeCache[k] = nil | |||
end | |||
end | |||
routeCache[eventTab[9]] = {eventTab[2],eventTab[3],computer.uptime()} | |||
if eventTab[8] == net.hostname then | |||
if eventTab[7] ~= 2 then | |||
computer.pushSignal("net_msg",eventTab[9],eventTab[10],eventTab[11]) | |||
if eventTab[7] == 1 then | |||
sendPacket(genPacketID(),2,eventTab[9],eventTab[10],eventTab[6]) | |||
end | |||
else | |||
packetQueue[eventTab[11]] = nil | |||
end | |||
elseif net.route and checkCache(eventTab[6]) then | |||
rawSendPacket(eventTab[6],eventTab[7],eventTab[8],eventTab[9],eventTab[10],eventTab[11]) | |||
end | |||
packetCache[eventTab[6]] = computer.uptime() | |||
end | |||
for k,v in pairs(packetQueue) do | |||
if computer.uptime() > v[5] then | |||
sendPacket(k,table.unpack(v)) | |||
v[5]=computer.uptime()+30 | |||
end | |||
end | |||
end | |||
end,"minitel.3") | |||
end | |||
os.spawn(function() print(pcall(function() | |||
print(_OSVERSION,tostring(computer.totalMemory()/1024).."K memory") | |||
local f = fs.open("/boot/init.txt","rb") | |||
local fc = f:read("*a") | |||
f:close() | |||
for line in fc:gmatch("[^\n]+") do | |||
print(line) | |||
end | |||
for k,v in pairs(fd) do | |||
if v.t == "t" then | |||
tTasks[cPid].t = k | |||
print("Spawning a shell for terminal #"..tostring(k)) | |||
spawnfile("/boot/exec/shell.lua","shell #"..tostring(k)) | |||
end | |||
end | |||
end)) end,"init") | |||
_OSVERSION="PsychOS 2.0a0" | |||
sched() |
@@ -0,0 +1,2 @@ | |||
print("Total Used Free") | |||
print(string.format("%4dK %4dK %4dK",computer.totalMemory()/1024,math.floor((computer.totalMemory()-computer.freeMemory())/1024),math.floor(computer.freeMemory()/1024))) |
@@ -0,0 +1,4 @@ | |||
print("PID# VTY# Name") | |||
for k,v in pairs(tTasks) do | |||
print(string.format("%4d %4d %s",k,v.t or 1,v.n)) | |||
end |
@@ -0,0 +1,9 @@ | |||
local shenv = {} | |||
setmetatable(shenv,{__index=function(_,k) if _G[k] then return _G[k] elseif fs.exists("/boot/exec/"..k..".lua") then return loadfile("/boot/exec/"..k..".lua") end end}) | |||
while true do | |||
io.write(_VERSION.."> ") | |||
tResult = {pcall(load(io.read(),"shell","t",shenv))} | |||
for k,v in pairs(tResult) do | |||
print(v) | |||
end | |||
end |
@@ -0,0 +1,8 @@ | |||
#!/bin/bash | |||
for f in service/*; do | |||
nf=$(echo $f | cut -d '/' -f 2) | |||
echo $nf | |||
echo os.spawn\(function\(\) >mod-service/$nf | |||
cat $f >> mod-service/$nf | |||
echo end,\"$nf\"\) >> mod-service/$nf | |||
done |
@@ -0,0 +1,88 @@ | |||
os.spawn(function() | |||
_G.net={} | |||
do | |||
local modems,packetQueue,packetCache,routeCache,C,Y = {},{},{},{},COMPUTER,UNPACK | |||
net.port,net.hostname,net.route,net.hook,U=4096,computer.address():sub(1,8),true,{},UPTIME | |||
for a in component.list("modem") do | |||
modems[a] = component.proxy(a) | |||
modems[a].open(net.port) | |||
end | |||
local function genPacketID() | |||
local packetID = "" | |||
for i = 1, 16 do | |||
packetID = packetID .. string.char(math.random(32,126)) | |||
end | |||
return packetID | |||
end | |||
local function rawSendPacket(packetID,packetType,to,from,vport,data) | |||
if routeCache[to] then | |||
modems[routeCache[to][1]].send(routeCache[to][2],net.port,packetID,packetType,to,from,vport,data) | |||
else | |||
for k,v in pairs(modems) do | |||
v.broadcast(net.port,packetID,packetType,to,from,vport,data) | |||
end | |||
end | |||
end | |||
local function sendPacket(packetID,packetType,to,vport,data) | |||
packetCache[packetID] = computer.uptime() | |||
rawSendPacket(packetID,packetType,to,net.hostname,vport,data) | |||
end | |||
function net.send(to,vport,data,packetType,packetID) | |||
packetType,packetID = packetType or 1, packetID or genPacketID() | |||
packetQueue[packetID] = {packetType,to,vport,data,0} | |||
sendPacket(packetID,packetType,to,vport,data) | |||
end | |||
local function checkCache(packetID) | |||
for k,v in pairs(packetCache) do | |||
if k == packetID then | |||
return false | |||
end | |||
end | |||
return true | |||
end | |||
while true do | |||
local eventTab = {coroutine.yield()} | |||
if eventTab[1] == "modem_message" and (eventTab[4] == net.port or eventTab[4] == 0) and checkCache(eventTab[6]) then | |||
for k,v in pairs(packetCache) do | |||
if computer.uptime() > v+30 then | |||
packetCache[k] = nil | |||
end | |||
end | |||
for k,v in pairs(routeCache) do | |||
if computer.uptime() > v[3]+30 then | |||
routeCache[k] = nil | |||
end | |||
end | |||
routeCache[eventTab[9]] = {eventTab[2],eventTab[3],computer.uptime()} | |||
if eventTab[8] == net.hostname then | |||
if eventTab[7] ~= 2 then | |||
computer.pushSignal("net_msg",eventTab[9],eventTab[10],eventTab[11]) | |||
if eventTab[7] == 1 then | |||
sendPacket(genPacketID(),2,eventTab[9],eventTab[10],eventTab[6]) | |||
end | |||
else | |||
packetQueue[eventTab[11]] = nil | |||
end | |||
elseif net.route and checkCache(eventTab[6]) then | |||
rawSendPacket(eventTab[6],eventTab[7],eventTab[8],eventTab[9],eventTab[10],eventTab[11]) | |||
end | |||
packetCache[eventTab[6]] = computer.uptime() | |||
end | |||
for k,v in pairs(packetQueue) do | |||
if computer.uptime() > v[5] then | |||
sendPacket(k,table.unpack(v)) | |||
v[5]=computer.uptime()+30 | |||
end | |||
end | |||
end | |||
end | |||
end,"microtel-3.lua") |
@@ -0,0 +1,114 @@ | |||
fs = {} | |||
fs.mounts = {} | |||
-- basics | |||
function fs.segments(path) | |||
local segments = {} | |||
for segment in path:gmatch("[^/]+") do | |||
segments[#segments+1] = segment | |||
end | |||
return segments | |||
end | |||
function fs.resolve(path) | |||
local segments, rpath = fs.segments(path), "/" | |||
for i = 2, #segments do | |||
rpath = rpath .. segments[i] .. "/" | |||
end | |||
rpath = rpath:match("(.+)/") or rpath | |||
return segments[1] or "root",rpath | |||
end | |||
-- generate some simple functions | |||
for k,v in pairs({"makeDirectory","exists","isDirectory","list","lastModified","remove","size","spaceUsed","isReadOnly","getLabel"}) do | |||
fs[v] = function(path) | |||
local fsi,path = fs.resolve(path) | |||
return fs.mounts[fsi][v](path) | |||
end | |||
end | |||
local function fread(self,length) | |||
if length == "*a" then | |||
length = math.huge | |||
end | |||
local rstr, lstr = "", "" | |||
repeat | |||
lstr = fs.mounts[self.fs].read(self.fid,math.min(2^16,length-rstr:len())) or "" | |||
rstr = rstr .. lstr | |||
until rstr:len() == length or lstr == "" | |||
return rstr | |||
end | |||
local function fwrite(self,data) | |||
fs.mounts[self.fs].write(self.fid,data) | |||
end | |||
local function fclose(self) | |||
fs.mounts[self.fs].close(self.fid) | |||
end | |||
function fs.open(path,mode) | |||
mode = mode or "rb" | |||
local fsi,path = fs.resolve(path) | |||
if not fs.mounts[fsi] then return false end | |||
local fid = fs.mounts[fsi].open(path,mode) | |||
if fid then | |||
local fobj = {["fs"]=fsi,["fid"]=fid,["close"]=fclose} | |||
if mode:sub(1,1) == "r" then | |||
fobj.read = fread | |||
else | |||
fobj.write = fwrite | |||
end | |||
return fobj | |||
end | |||
return false | |||
end | |||
function fs.copy(from,to) | |||
local of = fs.open(from,"rb") | |||
local df = fs.open(to,"wb") | |||
if not of or not df then | |||
return false | |||
end | |||
df:write(of:read("*a")) | |||
df:close() | |||
of:close() | |||
end | |||
function fs.rename(from,to) | |||
local ofsi, opath = fs.resolve(from) | |||
local dfsi, dpath = fs.resolve(to) | |||
if ofsi == dfsi then | |||
fs.mounts[ofsi].rename(opath,dpath) | |||
return true | |||
end | |||
fs.copy(from,to) | |||
fs.remove(from) | |||
return true | |||
end | |||
fs.mounts.temp = component.proxy(computer.tmpAddress()) | |||
if computer.getBootAddress then | |||
fs.mounts.boot = component.proxy(computer.getBootAddress()) | |||
end | |||
for addr, _ in component.list("filesystem") do | |||
fs.mounts[addr:sub(1,3)] = component.proxy(addr) | |||
end | |||
local function rf() | |||
return false | |||
end | |||
fs.mounts.root = {} | |||
for k,v in pairs(fs.mounts.temp) do | |||
fs.mounts.root[k] = rf | |||
end | |||
function fs.mounts.root.list() | |||
local t = {} | |||
for k,v in pairs(fs.mounts) do | |||
t[#t+1] = k | |||
end | |||
t.n = #t | |||
return t | |||
end | |||
function fs.mounts.root.isReadOnly() | |||
return true | |||
end |
@@ -0,0 +1,17 @@ | |||
os.spawn(function() print(pcall(function() | |||
print(_OSVERSION,tostring(math.floor(computer.totalMemory()/1024)).."K memory") | |||
local f = fs.open("/boot/init.txt","rb") | |||
local fc = f:read("*a") | |||
f:close() | |||
for line in fc:gmatch("[^\n]+") do | |||
print("Starting service "..line) | |||
spawnfile("/boot/service/"..line) | |||
end | |||
for k,v in pairs(fd) do | |||
if v.t == "t" then | |||
tTasks[cPid].t = k | |||
print("Spawning a shell for terminal #"..tostring(k)) | |||
spawnfile("/boot/exec/shell.lua","shell #"..tostring(k)) | |||
end | |||
end | |||
end)) end,"init") |
@@ -0,0 +1,28 @@ | |||
_G.fd,_G.io = {},{} | |||
do | |||
function io.write(d) | |||
fd[tTasks[cPid].t or 1].w(d) | |||
end | |||
function io.read(d,b) | |||
local r = "" | |||
repeat | |||
r=fd[tTasks[cPid].t or 1].r(d) | |||
coroutine.yield() | |||
until r or b | |||
return r | |||
end | |||
function print(...) | |||
for k,v in pairs({...}) do | |||
io.write(tostring(v).."\n") | |||
end | |||
end | |||
local ts = {} | |||
for a,_ in component.list("screen") do | |||
ts[#ts+1] = a | |||
end | |||
for a,_ in component.list("gpu") do | |||
local r,w = vtemu(a,table.remove(ts,1)) | |||
fd[#fd+1] = {["r"]=r,["w"]=w,["t"]="t"} | |||
end | |||
end |
@@ -0,0 +1,12 @@ | |||
function loadfile(p) | |||
local f = fs.open(p,"rb") | |||
local c = f:read("*a") | |||
f:close() | |||
return load(c,p,"t") | |||
end | |||
function runfile(p,...) | |||
loadfile(p)(...) | |||
end | |||
function spawnfile(p,n) | |||
os.spawn(loadfile(p),n) | |||
end |
@@ -0,0 +1,88 @@ | |||
_G.net={} | |||
do | |||
local modems,packetQueue,packetCache,routeCache,C,Y = {},{},{},{},COMPUTER,UNPACK | |||
net.port,net.hostname,net.route,net.hook,U=4096,computer.address():sub(1,8),true,{},UPTIME | |||
for a in component.list("modem") do | |||
modems[a] = component.proxy(a) | |||
modems[a].open(net.port) | |||
end | |||
local function genPacketID() | |||
local packetID = "" | |||
for i = 1, 16 do | |||
packetID = packetID .. string.char(math.random(32,126)) | |||
end | |||
return packetID | |||
end | |||
local function rawSendPacket(packetID,packetType,to,from,vport,data) | |||
if routeCache[to] then | |||
modems[routeCache[to][1]].send(routeCache[to][2],net.port,packetID,packetType,to,from,vport,data) | |||
else | |||
for k,v in pairs(modems) do | |||
v.broadcast(net.port,packetID,packetType,to,from,vport,data) | |||
end | |||
end | |||
end | |||
local function sendPacket(packetID,packetType,to,vport,data) | |||
packetCache[packetID] = computer.uptime() | |||
rawSendPacket(packetID,packetType,to,net.hostname,vport,data) | |||
end | |||
function net.send(to,vport,data,packetType,packetID) | |||
packetType,packetID = packetType or 1, packetID or genPacketID() | |||
packetQueue[packetID] = {packetType,to,vport,data,0} | |||
sendPacket(packetID,packetType,to,vport,data) | |||
end | |||
local function checkCache(packetID) | |||
for k,v in pairs(packetCache) do | |||
if k == packetID then | |||
return false | |||
end | |||
end | |||
return true | |||
end | |||
os.spawn(function() | |||
while true do | |||
local eventTab = {coroutine.yield()} | |||
if eventTab[1] == "modem_message" and (eventTab[4] == net.port or eventTab[4] == 0) and checkCache(eventTab[6]) then | |||
for k,v in pairs(packetCache) do | |||
if computer.uptime() > v+30 then | |||
packetCache[k] = nil | |||
end | |||
end | |||
for k,v in pairs(routeCache) do | |||
if computer.uptime() > v[3]+30 then | |||
routeCache[k] = nil | |||
end | |||
end | |||
routeCache[eventTab[9]] = {eventTab[2],eventTab[3],computer.uptime()} | |||
if eventTab[8] == net.hostname then | |||
if eventTab[7] ~= 2 then | |||
computer.pushSignal("net_msg",eventTab[9],eventTab[10],eventTab[11]) | |||
if eventTab[7] == 1 then | |||
sendPacket(genPacketID(),2,eventTab[9],eventTab[10],eventTab[6]) | |||
end | |||
else | |||
packetQueue[eventTab[11]] = nil | |||
end | |||
elseif net.route and checkCache(eventTab[6]) then | |||
rawSendPacket(eventTab[6],eventTab[7],eventTab[8],eventTab[9],eventTab[10],eventTab[11]) | |||
end | |||
packetCache[eventTab[6]] = computer.uptime() | |||
end | |||
for k,v in pairs(packetQueue) do | |||
if computer.uptime() > v[5] then | |||
sendPacket(k,table.unpack(v)) | |||
v[5]=computer.uptime()+30 | |||
end | |||
end | |||
end | |||
end,"minitel.3") | |||
end |
@@ -0,0 +1,22 @@ | |||
tTasks,nPid,nTimeout,cPid = {},1,1,0 | |||
function os.spawn(f,n) | |||
tTasks[nPid] = {["c"]=coroutine.create(f),["n"]=n,["p"]=nPid} | |||
for k,v in pairs(tTasks[cPid] or {}) do | |||
tTasks[nPid][k] = tTasks[nPid][k] or v | |||
end | |||
nPid = nPid + 1 | |||
return nPid - 1 | |||
end | |||
function sched() | |||
while #tTasks > 0 do | |||
local tEv = {computer.pullSignal(nTimeout)} | |||
for k,v in pairs(tTasks) do | |||
if coroutine.status(v.c) ~= "dead" then | |||
cPid = k | |||
coroutine.resume(v.c,table.unpack(tEv)) | |||
else | |||
tTasks[k] = nil | |||
end | |||
end | |||
end | |||
end |
@@ -0,0 +1,15 @@ | |||
os.spawn(function() | |||
print(_OSVERSION,tostring(computer.totalMemory()/1024).."K memory") | |||
for k,v in pairs(fd) do | |||
if v.t == "t" then | |||
tTasks[cPid].t = k | |||
print("Spawning Lua prompt for "..tostring(k)) | |||
os.spawn(function() print(pcall(function() while true do | |||
io.write(_VERSION.."> ") | |||
tResult = {pcall(load(io.read()))} | |||
for k,v in pairs(tResult) do | |||
print(v) | |||
end | |||
end end)) end,"lua prompt") | |||
end | |||
end end,"init") |
@@ -0,0 +1,43 @@ | |||
function vtemu(gpua,scra) | |||
local gpu,scr = component.proxy(gpua),component.proxy(scra) | |||
gpu.bind(scra) | |||
local write = vt100emu(gpu) | |||
local kba = {} | |||
for k,v in ipairs(scr.getKeyboards()) do | |||
kba[v]=true | |||
end | |||
local buf = "" | |||
os.spawn(function() | |||
while true do | |||
local ty,ka,ch = coroutine.yield() | |||
if ty == "key_down" and kba[ka] then | |||
if ch == 13 then ch = 10 end | |||
if ch == 8 and buf:len() > 0 then | |||
write("\8 \8") | |||
buf = buf:sub(1,-2) | |||
elseif ch > 0 then | |||
write(string.char(ch)) | |||
buf = buf .. string.char(ch) | |||
end | |||
end | |||
end | |||
end,"keyboard daemon for "..gpua:sub(1,8)..":"..scra:sub(1,8)) | |||
local function read(n) | |||
n = n or "\n" | |||
local rdata = "" | |||
if type(n) == "number" then | |||
rdata = buf:sub(1,n) | |||
return rdata | |||
else | |||
if n == "*a" then | |||
rdata = buf | |||
buf = "" | |||
return rdata | |||
end | |||
local pr,po = buf:match("(.-)"..n.."(.*)") | |||
buf = po or buf | |||
return pr | |||
end | |||
end | |||
return read,write | |||
end |
@@ -0,0 +1,107 @@ | |||
function vt100emu(gpu) | |||
local mx, my = gpu.maxResolution() | |||
local cx, cy = 1, 1 | |||
local pc = " " | |||
local lc = "" | |||
local mode = "n" | |||
local lw = true | |||
local sx, sy = 1,1 | |||
local cs = "" | |||
-- setup | |||
gpu.setResolution(mx,my) | |||
gpu.fill(1,1,mx,my," ") | |||
function termwrite(s) | |||
s=s:gsub("\8","\27[D") | |||
pc = gpu.get(cx,cy) | |||
gpu.setForeground(0xFFFFFF) | |||
gpu.setBackground(0) | |||
gpu.set(cx,cy,pc) | |||
for i = 1, s:len() do | |||
local cc = s:sub(i,i) | |||
if mode == "n" then | |||
if cc == "\n" then -- line feed | |||
cx, cy = 1, cy+1 | |||
elseif cc == "\r" then -- cursor home | |||
cx = 1 | |||
elseif cc == "\27" then -- escape | |||
mode = "e" | |||
elseif string.byte(cc) > 31 and string.byte(cc) < 127 then -- printable, I guess | |||
gpu.set(cx, cy, cc) | |||
cx = cx + 1 | |||
end | |||
elseif mode == "e" then | |||
if cc == "[" then | |||
mode = "v" | |||
cs = "" | |||
elseif cc == "D" then -- scroll down | |||
gpu.copy(1,2,mx,my-1,0,-1) | |||
gpu.fill(1,my,mx,1," ") | |||
cy=cy+1 | |||
mode = "n" | |||
elseif cc == "M" then -- scroll up | |||
gpu.copy(1,1,mx,my-1,0,1) | |||
gpu.fill(1,1,mx,1," ") | |||
mode = "n" | |||
end | |||
elseif mode == "v" then -- save cursor | |||
local n = cs:sub(cs:len(),cs:len()) | |||
if n == "" then n = "\1" end | |||
if cc == "s" then | |||
sx, sy = cx, cy | |||
mode = "n" | |||
elseif cc == "u" then -- restore cursor | |||
cx, cy = sx, sy | |||
mode = "n" | |||
elseif cc == "H" then -- cursor home or to | |||
local tx, ty = cs:match("(.);(.)") | |||
tx, ty = tx or "\1", ty or "\1" | |||
cx, cy = string.byte(tx), string.byte(ty) | |||
mode = "n" | |||
elseif cc == "A" then -- cursor up | |||
cy = cy - string.byte(n) | |||
mode = "n" | |||
elseif cc == "B" then -- cursor down | |||
cy = cy + string.byte(n) | |||
mode = "n" | |||
elseif cc == "C" then -- cursor right | |||
cx = cx + string.byte(n) | |||
mode = "n" | |||
elseif cc == "D" then -- cursor left | |||
cx = cx - string.byte(n) | |||
mode = "n" | |||
elseif cc == "h" and lc == "7" then -- enable line wrap | |||
lw = true | |||
elseif cc == "l" and lc == "7" then -- disable line wrap | |||
lw = false | |||
end | |||
cs = cs .. cc | |||
end | |||
if cx > mx and lw then | |||
cx, cy = 1, cy+1 | |||
end | |||
if cy > my then | |||
gpu.copy(1,2,mx,my-1,0,-1) | |||
gpu.fill(1,my,mx,1," ") | |||
cy=my | |||
end | |||
if cy < 1 then cy = 1 end | |||
if cx < 1 then cx = 1 end | |||
lc = cc | |||
end | |||
pc = gpu.get(cx,cy) | |||
gpu.setForeground(0) | |||
gpu.setBackground(0xFFFFFF) | |||
gpu.set(cx,cy,pc) | |||
gpu.setForeground(0xFFFFFF) | |||
gpu.setBackground(0) | |||
end | |||
return termwrite | |||
end |
@@ -0,0 +1,86 @@ | |||
_G.net={} | |||
do | |||
local modems,packetQueue,packetCache,routeCache,C,Y = {},{},{},{},COMPUTER,UNPACK | |||
net.port,net.hostname,net.route,net.hook,U=4096,computer.address():sub(1,8),true,{},UPTIME | |||
for a in component.list("modem") do | |||
modems[a] = component.proxy(a) | |||
modems[a].open(net.port) | |||
end | |||
local function genPacketID() | |||
local packetID = "" | |||
for i = 1, 16 do | |||
packetID = packetID .. string.char(math.random(32,126)) | |||
end | |||
return packetID | |||
end | |||
local function rawSendPacket(packetID,packetType,to,from,vport,data) | |||
if routeCache[to] then | |||
modems[routeCache[to][1]].send(routeCache[to][2],net.port,packetID,packetType,to,from,vport,data) | |||
else | |||
for k,v in pairs(modems) do | |||
v.broadcast(net.port,packetID,packetType,to,from,vport,data) | |||
end | |||
end | |||
end | |||
local function sendPacket(packetID,packetType,to,vport,data) | |||
packetCache[packetID] = computer.uptime() | |||
rawSendPacket(packetID,packetType,to,net.hostname,vport,data) | |||
end | |||
function net.send(to,vport,data,packetType,packetID) | |||
packetType,packetID = packetType or 1, packetID or genPacketID() | |||
packetQueue[packetID] = {packetType,to,vport,data,0} | |||
sendPacket(packetID,packetType,to,vport,data) | |||
end | |||
local function checkCache(packetID) | |||
for k,v in pairs(packetCache) do | |||
if k == packetID then | |||
return false | |||
end | |||
end | |||
return true | |||
end | |||
while true do | |||
local eventTab = {coroutine.yield()} | |||
if eventTab[1] == "modem_message" and (eventTab[4] == net.port or eventTab[4] == 0) and checkCache(eventTab[6]) then | |||
for k,v in pairs(packetCache) do | |||
if computer.uptime() > v+30 then | |||
packetCache[k] = nil | |||
end | |||
end | |||
for k,v in pairs(routeCache) do | |||
if computer.uptime() > v[3]+30 then | |||
routeCache[k] = nil | |||
end | |||
end | |||
routeCache[eventTab[9]] = {eventTab[2],eventTab[3],computer.uptime()} | |||
if eventTab[8] == net.hostname then | |||
if eventTab[7] ~= 2 then | |||
computer.pushSignal("net_msg",eventTab[9],eventTab[10],eventTab[11]) | |||
if eventTab[7] == 1 then | |||
sendPacket(genPacketID(),2,eventTab[9],eventTab[10],eventTab[6]) | |||
end | |||
else | |||
packetQueue[eventTab[11]] = nil | |||
end | |||
elseif net.route and checkCache(eventTab[6]) then | |||
rawSendPacket(eventTab[6],eventTab[7],eventTab[8],eventTab[9],eventTab[10],eventTab[11]) | |||
end | |||
packetCache[eventTab[6]] = computer.uptime() | |||
end | |||
for k,v in pairs(packetQueue) do | |||
if computer.uptime() > v[5] then | |||
sendPacket(k,table.unpack(v)) | |||
v[5]=computer.uptime()+30 | |||
end | |||
end | |||
end | |||
end |