mirror of
https://github.com/20kdc/OC-KittenOS.git
synced 2024-11-08 19:48:07 +11:00
339 lines
7.5 KiB
Lua
339 lines
7.5 KiB
Lua
|
-- This is released into the public domain.
|
||
|
-- No warranty is provided, implied or otherwise.
|
||
|
|
||
|
-- app-claw: Package manager.
|
||
|
|
||
|
-- HTTP-only because OCEmu SUCKS
|
||
|
local source = "http://20kdc.duckdns.org/neo/"
|
||
|
|
||
|
local primaryINet = neo.requestAccess("c.internet")
|
||
|
if primaryINet then primaryINet = primaryINet.list()() end
|
||
|
|
||
|
local function pkgExists(pkg, isApp)
|
||
|
local b = {}
|
||
|
if isApp then
|
||
|
b = neo.listApps()
|
||
|
else
|
||
|
b = neo.listLibs()
|
||
|
end
|
||
|
for _, v in ipairs(b) do
|
||
|
if v == pkg then return true end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- global app variables
|
||
|
-- elements:
|
||
|
-- {
|
||
|
-- description,
|
||
|
-- dlURL/nil,
|
||
|
-- localPath,
|
||
|
-- isApp,
|
||
|
-- }
|
||
|
local packages = {}
|
||
|
local packageList = {}
|
||
|
local libList = {} -- removed after scan
|
||
|
local windows = 1
|
||
|
local searchTx = ""
|
||
|
local primaryWindowRegen
|
||
|
--
|
||
|
|
||
|
local event = require("event")(neo)
|
||
|
local neoux, err = require("neoux")
|
||
|
if not neoux then error(err) end
|
||
|
neoux = neoux(event, neo)
|
||
|
|
||
|
local function download(url)
|
||
|
if not primaryINet then return nil, "no internet" end
|
||
|
local req, err = primaryINet.request(url)
|
||
|
if not req then
|
||
|
return nil, tostring(err)
|
||
|
end
|
||
|
local ok, err = req.finishConnect()
|
||
|
if not req.finishConnect() then
|
||
|
req.close()
|
||
|
return nil, tostring(err)
|
||
|
end
|
||
|
local dt = ""
|
||
|
while true do
|
||
|
local n, n2 = req.read()
|
||
|
if not n then
|
||
|
req.close()
|
||
|
if n2 then
|
||
|
return nil, n2
|
||
|
else
|
||
|
break
|
||
|
end
|
||
|
else
|
||
|
if n == "" then
|
||
|
-- slightly dangerous, but what can we do?
|
||
|
event.sleepTo(os.uptime() + 0.05)
|
||
|
end
|
||
|
dt = dt .. n
|
||
|
end
|
||
|
end
|
||
|
req.close()
|
||
|
return dt
|
||
|
end
|
||
|
|
||
|
local function readLocal()
|
||
|
-- Read apps & libs
|
||
|
local function isLua(v)
|
||
|
if v:sub(#v - 3) == ".lua" then
|
||
|
return v:sub(1, #v - 4)
|
||
|
end
|
||
|
end
|
||
|
for _, pkg in ipairs(neo.listApps()) do
|
||
|
table.insert(packageList, pkg)
|
||
|
packages[pkg] = {
|
||
|
"A pre-installed or self-written process.",
|
||
|
nil,
|
||
|
"apps/" .. pkg .. ".lua",
|
||
|
true
|
||
|
}
|
||
|
end
|
||
|
for _, pkg in ipairs(neo.listLibs()) do
|
||
|
table.insert(libList, pkg)
|
||
|
packages[pkg] = {
|
||
|
"A pre-installed or self-written library.",
|
||
|
nil,
|
||
|
"libs/" .. pkg .. ".lua",
|
||
|
false
|
||
|
}
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function getEntry(name, isApp)
|
||
|
if packages[name] then
|
||
|
if packages[name][4] ~= isApp then
|
||
|
return
|
||
|
end
|
||
|
else
|
||
|
local path = "libs/" .. name .. ".lua"
|
||
|
if isApp then
|
||
|
path = "apps/" .. name .. ".lua"
|
||
|
end
|
||
|
packages[name] = {"An unknown entry, lost to time.", nil, path, isApp}
|
||
|
if isApp then
|
||
|
table.insert(packageList, name)
|
||
|
else
|
||
|
table.insert(libList, name)
|
||
|
end
|
||
|
end
|
||
|
return packages[name]
|
||
|
end
|
||
|
|
||
|
local function readWeb()
|
||
|
local listData, err = download(source .. "list")
|
||
|
if not listData then
|
||
|
neoux.startDialog("Couldn't get web index: " .. err, "web", true)
|
||
|
return
|
||
|
end
|
||
|
--neoux.startDialog(listData, "web", false)
|
||
|
listData = (listData .. "\n"):gmatch(".-\n")
|
||
|
local function listDataStrip()
|
||
|
local l = listData()
|
||
|
if not l then
|
||
|
return
|
||
|
end
|
||
|
l = l:sub(1, #l - 1)
|
||
|
return l
|
||
|
end
|
||
|
while true do
|
||
|
local l = listDataStrip()
|
||
|
if not l then return end
|
||
|
if l == "end" then return end
|
||
|
local ent = getEntry(l:sub(5), l:sub(1, 4) == "app ")
|
||
|
if ent then
|
||
|
ent[1] = listDataStrip() or "PARSE ERROR"
|
||
|
ent[2] = source .. l:sub(5) .. ".lua"
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
readLocal()
|
||
|
if source then
|
||
|
readWeb()
|
||
|
end
|
||
|
|
||
|
table.sort(packageList)
|
||
|
table.sort(libList)
|
||
|
for _, v in ipairs(libList) do
|
||
|
table.insert(packageList, v)
|
||
|
end
|
||
|
libList = nil
|
||
|
|
||
|
local function startPackageWindow(pkg)
|
||
|
windows = windows + 1
|
||
|
local downloading = false
|
||
|
local desc = packages[pkg][1]
|
||
|
local isApp = packages[pkg][4]
|
||
|
local isSysSvc = isApp and (pkg:sub(1, 4) == "sys-")
|
||
|
local isSvc = isSysSvc or (isApp and (pkg:sub(1, 4) == "svc-"))
|
||
|
local settings
|
||
|
if isSvc then
|
||
|
settings = neo.requestAccess("x.neo.sys.manage")
|
||
|
end
|
||
|
local function update(w)
|
||
|
if downloading then return end
|
||
|
downloading = true
|
||
|
local fd = download(packages[pkg][2])
|
||
|
local msg = "Success!"
|
||
|
if fd then
|
||
|
local primaryDisk = neo.requestAccess("c.filesystem").primary
|
||
|
local f = primaryDisk.open(packages[pkg][3], "wb")
|
||
|
primaryDisk.write(f, fd)
|
||
|
primaryDisk.close(f)
|
||
|
else
|
||
|
msg = "Couldn't download."
|
||
|
end
|
||
|
w.close()
|
||
|
windows = windows - 1
|
||
|
primaryWindowRegen()
|
||
|
-- Another event loop so the program won't exit too early.
|
||
|
neoux.startDialog(msg, pkg, true)
|
||
|
downloading = false
|
||
|
end
|
||
|
|
||
|
local elems = {
|
||
|
neoux.tcrawview(1, 1, neoux.fmtText(unicode.safeTextFormat(desc), 30)),
|
||
|
}
|
||
|
-- {txt, run}
|
||
|
local buttonbar = {}
|
||
|
if pkgExists(pkg, isApp) then
|
||
|
if isApp then
|
||
|
if not isSvc then
|
||
|
table.insert(buttonbar, {"Start", function (w)
|
||
|
neo.executeAsync(pkg)
|
||
|
w.close()
|
||
|
windows = windows - 1
|
||
|
end})
|
||
|
else
|
||
|
if not isSysSvc then
|
||
|
table.insert(buttonbar, {"Start", function (w)
|
||
|
neo.executeAsync(pkg)
|
||
|
w.close()
|
||
|
windows = windows - 1
|
||
|
end})
|
||
|
end
|
||
|
if settings.getSetting("run." .. pkg) == "yes" then
|
||
|
table.insert(buttonbar, {"Disable", function (w)
|
||
|
settings.setSetting("run." .. pkg, "no")
|
||
|
w.close()
|
||
|
windows = windows - 1
|
||
|
end})
|
||
|
else
|
||
|
table.insert(buttonbar, {"Enable", function (w)
|
||
|
settings.setSetting("run." .. pkg, "yes")
|
||
|
w.close()
|
||
|
windows = windows - 1
|
||
|
end})
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
if packages[pkg][2] then
|
||
|
table.insert(buttonbar, {"Update", update})
|
||
|
end
|
||
|
table.insert(buttonbar, {"Delete", function (w)
|
||
|
local primaryDisk = neo.requestAccess("c.filesystem").primary
|
||
|
primaryDisk.remove(packages[pkg][3])
|
||
|
w.close()
|
||
|
windows = windows - 1
|
||
|
primaryWindowRegen()
|
||
|
end})
|
||
|
else
|
||
|
if packages[pkg][2] then
|
||
|
table.insert(buttonbar, {"Install", update})
|
||
|
end
|
||
|
end
|
||
|
local x = 1
|
||
|
for _, v in ipairs(buttonbar) do
|
||
|
local b = neoux.tcbutton(x, 10, v[1], v[2])
|
||
|
x = x + (#v[1]) + 2
|
||
|
table.insert(elems, b)
|
||
|
end
|
||
|
neoux.create(30, 10, pkg, neoux.tcwindow(30, 10, elems, function (w)
|
||
|
w.close()
|
||
|
windows = windows - 1
|
||
|
end, 0xFFFFFF, 0))
|
||
|
end
|
||
|
|
||
|
local genwin, primaryWindow
|
||
|
local primaryWindowPage = 1
|
||
|
local primaryWindowList = packageList
|
||
|
|
||
|
function primaryWindowRegen()
|
||
|
primaryWindow.reset(20, 8, genwin(primaryWindowPage, primaryWindowList))
|
||
|
end
|
||
|
|
||
|
genwin = function (page, efList)
|
||
|
local pages = math.ceil(#efList / 6)
|
||
|
local elems = {
|
||
|
neoux.tcbutton(18, 1, "+", function (w)
|
||
|
if page < pages then
|
||
|
primaryWindowPage = page + 1
|
||
|
primaryWindowRegen()
|
||
|
end
|
||
|
end),
|
||
|
neoux.tcrawview(4, 1, {neoux.pad(page .. " / " .. pages, 14, true, true)}),
|
||
|
neoux.tcbutton(1, 1, "-", function (w)
|
||
|
if page > 1 then
|
||
|
primaryWindowPage = page - 1
|
||
|
primaryWindowRegen()
|
||
|
end
|
||
|
end)
|
||
|
}
|
||
|
local base = (page - 1) * 6
|
||
|
for i = 1, 6 do
|
||
|
local ent = efList[base + i]
|
||
|
if ent then
|
||
|
local enttx = ent
|
||
|
if packages[ent][4] then
|
||
|
enttx = "A " .. enttx
|
||
|
else
|
||
|
enttx = "L " .. enttx
|
||
|
end
|
||
|
if pkgExists(ent, packages[ent][4]) then
|
||
|
if packages[ent][2] then
|
||
|
enttx = "I" .. enttx
|
||
|
else
|
||
|
enttx = "i" .. enttx
|
||
|
end
|
||
|
else
|
||
|
enttx = " " .. enttx
|
||
|
end
|
||
|
table.insert(elems, neoux.tcbutton(1, i + 1, unicode.safeTextFormat(enttx), function (w)
|
||
|
-- Start a dialog
|
||
|
startPackageWindow(ent)
|
||
|
end))
|
||
|
end
|
||
|
end
|
||
|
table.insert(elems, neoux.tcfield(1, 8, 11, function (s)
|
||
|
if s then searchTx = s end
|
||
|
return searchTx
|
||
|
end))
|
||
|
table.insert(elems, neoux.tcbutton(12, 8, "Search!", function (w)
|
||
|
local n = {}
|
||
|
for _, v in ipairs(packageList) do
|
||
|
for i = 1, #v do
|
||
|
if v:sub(i, i + #searchTx - 1) == searchTx then
|
||
|
table.insert(n, v)
|
||
|
break
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
primaryWindowPage = 1
|
||
|
primaryWindowList = n
|
||
|
primaryWindowRegen()
|
||
|
end))
|
||
|
return neoux.tcwindow(20, 8, elems, function (w)
|
||
|
w.close()
|
||
|
windows = windows - 1
|
||
|
end, 0xFFFFFF, 0)
|
||
|
end
|
||
|
|
||
|
primaryWindow = neoux.create(20, 8, "claw", genwin(1, packageList))
|
||
|
|
||
|
while windows > 0 do
|
||
|
event.pull()
|
||
|
end
|