1
1
mirror of https://git.shadowkat.net/izaya/OC-PsychOS2.git synced 2024-11-24 20:27:39 -05:00

Compare commits

..

8 Commits

5 changed files with 331 additions and 19 deletions

123
lib/download.lua Normal file
View File

@ -0,0 +1,123 @@
local net = require "minitel"
local dl = {}
dl.protos = {}
-- Stolen from the old exec/fget
local function parseURL(url)
local proto,addr = url:match("(.-)://(.+)")
addr = addr or url
local hp, path = addr:match("(.-)(/.*)")
hp, path = hp or addr, path or "/"
local host, port = hp:match("(.+):(.+)")
host = host or hp
return proto, host, port, path
end
function dl.protos.fget(host, optPort, path, dest) -- string string string number -- boolean -- Downloads path from host (on optPort or 70), printing the directory listing, or saving the file to dest.
local socket = assert(net.open(host, optPort or 70))
socket:write(string.format("t%s\n", path))
local status
repeat
coroutine.yield()
status = socket:read(1)
until status ~= ""
if status == "d" then
io.write("Directory Listing:\n")
local tmp = ""
repeat
coroutine.yield()
tmp = socket:read("*a")
io.write(tmp)
until socket.state == "closed" and tmp == ""
return true
elseif status == "y" then
if not dest then
error("Must provide local path to save remote files.")
end
io.write(string.format("Saving %s to %s...\n", path, dest))
local f = assert(io.open(dest, "wb"))
local tmp = ""
repeat
coroutine.yield()
tmp = socket:read("*a")
f:write(tmp)
until socket.state == "closed" and tmp == ""
f:close()
print("Done.")
return true
else
local err, tmp = "", ""
repeat
coroutine.yield()
tmp = socket:read("*a")
err = err .. tmp
until socket.state == "closed" and tmp == ""
error(string.format("Got error from remote host: %s", err))
end
end
function dl.protos.http(host, optPort, path, dest, url) -- string string string number -- boolean -- Downloads *url* to *dest* via the internet card, if available.
if not component.list("internet")() then
print("Internet card unavailable, falling back to proxy.")
local proto,host,sPort,path = parseURL(url)
local proxy = os.getenv(proto:upper().."_PROXY")
if not proxy and fs.exists("/boot/cfg/"..proto.."_proxy") then
local f = io.open("/boot/cfg/"..proto.."_proxy","rb")
proxy = f:read()
f:close()
end
if not proxy then error("No internet card or HTTP(S) proxy available") end
print("Proxy found: "..proxy)
if optPort then host=string.format("%s:%i",host,optPort) end
return dl.wget(string.format("%s/%s%s",proxy,host,path),dest)
end
if not dest then
error("Must provide local path to save remote files.")
end
local R,r=component.invoke(component.list("internet")(),"request",url)
if not R then error(r) end
repeat
coroutine.yield()
until R.finishConnect()
local code, message, headers = R.response()
if code > 299 or code < 200 then
return false, code, message
end
local f=io.open(dest,"wb")
if not f then error("Unable to open file "..dest) end
io.write(string.format("Saving %s to %s...\n", url, dest))
repeat
coroutine.yield()
ns = R.read(2048)
f:write(ns or "")
until not ns
f:close()
print("Done.")
return true
end
dl.protos.https = dl.protos.http
function dl.wget(remotePath, dest) -- string string -- -- Downloads from remote *remotePath* to *dest*
local proto, host, sPort, path = parseURL(remotePath)
if dl.protos[proto] then
local port
if sPort then
port = tonumber(sPort)
end
dl.protos[proto](host, port, path, dest, remotePath)
else
error("Unsupported protocol: " .. tostring(proto))
end
end
return setmetatable(dl,{__call=function(_,path,dest) return dl.wget(path,dest) end})

View File

