mirror of
https://git.shadowkat.net/izaya/OC-PsychOS2.git
synced 2024-11-25 12:42:10 -05:00
Compare commits
6 Commits
6a39fe1743
...
8ae4d7b57c
Author | SHA1 | Date | |
---|---|---|---|
|
8ae4d7b57c | ||
|
2fbee483b2 | ||
|
b82bb2a853 | ||
|
92084e8c90 | ||
|
21f40b3f3c | ||
|
9983acb267 |
@ -1,63 +0,0 @@
|
|||||||
local imt = {}
|
|
||||||
|
|
||||||
imt.ttypes = {}
|
|
||||||
imt.ttypes.string=1
|
|
||||||
imt.ttypes.number=2
|
|
||||||
|
|
||||||
imt.ftypes = {tostring,tonumber}
|
|
||||||
|
|
||||||
function imt.to16bn(n)
|
|
||||||
return string.char(math.floor(n/256))..string.char(math.floor(n%256))
|
|
||||||
end
|
|
||||||
function imt.from16bn(s)
|
|
||||||
return (string.byte(s,1,1)*256)+string.byte(s,2,2)
|
|
||||||
end
|
|
||||||
|
|
||||||
function imt.encodePacket(...)
|
|
||||||
local tArgs = {...}
|
|
||||||
local packet = string.char(#tArgs%256)
|
|
||||||
for _,segment in ipairs(tArgs) do
|
|
||||||
local segtype = type(segment)
|
|
||||||
segment = tostring(segment)
|
|
||||||
packet = packet .. imt.to16bn(segment:len()) .. string.char(imt.ttypes[segtype]) .. tostring(segment)
|
|
||||||
end
|
|
||||||
packet = imt.to16bn(packet:len()) .. packet
|
|
||||||
return packet
|
|
||||||
end
|
|
||||||
|
|
||||||
function imt.decodePacket(s)
|
|
||||||
local function getfirst(n)
|
|
||||||
local ns = s:sub(1,n)
|
|
||||||
s=s:sub(n+1)
|
|
||||||
return ns
|
|
||||||
end
|
|
||||||
if s:len() < 2 then return false end
|
|
||||||
local plen = imt.from16bn(getfirst(2))
|
|
||||||
local segments = {}
|
|
||||||
if s:len() < plen then return false end
|
|
||||||
local nsegments = string.byte(getfirst(1))
|
|
||||||
--print(tostring(plen).." bytes, "..tostring(nsegments).." segments")
|
|
||||||
for i = 1, nsegments do
|
|
||||||
local seglen = imt.from16bn(getfirst(2))
|
|
||||||
local segtype = imt.ftypes[string.byte(getfirst(1))]
|
|
||||||
local segment = segtype(getfirst(seglen))
|
|
||||||
--print(seglen,segtype,segment,type(segment))
|
|
||||||
segments[#segments+1] = segment
|
|
||||||
end
|
|
||||||
return table.unpack(segments)
|
|
||||||
end
|
|
||||||
function imt.getRemainder(s)
|
|
||||||
local function getfirst(n)
|
|
||||||
local ns = s:sub(1,n)
|
|
||||||
s=s:sub(n+1)
|
|
||||||
return ns
|
|
||||||
end
|
|
||||||
local plen = imt.from16bn(getfirst(2))
|
|
||||||
if s:len() > plen then
|
|
||||||
getfirst(plen)
|
|
||||||
return s
|
|
||||||
end
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
return imt
|
|
@ -1,9 +1,13 @@
|
|||||||
local serial = require "serialization"
|
local serial = require "serialization"
|
||||||
local dl = require "download"
|
local dl = require "download"
|
||||||
|
local mtar = require "libmtar"
|
||||||
local pkg = {}
|
local pkg = {}
|
||||||
pkg.cfgPath = "/boot/cfg/pkg"
|
pkg.cfgPath = "/boot/cfg/pkg"
|
||||||
pkg.sourcePath = pkg.cfgPath .. "/sources.cfg"
|
pkg.sourcePath = pkg.cfgPath .. "/sources.cfg"
|
||||||
pkg.installedPath = pkg.cfgPath .. "/installed.cfg"
|
pkg.installedPath = pkg.cfgPath .. "/installed.cfg"
|
||||||
|
local w, lz16 = pcall(require,"liblz16")
|
||||||
|
if not w then lz16 = nil end
|
||||||
|
require "pkgfs"
|
||||||
|
|
||||||
local function getSources()
|
local function getSources()
|
||||||
local f = io.open(pkg.sourcePath,"rb")
|
local f = io.open(pkg.sourcePath,"rb")
|
||||||
@ -53,6 +57,31 @@ end
|
|||||||
local function deactivatePackage(path)
|
local function deactivatePackage(path)
|
||||||
require("pkgfs").remove(path)
|
require("pkgfs").remove(path)
|
||||||
end
|
end
|
||||||
|
local function fnormalize(s)
|
||||||
|
return table.concat(fs.segments(s),"/")
|
||||||
|
end
|
||||||
|
local function installSystemPackage(path,comp)
|
||||||
|
local f
|
||||||
|
if comp and lz16 then
|
||||||
|
f = lz16.open(path,"rb")
|
||||||
|
else
|
||||||
|
f = io.open(path,"rb")
|
||||||
|
end
|
||||||
|
for fname, read, size in mtar.iter(f) do
|
||||||
|
local opath = "/boot/"..fnormalize(fname)
|
||||||
|
print(opath..": "..tostring(size))
|
||||||
|
fs.makeDirectory(opath:match("(.+)/[^/]+"))
|
||||||
|
local of = io.open(opath,"wb")
|
||||||
|
if not of then error("unable to open "..opath.." for writing") end
|
||||||
|
local tmp
|
||||||
|
repeat
|
||||||
|
tmp = read(2048) or ""
|
||||||
|
of:write(tmp)
|
||||||
|
until not tmp or tmp:len() < 1
|
||||||
|
of:close()
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
function pkg.addRepo(name,path,cache) -- string string boolean -- boolean -- Adds a repository, referred to as *name*, to the list of package sources, with the remote path *path*. If *cache* is set, keep a local copy of the repository index.
|
function pkg.addRepo(name,path,cache) -- string string boolean -- boolean -- Adds a repository, referred to as *name*, to the list of package sources, with the remote path *path*. If *cache* is set, keep a local copy of the repository index.
|
||||||
local sources = getSources()
|
local sources = getSources()
|
||||||
@ -75,7 +104,7 @@ function pkg.update() -- Re-download cached repository indexes.
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function pkg.list(filter) -- string -- -- Print a list of available packages matching *filter*.
|
function pkg.list(filter,installed) -- string boolean -- -- Print a list of available packages matching *filter*, optionally filtering to only installed packages if *installed* is set.
|
||||||
filter = filter or ""
|
filter = filter or ""
|
||||||
local pkglist = {}
|
local pkglist = {}
|
||||||
for repo,_ in pairs(getSources()) do
|
for repo,_ in pairs(getSources()) do
|
||||||
@ -87,7 +116,8 @@ function pkg.list(filter) -- string -- -- Print a list of available packages mat
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
for k,v in pairs(pkglist) do
|
for k,v in pairs(pkglist) do
|
||||||
print(string.format("%s/%s\n %s",v.repo,k,v.description))
|
if v.system then io.write("\27[31m") end
|
||||||
|
print(string.format("%s/%s: %s\27[0m\n %s\n Authors: %s",v.repo,k,v.name,v.description,v.authors))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -103,48 +133,54 @@ function pkg.getMeta(pkgname) -- string -- table -- Returns the metadata for a t
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function pkg.get(pkgname,auto) -- string boolean -- boolean -- Downloads and mounts a package, identified as *pkgname*, onto the pkgfs.
|
function pkg.get(pkgname,auto) -- string boolean -- boolean -- Downloads and mounts a package, identified as *pkgname,* onto the pkgfs. Setting *auto* will flag the package as automatically installed; this is used for dependencies.
|
||||||
local pkginfo = pkg.getMeta(pkgname)
|
local pkginfo = pkg.getMeta(pkgname)
|
||||||
if not pkginfo then error("unable to locate package "..pkgname) end
|
if not pkginfo then error("unable to locate package "..pkgname) end
|
||||||
pkginfo.manual = not auto
|
pkginfo.manual = not auto
|
||||||
fs.makeDirectory("/boot/pkg")
|
fs.makeDirectory("/boot/pkg")
|
||||||
for k,v in ipairs(pkginfo.dependencies or {}) do
|
for k,v in ipairs(pkginfo.dependencies or {}) do
|
||||||
if not getInstalled()[v] then
|
if not getInstalled()[v] then
|
||||||
pkg.get(v)
|
pkg.get(v,true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
dl(pkginfo.repository.path.."/"..pkginfo.filename,"/boot/pkg/"..pkginfo.filename)
|
dl(pkginfo.repository.path.."/"..pkginfo.filename,"/boot/pkg/"..pkginfo.filename)
|
||||||
local installed = getInstalled()
|
local installed = getInstalled()
|
||||||
installed[pkgname] = pkginfo
|
installed[pkgname] = pkginfo
|
||||||
saveInstalled(installed)
|
saveInstalled(installed)
|
||||||
|
if pkginfo.system then
|
||||||
|
local rv = installSystemPackage("/boot/pkg/"..pkginfo.filename,pkginfo.compressed)
|
||||||
|
fs.remove("/boot/pkg/"..pkginfo.filename)
|
||||||
|
return rv
|
||||||
|
end
|
||||||
pcall(activatePackage,"/boot/pkg/"..pkginfo.filename,pkginfo.compressed)
|
pcall(activatePackage,"/boot/pkg/"..pkginfo.filename,pkginfo.compressed)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
function pkg.upgrade(force) -- boolean -- boolean -- Upgrades all packages on the system to the current version stored in the relevant repository. If *force* is set, re-download all packages.
|
function pkg.upgrade(force) -- boolean -- -- Upgrades all packages on the system to the current version stored in the relevant repository. If *force* is set, re-download all packages.
|
||||||
pkg.update()
|
pkg.update()
|
||||||
fs.makeDirectory("/boot/pkg")
|
fs.makeDirectory("/boot/pkg")
|
||||||
local installed = getInstalled()
|
local installed = getInstalled()
|
||||||
for repo,info in pairs(getSources()) do
|
for repo,info in pairs(getSources()) do
|
||||||
for pkgname,pkg in pairs(getRepoMeta(repo)) do
|
for pkgname,pkginfo in pairs(getRepoMeta(repo)) do
|
||||||
if pkg.version ~= installed[pkgname].version or force then
|
if installed[pkgname] and pkginfo.version ~= installed[pkgname].version or force then
|
||||||
pkg.remove(pkgname)
|
pkg.remove(pkgname)
|
||||||
dl(info.path.."/"..pkg.filename,"/boot/pkg/"..pkg.filename)
|
pkg.get(pkgname,pkginfo.auto)
|
||||||
installed[pkgname] = pkg
|
|
||||||
pcall(activatePackage,"/boot/pkg/"..pkg.filename,pkg.compressed)
|
|
||||||
return true
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
saveInstalled(installed)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function pkg.remove(pkgname) -- string -- boolean -- Remove the package *pkgname* from the pkgfs and package directory.
|
function pkg.remove(pkgname) -- string -- boolean -- Remove the package *pkgname* from the pkgfs and package directory.
|
||||||
local installed = getInstalled()
|
local installed = getInstalled()
|
||||||
local pkginfo = installed[pkgname]
|
local pkginfo = installed[pkgname]
|
||||||
if not pkginfo then error(pkgname .." not installed") end
|
if not pkginfo then return true end
|
||||||
pcall(deactivatePackage,"/boot/pkg/"..pkginfo.filename)
|
pcall(deactivatePackage,"/boot/pkg/"..pkginfo.filename)
|
||||||
fs.remove("/boot/pkg/"..pkginfo.filename)
|
fs.remove("/boot/pkg/"..pkginfo.filename)
|
||||||
|
if pkginfo.system then
|
||||||
|
for k,v in pairs(pkginfo.files) do
|
||||||
|
fs.remove(v)
|
||||||
|
end
|
||||||
|
end
|
||||||
installed[pkgname] = nil
|
installed[pkgname] = nil
|
||||||
saveInstalled(installed)
|
saveInstalled(installed)
|
||||||
return true
|
return true
|
||||||
|
@ -1,69 +0,0 @@
|
|||||||
local preproc = {}
|
|
||||||
preproc.directives = {}
|
|
||||||
|
|
||||||
function preproc.parsewords(line) -- string -- table -- Returns a table of words from the string *line*, parsing quotes and escapes.
|
|
||||||
local rt = {""}
|
|
||||||
local escaped, quoted = false, false
|
|
||||||
for c in line:gmatch(".") do
|
|
||||||
if escaped then
|
|
||||||
rt[#rt] = rt[#rt]..c
|
|
||||||
elseif c == '"' or c == "'" then
|
|
||||||
quoted = not quoted
|
|
||||||
elseif c == "\\" then
|
|
||||||
escaped = true
|
|
||||||
elseif c:match("%s") and not quoted and rt[#rt]:len() > 0 then
|
|
||||||
rt[#rt+1] = ""
|
|
||||||
else
|
|
||||||
rt[#rt] = rt[#rt]..c
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return rt
|
|
||||||
end
|
|
||||||
|
|
||||||
function preproc.line(line) -- string -- -- Returns either a function - which can be called to get lines until it returns nil - or a string from processing *line* using preprocessor directives.
|
|
||||||
if line:match("^%-%-#") then
|
|
||||||
local directive, args = line:match("^%-%-#(%S+)%s(.+)")
|
|
||||||
print(directive,args)
|
|
||||||
local args = preproc.parsewords(args)
|
|
||||||
if preproc.directives[directive] then
|
|
||||||
return preproc.directives[directive](table.unpack(args))
|
|
||||||
else
|
|
||||||
error("unknown preprocessor directive: "..directive)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
return line
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function preproc.preproc(...) -- string -- string -- Returns the output from preprocessing the files listed in *...*.
|
|
||||||
local tA = {...}
|
|
||||||
local output = ""
|
|
||||||
for _,fname in ipairs(tA) do
|
|
||||||
local f,e = io.open(fname)
|
|
||||||
if not f then error("unable to open file "..fname..": "..e) end
|
|
||||||
for line in f:lines() do
|
|
||||||
local r = preproc.line(line)
|
|
||||||
if type(r) == "function" then
|
|
||||||
while true do
|
|
||||||
local rs = r()
|
|
||||||
if not rs then break end
|
|
||||||
output = output .. rs .. "\n"
|
|
||||||
end
|
|
||||||
else
|
|
||||||
output = output .. r .. "\n"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return output
|
|
||||||
end
|
|
||||||
|
|
||||||
preproc.directives.include = preproc.preproc
|
|
||||||
|
|
||||||
return setmetatable(preproc,{__call=function(_,...)
|
|
||||||
local tA = {...}
|
|
||||||
local out = table.remove(tA,#tA)
|
|
||||||
local f,e = io.open(out,"wb")
|
|
||||||
if not f then error("unable to open file "..out..": "..e) end
|
|
||||||
f:write(preproc.preproc(table.unpack(tA)))
|
|
||||||
f:close()
|
|
||||||
end})
|
|
@ -29,7 +29,12 @@ function rc.load(name,force) -- string boolean -- table -- Attempts to load serv
|
|||||||
end
|
end
|
||||||
if service[name] then return true end
|
if service[name] then return true end
|
||||||
service[name] = setmetatable({},{__index=_G})
|
service[name] = setmetatable({},{__index=_G})
|
||||||
local f = io.open("/boot/service/"..name..".lua","rb") or io.open("/pkg/service/"..name..".lua","rb")
|
local f
|
||||||
|
f = io.open("/boot/service/"..name..".lua","rb")
|
||||||
|
if not f then
|
||||||
|
pcall(require,"pkgfs")
|
||||||
|
f = io.open("/pkg/service/"..name..".lua","rb")
|
||||||
|
end
|
||||||
local res = load(f:read("*a"),name,"t",service[name])()
|
local res = load(f:read("*a"),name,"t",service[name])()
|
||||||
f:close()
|
f:close()
|
||||||
return res
|
return res
|
||||||
|
114
lib/unionfs.lua
114
lib/unionfs.lua
@ -1,114 +0,0 @@
|
|||||||
local unionfs = {}
|
|
||||||
|
|
||||||
local function normalise(path)
|
|
||||||
return table.concat(fs.segments(path),"/")
|
|
||||||
end
|
|
||||||
|
|
||||||
function unionfs.create(...) -- string -- table -- Returns a unionfs object of the directories specified in *...*.
|
|
||||||
local paths,fids,fc = {...}, {}, 0
|
|
||||||
for k,v in pairs(paths) do
|
|
||||||
paths[k] = "/"..normalise(v)
|
|
||||||
end
|
|
||||||
local proxy = {}
|
|
||||||
local function realpath(path)
|
|
||||||
path = path or ""
|
|
||||||
for k,v in pairs(paths) do
|
|
||||||
if fs.exists(v.."/"..path) then
|
|
||||||
return v.."/"..path
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return paths[1].."/"..path
|
|
||||||
end
|
|
||||||
|
|
||||||
function proxy.setLabel()
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
function proxy.spaceUsed()
|
|
||||||
return fs.spaceUsed(paths[1])
|
|
||||||
end
|
|
||||||
function proxy.spaceTotal()
|
|
||||||
return fs.spaceTotal(paths[1])
|
|
||||||
end
|
|
||||||
function proxy.isReadOnly()
|
|
||||||
return fs.isReadOnly(paths[1])
|
|
||||||
end
|
|
||||||
function proxy.isDirectory(path)
|
|
||||||
return fs.isDirectory(realpath(path))
|
|
||||||
end
|
|
||||||
function proxy.lastModified(path)
|
|
||||||
return fs.lastModified(realpath(path))
|
|
||||||
end
|
|
||||||
function proxy.getLabel()
|
|
||||||
return fs.getLabel(paths[1])
|
|
||||||
end
|
|
||||||
|
|
||||||
function proxy.exists(path)
|
|
||||||
return fs.exists(realpath(path))
|
|
||||||
end
|
|
||||||
function proxy.remove(path)
|
|
||||||
return fs.remove(realpath(path))
|
|
||||||
end
|
|
||||||
function proxy.size(path)
|
|
||||||
return fs.size(realpath(path))
|
|
||||||
end
|
|
||||||
|
|
||||||
function proxy.list(path)
|
|
||||||
local nt,rt = {},{}
|
|
||||||
if #fs.segments(path) < 1 then
|
|
||||||
for k,v in pairs(paths) do
|
|
||||||
for l,m in ipairs(fs.list(v.."/"..path)) do
|
|
||||||
nt[m] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for k,v in pairs(nt) do
|
|
||||||
rt[#rt+1] = k
|
|
||||||
end
|
|
||||||
table.sort(rt)
|
|
||||||
return rt
|
|
||||||
else
|
|
||||||
return fs.list(realpath(path))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function proxy.open(path,mode)
|
|
||||||
local fh, r = fs.open(realpath(path),mode)
|
|
||||||
if not fh then return fh, r end
|
|
||||||
fids[fc] = fh
|
|
||||||
fc = fc + 1
|
|
||||||
return fc - 1
|
|
||||||
end
|
|
||||||
|
|
||||||
function proxy.close(fid)
|
|
||||||
if not fids[fid] then
|
|
||||||
return false, "file not open"
|
|
||||||
end
|
|
||||||
local rfh = fids[fid]
|
|
||||||
fids[fid] = nil
|
|
||||||
return rfh:close()
|
|
||||||
end
|
|
||||||
function proxy.write(fid,d)
|
|
||||||
if not fids[fid] then
|
|
||||||
return false, "file not open"
|
|
||||||
end
|
|
||||||
return fids[fid]:write(d)
|
|
||||||
end
|
|
||||||
function proxy.read(fid,d)
|
|
||||||
if not fids[fid] then
|
|
||||||
return false, "file not open"
|
|
||||||
end
|
|
||||||
local rb = fids[fid]:read(d)
|
|
||||||
if rb == "" then rb = nil end
|
|
||||||
return rb
|
|
||||||
end
|
|
||||||
function proxy.seek(fid,d)
|
|
||||||
if not fids[fid] then
|
|
||||||
return false, "file not open"
|
|
||||||
end
|
|
||||||
return fids[fid]:seek(d)
|
|
||||||
end
|
|
||||||
|
|
||||||
return proxy
|
|
||||||
end
|
|
||||||
|
|
||||||
return unionfs
|
|
@ -1,197 +0,0 @@
|
|||||||
local proxylist = {}
|
|
||||||
local proxyobjs = {}
|
|
||||||
local typelist = {}
|
|
||||||
local doclist = {}
|
|
||||||
|
|
||||||
local oproxy = component.proxy
|
|
||||||
function component.proxy(address)
|
|
||||||
checkArg(1,address,"string")
|
|
||||||
if proxyobjs[address] ~= nil then
|
|
||||||
return proxyobjs[address]
|
|
||||||
end
|
|
||||||
return oproxy(address)
|
|
||||||
end
|
|
||||||
|
|
||||||
local olist = component.list
|
|
||||||
function component.list(filter, exact)
|
|
||||||
checkArg(1,filter,"string","nil")
|
|
||||||
local result = {}
|
|
||||||
local data = {}
|
|
||||||
for k,v in olist(filter, exact) do
|
|
||||||
data[#data + 1] = k
|
|
||||||
data[#data + 1] = v
|
|
||||||
result[k] = v
|
|
||||||
end
|
|
||||||
for k,v in pairs(typelist) do
|
|
||||||
if filter == nil or (exact and v == filter) or (not exact and v:find(filter, nil, true)) then
|
|
||||||
data[#data + 1] = k
|
|
||||||
data[#data + 1] = v
|
|
||||||
result[k] = v
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local place = 1
|
|
||||||
return setmetatable(result,
|
|
||||||
{__call=function()
|
|
||||||
local addr,type = data[place], data[place + 1]
|
|
||||||
place = place + 2
|
|
||||||
return addr, type
|
|
||||||
end}
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
local otype = component.type
|
|
||||||
function component.type(address)
|
|
||||||
checkArg(1,address,"string")
|
|
||||||
if typelist[address] ~= nil then
|
|
||||||
return typelist[address]
|
|
||||||
end
|
|
||||||
return otype(address)
|
|
||||||
end
|
|
||||||
|
|
||||||
local odoc = component.doc
|
|
||||||
function component.doc(address, method)
|
|
||||||
checkArg(1,address,"string")
|
|
||||||
checkArg(2,method,"string")
|
|
||||||
if proxylist[address] ~= nil then
|
|
||||||
if proxylist[address][method] == nil then
|
|
||||||
error("no such method",2)
|
|
||||||
end
|
|
||||||
if doclist[address] ~= nil then
|
|
||||||
return doclist[address][method]
|
|
||||||
end
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
return odoc(address, method)
|
|
||||||
end
|
|
||||||
|
|
||||||
local oslot = component.slot
|
|
||||||
function component.slot(address)
|
|
||||||
checkArg(1,address,"string")
|
|
||||||
if proxylist[address] ~= nil then
|
|
||||||
return -1 -- vcomponents do not exist in a slot
|
|
||||||
end
|
|
||||||
return oslot(address)
|
|
||||||
end
|
|
||||||
|
|
||||||
local omethods = component.methods
|
|
||||||
function component.methods(address)
|
|
||||||
checkArg(1,address,"string")
|
|
||||||
if proxylist[address] ~= nil then
|
|
||||||
local methods = {}
|
|
||||||
for k,v in pairs(proxylist[address]) do
|
|
||||||
if type(v) == "function" then
|
|
||||||
methods[k] = true -- All vcomponent methods are direct
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return methods
|
|
||||||
end
|
|
||||||
return omethods(address)
|
|
||||||
end
|
|
||||||
|
|
||||||
local oinvoke = component.invoke
|
|
||||||
function component.invoke(address, method, ...)
|
|
||||||
checkArg(1,address,"string")
|
|
||||||
checkArg(2,method,"string")
|
|
||||||
if proxylist[address] ~= nil then
|
|
||||||
if proxylist[address][method] == nil then
|
|
||||||
error("no such method",2)
|
|
||||||
end
|
|
||||||
return proxylist[address][method](...)
|
|
||||||
end
|
|
||||||
return oinvoke(address, method, ...)
|
|
||||||
end
|
|
||||||
|
|
||||||
local ofields = component.fields
|
|
||||||
function component.fields(address)
|
|
||||||
checkArg(1,address,"string")
|
|
||||||
if proxylist[address] ~= nil then
|
|
||||||
return {} -- What even is this?
|
|
||||||
end
|
|
||||||
return ofields(address)
|
|
||||||
end
|
|
||||||
|
|
||||||
local componentCallback =
|
|
||||||
{
|
|
||||||
__call = function(self, ...) return proxylist[self.address][self.name](...) end,
|
|
||||||
__tostring = function(self) return (doclist[self.address] ~= nil and doclist[self.address][self.name] ~= nil) and doclist[self.address][self.name] or "function" end
|
|
||||||
}
|
|
||||||
|
|
||||||
local vcomponent = {}
|
|
||||||
|
|
||||||
function vcomponent.register(address, ctype, proxy, doc)
|
|
||||||
checkArg(1,address,"string")
|
|
||||||
checkArg(2,ctype,"string")
|
|
||||||
checkArg(3,proxy,"table")
|
|
||||||
if proxylist[address] ~= nil then
|
|
||||||
return nil, "component already at address"
|
|
||||||
elseif component.type(address) ~= nil then
|
|
||||||
return nil, "cannot register over real component"
|
|
||||||
end
|
|
||||||
proxy.address = address
|
|
||||||
proxy.type = ctype
|
|
||||||
local proxyobj = {}
|
|
||||||
for k,v in pairs(proxy) do
|
|
||||||
if type(v) == "function" then
|
|
||||||
proxyobj[k] = setmetatable({name=k,address=address},componentCallback)
|
|
||||||
else
|
|
||||||
proxyobj[k] = v
|
|
||||||
end
|
|
||||||
end
|
|
||||||
proxylist[address] = proxy
|
|
||||||
proxyobjs[address] = proxyobj
|
|
||||||
typelist[address] = ctype
|
|
||||||
doclist[address] = doc
|
|
||||||
computer.pushSignal("component_added",address,ctype)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
function vcomponent.unregister(address)
|
|
||||||
checkArg(1,address,"string")
|
|
||||||
if proxylist[address] == nil then
|
|
||||||
if component.type(address) ~= nil then
|
|
||||||
return nil, "cannot unregister real component"
|
|
||||||
else
|
|
||||||
return nil, "no component at address"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local thetype = typelist[address]
|
|
||||||
proxylist[address] = nil
|
|
||||||
proxyobjs[address] = nil
|
|
||||||
typelist[address] = nil
|
|
||||||
doclist[address] = nil
|
|
||||||
computer.pushSignal("component_removed",address,thetype)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
function vcomponent.list()
|
|
||||||
local list = {}
|
|
||||||
for k,v in pairs(proxylist) do
|
|
||||||
list[#list + 1] = {k,typelist[k],v}
|
|
||||||
end
|
|
||||||
return list
|
|
||||||
end
|
|
||||||
|
|
||||||
function vcomponent.resolve(address, componentType)
|
|
||||||
checkArg(1, address, "string")
|
|
||||||
checkArg(2, componentType, "string", "nil")
|
|
||||||
for k,v in pairs(typelist) do
|
|
||||||
if componentType == nil or v == componentType then
|
|
||||||
if k:sub(1, #address) == address then
|
|
||||||
return k
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return nil, "no such component"
|
|
||||||
end
|
|
||||||
|
|
||||||
local r = math.random
|
|
||||||
function vcomponent.uuid()
|
|
||||||
return string.format("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
|
||||||
r(0,255),r(0,255),r(0,255),r(0,255),
|
|
||||||
r(0,255),r(0,255),
|
|
||||||
r(64,79),r(0,255),
|
|
||||||
r(128,191),r(0,255),
|
|
||||||
r(0,255),r(0,255),r(0,255),r(0,255),r(0,255),r(0,255))
|
|
||||||
end
|
|
||||||
|
|
||||||
return vcomponent
|
|
@ -1 +0,0 @@
|
|||||||
lib/preproc.lua
|
|
69
preproc.lua
Normal file
69
preproc.lua
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
local preproc = {}
|
||||||
|
preproc.directives = {}
|
||||||
|
|
||||||
|
function preproc.parsewords(line) -- string -- table -- Returns a table of words from the string *line*, parsing quotes and escapes.
|
||||||
|
local rt = {""}
|
||||||
|
local escaped, quoted = false, false
|
||||||
|
for c in line:gmatch(".") do
|
||||||
|
if escaped then
|
||||||
|
rt[#rt] = rt[#rt]..c
|
||||||
|
elseif c == '"' or c == "'" then
|
||||||
|
quoted = not quoted
|
||||||
|
elseif c == "\\" then
|
||||||
|
escaped = true
|
||||||
|
elseif c:match("%s") and not quoted and rt[#rt]:len() > 0 then
|
||||||
|
rt[#rt+1] = ""
|
||||||
|
else
|
||||||
|
rt[#rt] = rt[#rt]..c
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return rt
|
||||||
|
end
|
||||||
|
|
||||||
|
function preproc.line(line) -- string -- -- Returns either a function - which can be called to get lines until it returns nil - or a string from processing *line* using preprocessor directives.
|
||||||
|
if line:match("^%-%-#") then
|
||||||
|
local directive, args = line:match("^%-%-#(%S+)%s(.+)")
|
||||||
|
print(directive,args)
|
||||||
|
local args = preproc.parsewords(args)
|
||||||
|
if preproc.directives[directive] then
|
||||||
|
return preproc.directives[directive](table.unpack(args))
|
||||||
|
else
|
||||||
|
error("unknown preprocessor directive: "..directive)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return line
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function preproc.preproc(...) -- string -- string -- Returns the output from preprocessing the files listed in *...*.
|
||||||
|
local tA = {...}
|
||||||
|
local output = ""
|
||||||
|
for _,fname in ipairs(tA) do
|
||||||
|
local f,e = io.open(fname)
|
||||||
|
if not f then error("unable to open file "..fname..": "..e) end
|
||||||
|
for line in f:lines() do
|
||||||
|
local r = preproc.line(line)
|
||||||
|
if type(r) == "function" then
|
||||||
|
while true do
|
||||||
|
local rs = r()
|
||||||
|
if not rs then break end
|
||||||
|
output = output .. rs .. "\n"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
output = output .. r .. "\n"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return output
|
||||||
|
end
|
||||||
|
|
||||||
|
preproc.directives.include = preproc.preproc
|
||||||
|
|
||||||
|
return setmetatable(preproc,{__call=function(_,...)
|
||||||
|
local tA = {...}
|
||||||
|
local out = table.remove(tA,#tA)
|
||||||
|
local f,e = io.open(out,"wb")
|
||||||
|
if not f then error("unable to open file "..out..": "..e) end
|
||||||
|
f:write(preproc.preproc(table.unpack(tA)))
|
||||||
|
f:close()
|
||||||
|
end})
|
@ -1,162 +0,0 @@
|
|||||||
local vcomponent = require "vcomponent"
|
|
||||||
local serial = require "serialization"
|
|
||||||
local component = require "component"
|
|
||||||
local computer = require "computer"
|
|
||||||
local event = require "event"
|
|
||||||
local imt = require "interminitel"
|
|
||||||
|
|
||||||
local cfg = {}
|
|
||||||
cfg.peers = {}
|
|
||||||
cfg.rtimer = 5
|
|
||||||
cfg.katimer = 30
|
|
||||||
local listeners = {}
|
|
||||||
local proxies = {}
|
|
||||||
|
|
||||||
local function loadcfg()
|
|
||||||
local f = io.open("/boot/cfg/vtunnel.cfg","rb")
|
|
||||||
if not f then return false end
|
|
||||||
for k,v in pairs(serial.unserialize(f:read("*a")) or {}) do
|
|
||||||
cfg[k] = v
|
|
||||||
end
|
|
||||||
f:close()
|
|
||||||
end
|
|
||||||
local function savecfg()
|
|
||||||
local f = io.open("/boot/cfg/vtunnel.cfg","wb")
|
|
||||||
if not f then
|
|
||||||
print("Warning: unable to save configuration.")
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
f:write(serial.serialize(cfg))
|
|
||||||
f:close()
|
|
||||||
end
|
|
||||||
|
|
||||||
local function createTunnel(host,port,addr,raddr)
|
|
||||||
local proxy = {address=addr,buffer=""}
|
|
||||||
function proxy.connect()
|
|
||||||
if proxy.socket then
|
|
||||||
proxy.socket.close()
|
|
||||||
end
|
|
||||||
proxy.socket = component.invoke(component.list("internet")(),"connect",host,port)
|
|
||||||
local st = computer.uptime()
|
|
||||||
repeat
|
|
||||||
coroutine.yield()
|
|
||||||
until proxy.socket.finishConnect() or computer.uptime() > st+5
|
|
||||||
end
|
|
||||||
function proxy.send(...)
|
|
||||||
rt = 0
|
|
||||||
while not proxy.socket.write(imt.encodePacket(...)) and rt < 10 do
|
|
||||||
proxy.connect()
|
|
||||||
rt = rt + 1
|
|
||||||
end
|
|
||||||
proxy.last = computer.uptime()
|
|
||||||
end
|
|
||||||
function proxy.read()
|
|
||||||
local rb, r
|
|
||||||
local rt = 0
|
|
||||||
while true do
|
|
||||||
rb,r = proxy.socket.read(4096)
|
|
||||||
if rb or rt > 10 then break end
|
|
||||||
if type(rb) == "nil" then
|
|
||||||
proxy.connect()
|
|
||||||
end
|
|
||||||
rt = rt + 1
|
|
||||||
end
|
|
||||||
proxy.buffer = proxy.buffer .. rb
|
|
||||||
while imt.decodePacket(proxy.buffer) do
|
|
||||||
computer.pushSignal("modem_message",addr,raddr,0,0,imt.decodePacket(proxy.buffer))
|
|
||||||
proxy.buffer = imt.getRemainder(proxy.buffer) or ""
|
|
||||||
end
|
|
||||||
if computer.uptime() > proxy.last + cfg.katimer then
|
|
||||||
proxy.socket.write("\0\1\0")
|
|
||||||
proxy.last = computer.uptime()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function proxy.getWakeMessage()
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
proxy.setWakeMessage = proxy.getWakeMessage
|
|
||||||
function proxy.maxPacketSize()
|
|
||||||
return 8192
|
|
||||||
end
|
|
||||||
function proxy.getChannel()
|
|
||||||
return host..":"..tostring(port)
|
|
||||||
end
|
|
||||||
proxy.connect()
|
|
||||||
proxy.last = computer.uptime()
|
|
||||||
return proxy
|
|
||||||
end
|
|
||||||
|
|
||||||
vt = {}
|
|
||||||
function start()
|
|
||||||
loadcfg()
|
|
||||||
for k,v in pairs(cfg.peers) do
|
|
||||||
print(string.format("Connecting to %s:%d",v.host,v.port))
|
|
||||||
v.addr = v.addr or vcomponent.uuid()
|
|
||||||
v.raddr = v.raddr or vcomponent.uuid()
|
|
||||||
local px = createTunnel(v.host, v.port, v.addr, v.raddr)
|
|
||||||
vcomponent.register(v.addr, "tunnel", px)
|
|
||||||
proxies[v.addr] = px
|
|
||||||
end
|
|
||||||
for k,v in pairs(os.tasks()) do
|
|
||||||
if os.taskInfo(v).name:match("minitel") then
|
|
||||||
os.kill(v)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function vt.stop()
|
|
||||||
for k,v in pairs(proxies) do
|
|
||||||
vcomponent.unregister(k)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function vt.listpeers()
|
|
||||||
for k,v in pairs(cfg.peers) do
|
|
||||||
print(string.format("#%d (%s:%d)\n Local address: %s\n Remote address: %s",k,v.host,v.port,v.addr,v.raddr))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function vt.addpeer(host,port)
|
|
||||||
port = tonumber(port) or 4096
|
|
||||||
local t = {}
|
|
||||||
t.host = host
|
|
||||||
t.port = port
|
|
||||||
t.addr = vcomponent.uuid()
|
|
||||||
t.raddr = vcomponent.uuid()
|
|
||||||
cfg.peers[#cfg.peers+1] = t
|
|
||||||
print(string.format("Added peer #%d (%s:%d) to the configuration.\nRestart to apply changes.",#cfg.peers,host,port))
|
|
||||||
savecfg()
|
|
||||||
end
|
|
||||||
function vt.delpeer(n)
|
|
||||||
n=tonumber(n)
|
|
||||||
if not n then
|
|
||||||
print("delpeer requires a number, representing the peer number, as an argument.")
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
local dp = table.remove(cfg.peers, n)
|
|
||||||
savecfg()
|
|
||||||
print(string.format("Removed peer %s:%d",dp.host, dp.port))
|
|
||||||
end
|
|
||||||
|
|
||||||
function vt.settimer(time)
|
|
||||||
time = tonumber(time)
|
|
||||||
if not time then
|
|
||||||
print("Timer must be a number.")
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
cfg.rtime = time
|
|
||||||
savecfg()
|
|
||||||
end
|
|
||||||
|
|
||||||
vt.start = start
|
|
||||||
_G.libs.vtunnel = vt
|
|
||||||
|
|
||||||
start()
|
|
||||||
local last = computer.uptime()
|
|
||||||
while true do
|
|
||||||
local tE = {coroutine.yield()}
|
|
||||||
if computer.uptime() > last + cfg.rtimer then
|
|
||||||
for k,v in pairs(proxies) do
|
|
||||||
v.read()
|
|
||||||
end
|
|
||||||
last = computer.uptime()
|
|
||||||
end
|
|
||||||
end
|
|
Loading…
Reference in New Issue
Block a user