From 2f48091a0784b6a7a0c232696900309edb3f18f7 Mon Sep 17 00:00:00 2001 From: XeonSquared Date: Sat, 3 Nov 2018 03:05:41 +1100 Subject: [PATCH] fuck knows --- build.sh | 7 + build/psychos.lua | 432 +++++++++++++++++++++++++++++++++++++ exec/free.lua | 2 + exec/ps.lua | 4 + exec/shell.lua | 9 + mkmods.sh | 8 + mod-service/microtel-3.lua | 88 ++++++++ module/fs.lua | 114 ++++++++++ module/init.lua | 17 ++ module/io.lua | 28 +++ module/loadfile.lua | 12 ++ module/microtel-3.lua | 88 ++++++++ module/sched.lua | 22 ++ module/spawnprompt.lua | 15 ++ module/vt-task.lua | 43 ++++ module/vt100.lua | 107 +++++++++ service/microtel-3.lua | 86 ++++++++ 17 files changed, 1082 insertions(+) create mode 100755 build.sh create mode 100644 build/psychos.lua create mode 100644 exec/free.lua create mode 100644 exec/ps.lua create mode 100644 exec/shell.lua create mode 100755 mkmods.sh create mode 100644 mod-service/microtel-3.lua create mode 100644 module/fs.lua create mode 100644 module/init.lua create mode 100644 module/io.lua create mode 100644 module/loadfile.lua create mode 100644 module/microtel-3.lua create mode 100644 module/sched.lua create mode 100644 module/spawnprompt.lua create mode 100644 module/vt-task.lua create mode 100644 module/vt100.lua create mode 100644 service/microtel-3.lua diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..8aadb7b --- /dev/null +++ b/build.sh @@ -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/* diff --git a/build/psychos.lua b/build/psychos.lua new file mode 100644 index 0000000..e111eb9 --- /dev/null +++ b/build/psychos.lua @@ -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() diff --git a/exec/free.lua b/exec/free.lua new file mode 100644 index 0000000..f32690c --- /dev/null +++ b/exec/free.lua @@ -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))) diff --git a/exec/ps.lua b/exec/ps.lua new file mode 100644 index 0000000..dadbab1 --- /dev/null +++ b/exec/ps.lua @@ -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 diff --git a/exec/shell.lua b/exec/shell.lua new file mode 100644 index 0000000..475f6ad --- /dev/null +++ b/exec/shell.lua @@ -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 diff --git a/mkmods.sh b/mkmods.sh new file mode 100755 index 0000000..3679471 --- /dev/null +++ b/mkmods.sh @@ -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 diff --git a/mod-service/microtel-3.lua b/mod-service/microtel-3.lua new file mode 100644 index 0000000..f085681 --- /dev/null +++ b/mod-service/microtel-3.lua @@ -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") diff --git a/module/fs.lua b/module/fs.lua new file mode 100644 index 0000000..d76c5e8 --- /dev/null +++ b/module/fs.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 diff --git a/module/init.lua b/module/init.lua new file mode 100644 index 0000000..56ad6d1 --- /dev/null +++ b/module/init.lua @@ -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") diff --git a/module/io.lua b/module/io.lua new file mode 100644 index 0000000..1130b27 --- /dev/null +++ b/module/io.lua @@ -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 diff --git a/module/loadfile.lua b/module/loadfile.lua new file mode 100644 index 0000000..843af4d --- /dev/null +++ b/module/loadfile.lua @@ -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 diff --git a/module/microtel-3.lua b/module/microtel-3.lua new file mode 100644 index 0000000..07105c0 --- /dev/null +++ b/module/microtel-3.lua @@ -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 diff --git a/module/sched.lua b/module/sched.lua new file mode 100644 index 0000000..898e190 --- /dev/null +++ b/module/sched.lua @@ -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 diff --git a/module/spawnprompt.lua b/module/spawnprompt.lua new file mode 100644 index 0000000..4ec07a4 --- /dev/null +++ b/module/spawnprompt.lua @@ -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") diff --git a/module/vt-task.lua b/module/vt-task.lua new file mode 100644 index 0000000..0e407d3 --- /dev/null +++ b/module/vt-task.lua @@ -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 diff --git a/module/vt100.lua b/module/vt100.lua new file mode 100644 index 0000000..c9068ed --- /dev/null +++ b/module/vt100.lua @@ -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 diff --git a/service/microtel-3.lua b/service/microtel-3.lua new file mode 100644 index 0000000..a8654af --- /dev/null +++ b/service/microtel-3.lua @@ -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