@ -3,6 +3,7 @@ local w, lz16 = pcall(require, "liblz16")
if not w then lz16 = nil end if not w then lz16 = nil end
pkgfs = {} pkgfs = {}
pkgfs.files = {}
local findex = {} local findex = {}
local handles = {} local handles = {}
local hc = 0 local hc = 0
@ -98,17 +99,37 @@ function pkgfs.component.close(handle)
return true return true
end end
function pkgfs.add(fname,comp) -- string boolean -- -- Add a package as specified in *fname* to the pkgfs component. If *comp* is true, read it as a LZ16-compressed package. local function index()
if fname:sub(1,1) ~= "/" then findex = {}
fname = "/"..fnormalize(os.getenv("PWD").."/"..fname) for k,v in pairs(pkgfs.files) do
fname, comp = v[1], v[2]
if fname:sub(1,1) ~= "/" then
fname = "/"..fnormalize(os.getenv("PWD").."/"..fname)
end
local f = fopen(fname,comp)
if not f then error("unable to open file") end
print(fname)
for name, read, fsize in mtar.iter(f) do
findex[fnormalize(name)] = {fname,comp}
end
f:close()
end end
local f = fopen(fname,comp) return true
if not fname then error("unable to open file") end
print(fname)
for name, read, fsize in mtar.iter(f) do
findex[fnormalize(name)] = {fname,comp}
end
f:close()
end end
function pkgfs.add(fname,comp) -- string boolean -- boolean -- Add a package as specified in *fname* to the pkgfs component. If *comp* is true, read it as a LZ16-compressed package.
pkgfs.files[#pkgfs.files+1] = {fname,comp}
return index()
end
function pkgfs.remove(fname) -- string -- boolean -- Removes the package specified by *fname* from the pkgfs index.
for k,v in pairs(pkgfs.files) do
if v[1] == fname then
table.remove(pkgfs.files,k)
end
end
return index()
end
fs.makeDirectory("/pkg")
fs.mount("/pkg",pkgfs.component)
return pkgfs return pkgfs

152
lib/pkgman.lua Normal file
View File

@ -0,0 +1,152 @@
local serial = require "serialization"
local dl = require "download"
local pkg = {}
pkg.cfgPath = "/boot/cfg/pkg"
pkg.sourcePath = pkg.cfgPath .. "/sources.cfg"
pkg.installedPath = pkg.cfgPath .. "/installed.cfg"
local function getSources()
local f = io.open(pkg.sourcePath,"rb")
if not f then return {} end
local c = f:read("*a")
f:close()
return serial.unserialize(c)
end
local function saveSources(t)
fs.makeDirectory(pkg.cfgPath)
local f = io.open(pkg.sourcePath,"wb")
f:write(serial.serialize(t))
f:close()
end
local function getInstalled()
local f = io.open(pkg.installedPath,"rb")
if not f then return {} end
local c = f:read("*a")
f:close()
return serial.unserialize(c)
end
local function saveInstalled(t)
fs.makeDirectory(pkg.cfgPath)
local f = io.open(pkg.installedPath,"wb")
if not f then return false end
f:write(serial.serialize(t))
f:close()
end
local function getRepoMeta(repo)
if not getSources()[repo].cache or not fs.exists("/boot/cfg/pkg/repo-"..repo..".cfg") then
dl(getSources()[repo].path.."/packages.cfg","/boot/cfg/pkg/repo-"..repo..".cfg")
end
local f = io.open("/boot/cfg/pkg/repo-"..repo..".cfg","rb")
local rt = serial.unserialize(f:read("*a"))
f:close()
if not getSources()[repo].cache then
fs.remove("/boot/cfg/pkg/repo-"..repo..".cfg")
end
return rt
end
local function activatePackage(path,compressed)
require("pkgfs").add(path,compressed)
end
local function deactivatePackage(path)
require("pkgfs").remove(path)
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.
local sources = getSources()
sources[name] = {path=path,cache=cache,name=name}
saveSources(sources)
end
function pkg.delRepo(name) -- string -- boolean -- Removes a repository from the list of repositories.
local sources = getSources()
sources[name] = nil
saveSources(sources)
end
function pkg.update() -- Re-download cached repository indexes.
for repo,meta in pairs(getSources()) do
fs.remove("/boot/cfg/pkg/repo-"..repo..".cfg")
if meta.cache then
getRepoMeta(repo)
end
end
end
function pkg.list(filter) -- string -- -- Print a list of available packages matching *filter*.
filter = filter or ""
local pkglist = {}
for repo,_ in pairs(getSources()) do
for pkg,meta in pairs(getRepoMeta(repo)) do
if pkg:find(filter) or (pkg.meta or ""):find(filter) then
meta.repo = repo
pkglist[pkg] = meta
end
end
end
for k,v in pairs(pkglist) do
print(string.format("%s/%s\n %s",v.repo,k,v.description))
end
end
function pkg.getMeta(pkgname) -- string -- table -- Returns the metadata for a the package specified in *pkgname*.
print("Finding package "..pkgname)
for repo,info in pairs(getSources()) do
local pkg = getRepoMeta(repo)[pkgname]
if pkg then
print("Package "..pkgname.." located in repo "..repo.." at "..info.path)
pkg.repository = info
return pkg
end
end
end
function pkg.get(pkgname,auto) -- string boolean -- boolean -- Downloads and mounts a package, identified as *pkgname*, onto the pkgfs.
local pkginfo = pkg.getMeta(pkgname)
if not pkginfo then error("unable to locate package "..pkgname) end
pkginfo.manual = not auto
fs.makeDirectory("/boot/pkg")
for k,v in ipairs(pkginfo.dependencies or {}) do
if not getInstalled()[v] then
pkg.get(v)
end
end
dl(pkginfo.repository.path.."/"..pkginfo.filename,"/boot/pkg/"..pkginfo.filename)
local installed = getInstalled()
installed[pkgname] = pkginfo
saveInstalled(installed)
pcall(activatePackage,"/boot/pkg/"..pkginfo.filename,pkginfo.compressed)
return true
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.
pkg.update()
fs.makeDirectory("/boot/pkg")
local installed = getInstalled()
for repo,info in pairs(getSources()) do
for pkgname,pkg in pairs(getRepoMeta(repo)) do
if pkg.version ~= installed[pkgname].version or force then
dl(info.path.."/"..pkg.filename,"/boot/pkg/"..pkg.filename)
installed[pkgname] = pkg
pcall(activatePackage,"/boot/pkg/"..pkg.filename,pkg.compressed)
return true
end
end
end
saveInstalled(installed)
end
function pkg.remove(pkgname) -- string -- boolean -- Remove the package *pkgname* from the pkgfs and package directory.
local installed = getInstalled()
local pkginfo = installed[pkgname]
if not pkginfo then error(pkgname .." not installed") end
pcall(deactivatePackage,"/boot/pkg/"..pkginfo.filename)
fs.remove("/boot/pkg/"..pkginfo.filename)
installed[pkgname] = nil
saveInstalled(installed)
return true
end
return pkg

View File

@ -68,7 +68,11 @@ function fs.copy(from,to) -- string string -- boolean -- copies a file from *fro
if not of or not df then if not of or not df then
return false return false
end end
df:write(of:read("*a")) local tmp
repeat
tmp = of:read(2048)
df:write(tmp or "")
until not tmp
df:close() df:close()
of:close() of:close()
return true return true

View File

@ -3,12 +3,14 @@ local serial = require "serialization"
local cfg = {["path"]="/boot/srv/frequest",["port"]=70} local cfg = {["path"]="/boot/srv/frequest",["port"]=70}
f=io.open("/boot/cfg/fserv.cfg","rb") local function loadConfig(cfgpath)
if f then local f=io.open(cfgpath or "/boot/cfg/fserv.cfg","rb")
local ncfg = serial.unserialize(f:read("*a")) if f then
f:close() local ncfg = serial.unserialize(f:read("*a"))
for k,v in pairs(ncfg) do f:close()
cfg[k] = v for k,v in pairs(ncfg) do
cfg[k] = v
end
end end
end end
@ -61,6 +63,7 @@ local function httpHandler(socket,rtype,path)
if code < 200 or code > 299 then if code < 200 or code > 299 then
socket:write(string.format("f%d\n%s",code,message)) socket:write(string.format("f%d\n%s",code,message))
else else
socket:write("y")
local data = "" local data = ""
repeat repeat
coroutine.yield() coroutine.yield()
@ -90,6 +93,15 @@ local function socketHandler(socket)
end end
end end
while true do local function fileServer()
os.spawn(socketHandler(minitel.listen(70)),"fserv worker process") while true do
os.spawn(socketHandler(minitel.listen(70)),"fserv worker process")
end
end end
function start(cfgpath)
loadConfig(cfgpath)
return os.spawn(fileServer,"fserv")
end
return {start=start}