Just make everything *better*.

This commit is contained in:
20kdc 2018-03-27 14:40:05 +01:00
parent 36afa760c4
commit c2b373f261
19 changed files with 616 additions and 385 deletions

View File

@ -3,59 +3,48 @@
-- 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
--
-- libs & such
local event = require("event")(neo)
local neoux, err = require("neoux")
if not neoux then error(err) end
neoux = neoux(event, neo)
local claw = require("claw")()
local function download(url)
-- HTTP-only because OCEmu SUCKS
local source = "http://20kdc.duckdns.org/neo/"
local disks = neo.requireAccess("c.filesystem", "searching disks for packages")
local primaryDisk = disks.primary
local primaryINet = neo.requestAccess("c.internet")
if primaryINet then primaryINet = primaryINet.list()() end
--
local function yielder()
-- slightly dangerous, but what can we do?
event.sleepTo(os.uptime() + 0.05)
end
local function download(url, cb)
if not primaryINet then return nil, "no internet" end
local req, err = primaryINet.request(url)
local req, err = primaryINet.request(source .. url)
if not req then
cb(nil)
return nil, tostring(err)
end
local ok, err = req.finishConnect()
if not req.finishConnect() then
req.close()
cb(nil)
return nil, tostring(err)
end
local dt = ""
while true do
local n, n2 = req.read()
local o, r = cb(n)
if not o then
req.close()
return nil, r
end
if not n then
req.close()
if n2 then
@ -65,274 +54,280 @@ local function download(url)
end
else
if n == "" then
-- slightly dangerous, but what can we do?
event.sleepTo(os.uptime() + 0.05)
yielder()
end
dt = dt .. n
end
end
req.close()
return dt
return true
end
local function readLocal()
-- Read apps & libs
local function isLua(v)
if v:sub(#v - 3) == ".lua" then
return v:sub(1, #v - 4)
local function fsSrc(disk)
return function (url, cb)
local h, e = disk.open(url, "rb")
if not h then cb(nil) return nil, tostring(e) end
local c = ""
while c do
c = disk.read(h, neo.readBufSize)
local o, r = cb(c)
if not o then return nil, r end
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
}
disk.close(h)
return true
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})
local function fsDst(disk)
return {function (url)
local h, e = disk.open(url, "wb")
if not h then return nil, tostring(e) end
return function (d)
local ok, r = true
if d then
ok, r = disk.write(h, d)
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
disk.close(h)
end
if not ok then return nil, tostring(r) end
return true
end
if packages[pkg][2] then
table.insert(buttonbar, {"Update", update})
end, disk.makeDirectory, disk.exists, disk.isDirectory, disk.remove, disk.rename}
end
local function checked(...)
local res, res2, err = pcall(...)
if not res then
neoux.startDialog(tostring(res2), "error!", true)
elseif not res2 then
neoux.startDialog(tostring(err), "failed!", true)
else
return res2
end
end
-- Beginning Of The App (well, the actual one)
local genCurrent, genPrimary, genPackage, primaryWindow
local windows = 1
-- primary
local primarySearchTx = ""
local primaryPage = 1
local primaryList = {}
-- package
local packageLock = nil
local packageId = "FIXME"
local function describe(pkg)
local weHave = claw.getInfo(pkg, "local")
local theyHave = claw.getInfo(pkg, "local")
local someoneHas = claw.getInfo(pkg, nil, true)
if weHave then
if theyHave.v > weHave.v then
return pkg .. " [v" .. weHave.v .. "!]"
end
table.insert(buttonbar, {"Delete", function (w)
local primaryDisk = neo.requestAccess("c.filesystem").primary
primaryDisk.remove(packages[pkg][3])
if someoneHas.v < weHave.v then
return pkg .. " (v" .. weHave.v .. ") R<"
end
return pkg .. " (v" .. weHave.v .. ")"
end
return pkg
end
local function primaryWindowRegenCore()
return neoux.tcwindow(25, 12, genCurrent(), function (w)
w.close()
windows = windows - 1
primaryWindowRegen()
end})
else
if packages[pkg][2] then
table.insert(buttonbar, {"Install", update})
end, 0xFF8F00, 0)
end
local function primaryWindowRegen()
primaryWindow.reset(25, 12, primaryWindowRegenCore())
end
-- Use all non-primary filesystems
for pass = 1, 3 do
for v in disks.list() do
local nam = nil
if v == primaryDisk then
nam = (pass == 1) and "local"
elseif v == disks.temporary then
nam = (pass == 2) and "ramfs"
elseif pass == 3 then
nam = v.address
end
if nam then
local ok, r = claw.addSource(nam, fsSrc(v), (not v.isReadOnly()) and fsDst(v))
if not ok and nam == "local" then
claw.unlock()
error(r)
end
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))
if primaryINet then
checked(claw.addSource, "inet", download)
end
genwin = function (page, efList)
local pages = math.ceil(#efList / 6)
primaryList = claw.getList()
-- Sections
function genPrimary()
local pgs = 10
local pages = math.ceil(#primaryList / pgs)
local elems = {
neoux.tcbutton(18, 1, "+", function (w)
if page < pages then
primaryWindowPage = page + 1
neoux.tcbutton(23, 1, "+", function (w)
if primaryPage < pages then
primaryPage = primaryPage + 1
primaryWindowRegen()
end
end),
neoux.tcrawview(4, 1, {neoux.pad(page .. " / " .. pages, 14, true, true)}),
neoux.tcrawview(4, 1, {neoux.pad(primaryPage .. " / " .. pages, 19, true, true)}),
neoux.tcbutton(1, 1, "-", function (w)
if page > 1 then
primaryWindowPage = page - 1
if primaryPage > 1 then
primaryPage = primaryPage - 1
primaryWindowRegen()
end
end)
}
local base = (page - 1) * 6
for i = 1, 6 do
local ent = efList[base + i]
local base = (primaryPage - 1) * pgs
for i = 1, pgs do
local ent = primaryList[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
local enttx = describe(ent)
table.insert(elems, neoux.tcbutton(1, i + 1, unicode.safeTextFormat(enttx), function (w)
-- Start a dialog
startPackageWindow(ent)
packageId = ent
genCurrent = genPackage
primaryWindowRegen()
end))
end
end
table.insert(elems, neoux.tcfield(1, 8, 11, function (s)
if s then searchTx = s end
return searchTx
table.insert(elems, neoux.tcfield(1, 12, 16, function (s)
if s then primarySearchTx = s end
return primarySearchTx
end))
table.insert(elems, neoux.tcbutton(12, 8, "Search!", function (w)
table.insert(elems, neoux.tcbutton(17, 12, "Search!", function (w)
local n = {}
for _, v in ipairs(packageList) do
for _, v in ipairs(claw.getList()) do
for i = 1, #v do
if v:sub(i, i + #searchTx - 1) == searchTx then
if v:sub(i, i + #primarySearchTx - 1) == primarySearchTx then
table.insert(n, v)
break
end
end
end
primaryWindowPage = 1
primaryWindowList = n
primaryPage = 1
primaryList = n
primaryWindowRegen()
end))
return neoux.tcwindow(20, 8, elems, function (w)
w.close()
windows = windows - 1
end, 0xFFFFFF, 0)
return elems
end
primaryWindow = neoux.create(20, 8, "claw", genwin(1, packageList))
--
local function packageGetBB(src, lclI, srcI, srcW)
local buttons = {}
if srcI and srcW then
table.insert(buttons, {
"Del",
function ()
if packageLock then return end
packageLock = ""
checked(claw.remove, src, packageId, true)
packageLock = nil
primaryWindowRegen()
end
})
end
if srcI and ((not lclI) or (lclI.v < srcI.v)) then
table.insert(buttons, {
"Get",
function ()
if packageLock then return end
packageLock = "installing from " .. src
primaryWindowRegen()
checked(claw.installTo, "local", packageId, src, true, yielder)
packageLock = nil
primaryWindowRegen()
end
})
end
if srcW and lclI and not srcI then
table.insert(buttons, {
"All",
function ()
if packageLock then return end
packageLock = "storing w/ dependencies at " .. src
primaryWindowRegen()
checked(claw.installTo, src, packageId, "local", true, yielder)
packageLock = nil
primaryWindowRegen()
end
})
table.insert(buttons, {
"Put",
function ()
if packageLock then return end
packageLock = "storing at " .. src
primaryWindowRegen()
checked(claw.installTo, src, packageId, "local", false, yielder)
packageLock = nil
primaryWindowRegen()
end
})
end
return buttons
end
function genPackage()
if packageLock then
return {neoux.tcrawview(1, 1, neoux.fmtText(unicode.safeTextFormat(packageId .. "\n" .. packageLock), 25))}
end
-- concept:
-- mtd <back>
-- Multi-Track Drifting
--
-- local v20 <del> <run>
-- inet v21 <pull>
-- dir v22 <pull> <push>
-- crockett <push>
local info = claw.getInfo(packageId)
local infoL = claw.getInfo(packageId, "local")
local elems = {
neoux.tcrawview(1, 1, neoux.fmtText(unicode.safeTextFormat(packageId .. "\n" .. info.desc .. "\nv" .. info.v .. " deps " .. table.concat(info.deps, ", ")), 25)),
neoux.tcbutton(20, 1, "Back", function ()
if packageLock then return end
genCurrent = genPrimary
primaryWindowRegen()
end)
}
local srcs = claw.getSources()
for k, v in ipairs(srcs) do
local lI = claw.getInfo(packageId, v[1])
local row = 12 + k - #srcs
local pfx = " "
if lI then
pfx = "v" .. string.format("%04i", lI.v) .. " "
end
table.insert(elems, neoux.tcrawview(1, row, {neoux.pad(pfx .. v[1], 14, false, true)}))
local col = 26
for _, bv in ipairs(packageGetBB(v[1], infoL, lI, v[2])) do
local b = neoux.tcbutton(col, row, bv[1], bv[2])
col = col - b.w
b.x = col
table.insert(elems, b)
end
end
return elems
end
--
genCurrent = genPrimary
primaryWindow = neoux.create(25, 12, "claw", primaryWindowRegenCore())
while windows > 0 do
event.pull()
end
claw.unlock()

View File

@ -36,7 +36,8 @@ local ctrlFlag = false
local dialogLock = false
local appendFlag = false
local sW, sH = 37, #lines + 2
local window = neo.requestAccess("x.neo.pub.window")(sW, sH)
local windows = neo.requestAccess("x.neo.pub.window")
local window = windows(sW, sH)
local flush
local function splitCur()
@ -55,13 +56,24 @@ local function clampCursorX()
return false
end
local cbs = {}
local function fileDialog(writing, callback)
local tag = neo.requestAccess("x.neo.pub.base").showFileDialogAsync(writing)
local f
function f(_, evt, tag2, res)
if evt == "filedialog" then
if tag == tag2 then
callback(res)
local ok, e = pcall(callback, res)
if not ok then
e = unicode.safeTextFormat(tostring(e))
local wnd = windows(unicode.len(e), 1, "ERROR")
cbs[wnd.id] = {
wnd.close,
wnd.span,
e
}
end
event.ignore(f)
end
end
@ -410,6 +422,14 @@ while true do
ev_clipboard(e[4])
flush()
end
elseif cbs[e[2]] then
if e[3] == "line" then
cbs[e[2]][2](1, 1, cbs[e[2]][3], 0, 0xFFFFFF)
end
if e[3] == "close" then
cbs[e[2]][1]()
cbs[e[2]] = nil
end
end
end
end

View File

@ -26,9 +26,7 @@
-- or this is a screensaver host, and has a saving-throw to start Bristol if it dies unexpectedly.
-- In any case, this eventually returns to 2 or 4.
local everestProvider = neo.requestAccess("r.neo.pub.window", "registering npw")
if not everestProvider then return end
local everestProvider = neo.requireAccess("r.neo.pub.window", "registering npw")
local everestSessionProvider = neo.requireAccess("r.neo.sys.session", "registering nsse")
-- Got mutexes. Now setup saving throw and shutdown callback
@ -57,6 +55,9 @@ monitors[0] = {nil, nil, 160, 50}
-- line y
local surfaces = {}
-- Last Interact Monitor
local lIM = 1
-- Stops the main loop
local shuttingDown = false
@ -98,7 +99,7 @@ local function surfaceAt(monitor, x, y)
end
end
-- Always use the first sometime before the second
-- Always use the first if the GPU has been rebound
local function monitorResetBF(m)
m[5] = -1
m[6] = -1
@ -136,9 +137,11 @@ end
local function updateRegion(monitorId, x, y, w, h, surfaceSpanCache)
if not renderingAllowed() then return end
local m = monitors[monitorId]
local mg = m[1]()
local mg, rb = m[1]()
if not mg then return end
monitorResetBF(m)
if rb then
monitorResetBF(m)
end
-- The input region is the one that makes SENSE.
-- Considering WC handling, that's not an option.
-- WCHAX: start
@ -198,7 +201,7 @@ local function ensureOnscreen(monitor, x, y, w, h)
-- Failing anything else, revert to monitor 0
if #monitors == 0 then monitor = 0 end
x = math.min(math.max(1, x), monitors[monitor][3] - (w - 1))
y = math.min(math.max(1, y), monitors[monitor][4] - (h - 1))
y = math.max(1, math.min(monitors[monitor][4] - (h - 1), y))
return monitor, x, y
end
@ -209,7 +212,10 @@ local function reconcileAll()
v[1], v[2], v[3] = ensureOnscreen(v[1], v[2], v[3], v[4], v[5])
end
for k, v in ipairs(monitors) do
local mon = v[1]()
local mon, rb = v[1]()
if rb then
monitorResetBF(v)
end
if mon then
v[3], v[4] = mon.getResolution()
end
@ -218,7 +224,8 @@ local function reconcileAll()
updateStatus()
end
local function moveSurface(surface, m, x, y, w, h)
-- NOTE: If the M, X, Y, W and H are the same, this function ignores you, unless you put , true on the end.
local function moveSurface(surface, m, x, y, w, h, force)
local om, ox, oy, ow, oh = table.unpack(surface, 1, 5)
m = m or om
x = x or ox
@ -227,24 +234,18 @@ local function moveSurface(surface, m, x, y, w, h)
h = h or oh
surface[1], surface[2], surface[3], surface[4], surface[5] = m, x, y, w, h
local cache = {}
if om == m then
if ow == w then
if oh == h then
-- Cheat - perform a GPU copy
-- this increases "apparent" performance while we're inevitably waiting for the app to catch up,
-- CANNOT glitch since we're going to draw over this later,
-- and will usually work since the user can only move focused surfaces
if renderingAllowed() then
local cb = monitors[m][1]()
if cb then
cb.copy(ox, oy, w, h, x - ox, y - oy)
end
end
--because OC's widechar support sucks, comment out this perf. opt.
--if surfaces[1] == surface then
-- updateRegion(om, ox, oy, ow, oh, cache)
-- return
--end
if om == m and ow == w and oh == h then
if ox == x and oy == y and not force then
return
end
-- note: this doesn't always work due to WC support
if renderingAllowed() then
local cb, b = monitors[m][1]()
if b then
monitorResetBF(b)
end
if cb then
cb.copy(ox, oy, w, h, x - ox, y - oy)
end
end
end
@ -266,9 +267,11 @@ end
local function handleSpan(target, x, y, text, bg, fg)
if not renderingAllowed() then return end
local m = monitors[target[1]]
local cb = m[1]()
local cb, rb = m[1]()
if not cb then return end
monitorResetBF(m)
if rb then
monitorResetBF(m)
end
-- It is assumed basic type checks were handled earlier.
if y < 1 then return end
if y > target[5] then return end
@ -366,8 +369,7 @@ everestProvider(function (pkg, pid, sendSig)
end
local m = 0
if renderingAllowed() then m = 1 end
if surfaces[1] then m = surfaces[1][1] end
local surf = {m, 1, 2, w, h}
local surf = {math.min(#monitors, math.max(1, lIM)), 1, 2, w, h}
local focusState = false
local llid = lid
lid = lid + 1
@ -380,6 +382,10 @@ everestProvider(function (pkg, pid, sendSig)
if ev == "touch" then
specialDragHandler = nil
if math.floor(b) == 1 then
if e == 1 then
sendSig(llid, "close")
return
end
specialDragHandler = function (x, y)
local ofsX, ofsY = math.floor(x) - math.floor(a), math.floor(y) - math.floor(b)
if (ofsX == 0) and (ofsY == 0) then return end
@ -397,6 +403,7 @@ everestProvider(function (pkg, pid, sendSig)
b = b - 1
end
if ev == "scroll" or ev == "drop" then
specialDragHandler = nil
b = b - 1
end
if ev == "line" then
@ -435,7 +442,7 @@ everestProvider(function (pkg, pid, sendSig)
w = math.floor(math.max(w, 8))
h = math.floor(math.max(h, 1)) + 1
local _, x, y = ensureOnscreen(surf[1], surf[2], surf[3], w, h)
moveSurface(surf, nil, x, y, w, h)
moveSurface(surf, nil, x, y, w, h, true)
return w, (h - 1)
end,
span = function (x, y, text, bg, fg)
@ -538,6 +545,7 @@ local function key(ka, kc, down)
end
end
if focus then
lIM = focus[1]
focus[6]("key", ka, kc, down)
end
end
@ -577,6 +585,7 @@ while not shuttingDown do
if s[1] == "h.touch" then
for k, v in ipairs(monitors) do
if v[2] == s[2] then
lIM = k
local x, y = math.floor(s[3]), math.floor(s[4])
local ix, iy = s[3] - x, s[4] - y
local sid, lx, ly = surfaceAt(k, x, y)
@ -586,6 +595,8 @@ while not shuttingDown do
table.insert(surfaces, 1, ns)
changeFocus(os)
ns[6]("touch", lx, ly, ix, iy, s[5])
else
if s[5] == 1 and not waitingShutdownCallback then neo.executeAsync("app-launcher") end
end
break
end

View File

@ -263,11 +263,13 @@ donkonitRDProvider(function (pkg, pid, sendSig)
return function ()
for v in gpus.list() do
if v.address == gpu then
local didBind = false
if currentGPUBinding[gpu] ~= address then
v.bind(address, false)
didBind = true
end
currentGPUBinding[gpu] = address
return v
return v, didBind
end
end
end

View File

@ -110,27 +110,24 @@ end)
local rootAccess = neo.requireAccess("k.root", "installing GUI integration")
local backup = rootAccess.securityPolicyINIT or rootAccess.securityPolicy
rootAccess.securityPolicyINIT = backup
rootAccess.securityPolicy = function (pid, proc, req)
rootAccess.securityPolicy = function (pid, proc, perm, req)
if neo.dead then
return backup(pid, proc, req)
return backup(pid, proc, perm, req)
end
req.result = proc.pkg:sub(1, 4) == "sys-"
local def = proc.pkg:sub(1, 4) == "sys-"
local secpol, err = require("sys-secpolicy")
if not secpol then
-- Failsafe.
neo.emergency("Used fallback policy because of load-err: " .. err)
req.service()
req(def)
return
end
-- Push to ICECAP thread to avoid deadlock on neoux b/c wrong event-pull context
event.runAt(0, function ()
local ok, err = pcall(secpol, neoux, settings, proc.pkg, pid, req.perm, function (r)
req.result = r
req.service()
end)
local ok, err = pcall(secpol, neoux, settings, proc.pkg, pid, perm, req)
if not ok then
neo.emergency("Used fallback policy because of run-err: " .. err)
req.service()
req(def)
end
end)
end

View File

@ -153,6 +153,9 @@ local function finalPrompt()
local password = ""
if nsm then
password = nsm.getSetting("password")
if nsm.getSetting("sys-init.nologin") == "yes" then
return false
end
end
warnings[1] = "TAB to change option,"
warnings[2] = "ENTER to select..."

View File

@ -2,7 +2,6 @@ return {
["neo"] = {
desc = "KittenOS NEO Kernel & Base Libs",
v = 0,
app = false,
deps = {
},
dirs = {
@ -12,6 +11,7 @@ return {
},
files = {
"init.lua",
"apps/sys-glacier.lua",
"libs/event.lua",
"libs/serial.lua",
"libs/neoux.lua",
@ -21,10 +21,8 @@ return {
["neo-init"] = {
desc = "KittenOS NEO / sys-init (startup)",
v = 0,
app = "app-launcher",
deps = {
"neo",
"neo-glacier",
"neo-icecap",
"neo-everest"
},
@ -38,7 +36,6 @@ return {
["neo-launcher"] = {
desc = "KittenOS NEO / Default app-launcher",
v = 0,
app = "app-launcher",
deps = {
"neo"
},
@ -50,9 +47,8 @@ return {
},
},
["neo-everest"] = {
desc = "KittenOS NEO / Everest (settings & monitor management)",
desc = "KittenOS NEO / Everest (windowing)",
v = 0,
app = "sys-everest",
deps = {
"neo"
},
@ -66,7 +62,6 @@ return {
["neo-icecap"] = {
desc = "KittenOS NEO / Icecap",
v = 0,
app = "sys-icecap",
deps = {
"neo"
},
@ -81,24 +76,21 @@ return {
"apps/app-fm.lua"
},
},
["neo-glacier"] = {
desc = "KittenOS NEO / Glacier (settings & monitor management)",
["neo-secpolicy"] = {
desc = "KittenOS NEO / Secpolicy",
v = 0,
app = "sys-glacier",
deps = {
"neo"
},
dirs = {
"apps"
"libs"
},
files = {
"apps/sys-glacier.lua"
},
"libs/sys-secpolicy.lua"
}
},
["app-textedit"] = {
desc = "KittenOS NEO Text Editor (Neolithic)",
["neo-coreapps"] = {
desc = "KittenOS NEO Core Apps",
v = 0,
app = "app-textedit",
deps = {
"neo"
},
@ -106,13 +98,14 @@ return {
"apps"
},
files = {
"apps/app-textedit.lua"
},
"apps/app-textedit.lua",
"apps/app-pass.lua",
"apps/app-taskmgr.lua"
}
},
["app-flash"] = {
desc = "KittenOS NEO EEPROM Flasher",
v = 0,
app = "app-flash",
deps = {
"neo"
},
@ -123,38 +116,9 @@ return {
"apps/app-flash.lua"
},
},
["app-pass"] = {
desc = "KittenOS NEO Password Setter & Logout",
v = 0,
app = "app-pass",
deps = {
"neo"
},
dirs = {
"apps"
},
files = {
"apps/app-pass.lua"
},
},
["app-taskmgr"] = {
desc = "KittenOS NEO Task Manager",
v = 0,
app = "app-taskmgr",
deps = {
"neo"
},
dirs = {
"apps"
},
files = {
"apps/app-taskmgr.lua"
},
},
["app-claw"] = {
desc = "KittenOS NEO Package Manager",
v = 0,
app = "app-claw",
deps = {
"neo"
},
@ -166,5 +130,24 @@ return {
"apps/app-claw.lua",
"libs/claw.lua"
},
},
["neo-meta"] = {
desc = "KittenOS NEO: Use 'All' to install to other disks",
v = 0,
deps = {
"neo",
"neo-init",
"neo-launcher",
"neo-everest",
"neo-icecap",
"neo-secpolicy",
"neo-coreapps",
"app-flash",
"app-claw"
},
dirs = {
},
files = {
}
}
}

View File

@ -25,9 +25,7 @@ primaryDisk = component.proxy(computer.getBootAddress())
timers = {}
libraries = {}
setmetatable(libraries, {
__mode = "v"
})
setmetatable(libraries, {__mode = "v"})
-- proc.co = coroutine.create(appfunc)
-- proc.pkg = "pkg"
@ -89,7 +87,7 @@ function unicode.undoSafeTextFormat(s)
end
local function loadfile(s, e)
local h = primaryDisk.open(s)
local h, er = primaryDisk.open(s)
if h then
local ch = ""
local c = primaryDisk.read(h, readBufSize)
@ -100,7 +98,7 @@ local function loadfile(s, e)
primaryDisk.close(h)
return load(ch, "=" .. s, "t", e)
end
return nil, "File Unreadable"
return nil, tostring(er)
end
local wrapMeta = nil
@ -320,6 +318,7 @@ function loadLibraryInner(library)
library = "libs/" .. library .. ".lua"
ensurePath(library, "libs/")
if libraries[library] then return libraries[library] end
emergencyFunction("loading " .. library)
local l, r = loadfile(library, baseProcEnv())
if l then
local ok, al = pcall(l)
@ -335,10 +334,9 @@ end
-- These two are hooks for k.root level applications to change policy.
-- Only a k.root application is allowed to do this for obvious reasons.
function securityPolicy(pid, proc, req)
function securityPolicy(pid, proc, perm, req)
-- Important safety measure : only sys-* gets anything at first
req.result = proc.pkg:sub(1, 4) == "sys-"
req.service()
req(proc.pkg:sub(1, 4) == "sys-")
end
function runProgramPolicy(ipkg, pkg, pid, ...)
-- VERY specific injunction here:
@ -489,13 +487,11 @@ function start(pkg, ...)
local requestAccessAsync = function (perm)
ensureType(perm, "string")
-- Safety-checked, prepare security event.
local req = {}
req.perm = perm
req.service = function ()
local req = function (res)
if processes[pid] then
local n = nil
local n2 = nil
if req.result then
if res then
proc.access[perm] = true
proc.denied[perm] = nil
n, n2 = retrieveAccess(perm, pkg, pid)
@ -509,16 +505,14 @@ function start(pkg, ...)
end
end
-- outer security policy:
req.result = proc.access["k.root"] or not proc.denied[perm]
if proc.access["k.root"] or proc.access[perm] or proc.denied[perm] then
-- Use cached result to prevent possible unintentional security service spam
req.service()
req(proc.access["k.root"] or not proc.denied[perm])
return
end
-- Denied goes to on to prevent spam
proc.denied[perm] = true
securityPolicy(pid, proc, req)
securityPolicy(pid, proc, perm, req)
end
local env = baseProcEnv()
env.neo.pid = pid
@ -558,7 +552,7 @@ function start(pkg, ...)
if not appfunc then
return nil, r
end
proc.co = coroutine.create(appfunc)
proc.co = coroutine.create(function (...) local r = {xpcall(appfunc, debug.traceback)} if not r[1] then error(table.unpack(r, 2)) end return table.unpack(r, 2) end)
proc.pkg = pkg
proc.access = {
-- These permissions are the "critical set".

View File

@ -2,3 +2,182 @@
-- No warranty is provided, implied or otherwise.
-- claw: assistant to app-claw
-- should only ever be one app-claw at a time
local lock = false
return function ()
if lock then
error("libclaw safety lock in use")
end
lock = true
local sourceList = {}
local sources = {}
-- 1 2 3 4 5 6
-- dst entries: writeFile(fn), mkdir(fn), exists(fn), isDirectory(fn), remove(fn), rename(fna, fnb)
-- writeFile(fn) -> function (data/nil to close)
local function saveInfo(dn)
sources[dn][2][2]("data")
sources[dn][2][2]("data/app-claw")
local cb, _, r = sources[dn][2][1]("data/app-claw/local.lua")
if not cb then return false, r end
_, r = cb(require("serial").serialize(sources[dn][3]))
if not _ then return false, r end
_, r = cb(nil)
if not _ then return false, r end
return true
end
local remove, installTo
-- NOTE: Functions in this must return something due to the checked-call wrapper,
-- but should all use error() for consistency.
-- Operations
installTo = function (dstName, pkg, srcName, checked, yielder)
local installed = {pkg}
local errs = {}
if srcName == dstName then
error("Invalid API use")
end
-- preliminary checks
if checked then
for _, v in ipairs(sources[srcName][3][pkg].deps) do
if not sources[dstName][3][v] then
if not sources[srcName][3][v] then
table.insert(errs, pkg .. " depends on " .. v .. "\n")
elseif #errs == 0 then
installTo(dstName, v, srcName, checked, yielder)
else
table.insert(errs, pkg .. " depends on " .. v .. " (can autoinstall)\n")
end
end
end
end
-- Files from previous versions to get rid of
local ignFiles = {}
if sources[dstName][3][pkg] then
for _, v in ipairs(sources[dstName][3][pkg].files) do
ignFiles[v] = true
end
end
for _, v in ipairs(sources[srcName][3][pkg].files) do
if not ignFiles[v] then
if sources[dstName][2][3](v) then
table.insert(errs, v .. " already exists (corrupt system?)")
end
end
end
if #errs > 0 then
error(table.concat(errs))
end
for _, v in ipairs(sources[srcName][3][pkg].dirs) do
sources[dstName][2][2](v)
if not sources[dstName][2][4](v) then
error("Unable to create directory " .. v)
end
end
for _, v in ipairs(sources[srcName][3][pkg].files) do
local ok, r = sources[srcName][1](v, sources[dstName][2][1](v .. ".claw-tmp"))
if ok then
yielder()
else
-- Cleanup...
for _, v in ipairs(sources[srcName][3][pkg].files) do
sources[dstName][2][5](v .. ".claw-tmp")
end
error(r)
end
end
-- PAST THIS POINT, ERRORS CORRUPT!
sources[dstName][3][pkg] = nil
saveInfo(dstName)
for k, _ in pairs(ignFiles) do
yielder()
sources[dstName][2][5](k)
end
for _, v in ipairs(sources[srcName][3][pkg].files) do
yielder()
sources[dstName][2][6](v .. ".claw-tmp", v)
end
sources[dstName][3][pkg] = sources[srcName][3][pkg]
saveInfo(dstName)
return true
end
remove = function (dstName, pkg, checked)
if checked then
local errs = {}
for dpsName, dpsV in pairs(sources[dstName][3]) do
for _, v in ipairs(dpsV.deps) do
if v == pkg then
table.insert(errs, dpsName .. " depends on " .. pkg .. "\n")
end
end
end
if #errs > 0 then
return nil, table.concat(errs)
end
end
for _, v in ipairs(sources[dstName][3][pkg].files) do
sources[dstName][2][5](v)
end
sources[dstName][3][pkg] = nil
saveInfo(dstName)
return true
end
return {
-- Gets the latest info, or if given a source just gives that source's info.
-- Do not modify output.
getInfo = function (pkg, source, oldest)
if source then return sources[source][3][pkg] end
local bestI = {
v = -1,
desc = "An unknown package.",
deps = {}
}
if oldest then bestI.v = 10000 end
for _, v in pairs(sources) do
if v[3][pkg] then
if ((not oldest) and (v[3][pkg].v > bestI.v)) or (oldest and (v[3][pkg].v > bestI.v)) then
bestI = v[3][pkg]
end
end
end
return bestI
end,
-- Provides an ordered list of sources, with writable.
-- Do not modify output.
getSources = function ()
return sourceList
end,
-- NOTE: If a source is writable, it's added anyway despite any problems.
addSource = function (name, src, dst)
local ifo = ""
local ifok, e = src("data/app-claw/local.lua", function (t)
ifo = ifo .. (t or "")
return true
end)
ifo = ifok and require("serial").deserialize(ifo)
if not (dst or ifo) then return false, e end
table.insert(sourceList, {name, not not dst})
sources[name] = {src, dst, ifo or {}}
return not not ifo, e or "local.lua parse error"
end,
remove = remove,
installTo = installTo,
-- Gets a total list of packages, as a table of strings. You can modify output.
getList = function ()
local n = {}
local seen = {}
for k, v in pairs(sources) do
for kb, vb in pairs(v[3]) do
if not seen[kb] then
seen[kb] = true
table.insert(n, kb)
end
end
end
table.sort(n)
return n
end,
unlock = function ()
lock = false
end
}
end

View File

@ -7,7 +7,8 @@
-- This function needs access to the caller's NEO in order to ensure that NEO system functions are covered.
-- This can do less checks than usual as it only affects the caller.
return function (neo)
-- Global forces reference to prevent duplication
newEvent = function (neo)
local listeners = {}
local translations = {}
local timers = {}
@ -102,3 +103,4 @@ return function (neo)
end
}
end
return newEvent

View File

@ -3,7 +3,9 @@
-- neoux: Implements utilities on top of Everest & event:
-- Everest crash protection
return function (event, neo)
-- Global forces reference. Otherwise, nasty duplication happens.
newNeoux = function (event, neo)
-- this is why neo access is 'needed'
local function retrieveIcecap()
return neo.requestAccess("x.neo.pub.base")
@ -448,8 +450,8 @@ return function (event, neo)
}
end
neoux.startDialog = function (fmt, title, wait)
fmt = neoux.fmtText(unicode.safeTextFormat(fmt), 20)
neoux.create(20, #fmt, title, function (window, ev, a, b, c)
fmt = neoux.fmtText(unicode.safeTextFormat(fmt), 40)
neoux.create(40, #fmt, title, function (window, ev, a, b, c)
if ev == "line" then
window.span(1, a, fmt[a], 0xFFFFFF, 0)
end
@ -464,3 +466,4 @@ return function (event, neo)
end
return neoux
end
return newNeoux

View File

@ -4,17 +4,26 @@ local doSerialize = nil
function doSerialize(s)
if type(s) == "table" then
local str = "{\n"
local p = 1
for k, v in pairs(s) do
str = str .. "[" .. doSerialize(k) .. "]=" .. doSerialize(v) .. ",\n"
if k == p then
str = str .. doSerialize(v) .. ",\n"
p = p + 1
else
str = str .. "[" .. doSerialize(k) .. "]=" .. doSerialize(v) .. ",\n"
end
end
return str .. "}"
end
if type(s) == "string" then
return string.format("%q", s)
end
if type(s) == "number" then
if type(s) == "number" or type(s) == "boolean" then
return tostring(s)
end
if s == nil then
return "nil"
end
error("Cannot serialize " .. type(s))
end
return neo.wrapMeta({

View File

@ -130,6 +130,19 @@ local function prepareNodeI(node)
if evt == "key" then
key(wnd, a, b, c)
end
if evt == "touch" then
local ns = b + math.max(1, selection - 4) - 2
local max = #l
if node.unknownAvailable then
max = max + 1
end
if ns == selection and selection ~= #l + 1 then
key(wnd, 13, 0, true)
else
selection = math.min(math.max(1, ns), max)
flush(wnd)
end
end
if evt == "line" then
updateLine(wnd, a)
end

View File

@ -113,7 +113,11 @@ getFsNode = function (fs, parent, fsc, path, mode)
end,
unknownAvailable = mode ~= nil,
selectUnknown = function (text)
return true, require("sys-filewrap")(fsc, path .. text, mode)
local rt, re = require("sys-filewrap")(fsc, path .. text, mode)
if not rt then
return false, dialog("Open Error: " .. tostring(re), parent)
end
return true, rt
end
}
return t
@ -127,11 +131,19 @@ getFsNode = function (fs, parent, fsc, path, mode)
end})
if mode ~= nil then
table.insert(n, {"Open", function ()
return true, require("sys-filewrap")(fsc, path, mode)
local rt, re = require("sys-filewrap")(fsc, path, mode)
if not rt then
return false, dialog("Open Error: " .. tostring(re), parent)
end
return true, rt
end})
end
table.insert(n, {"Copy", function ()
return nil, setupCopyVirtualEnvironment(fs, parent, require("sys-filewrap")(fsc, path, false))
local rt, re = require("sys-filewrap")(fsc, path, false)
if not rt then
return false, dialog("Open Error: " .. tostring(re), parent)
end
return nil, setupCopyVirtualEnvironment(fs, parent, rt)
end})
table.insert(n, {"Delete", function ()
fsc.remove(path)

View File

@ -4,7 +4,8 @@
return function(dev, file, mode)
local n = "rb"
if mode then n = "wb" end
local handle = dev.open(file, n)
local handle, r = dev.open(file, n)
if not handle then return nil, r end
local open = true
local function closer()
if not open then return end
@ -35,7 +36,8 @@ return function(dev, file, mode)
close = closer,
write = function (txt)
if type(txt) ~= "string" then error("Write data must be string-bytearray") end
return dev.write(handle, txt)
local ok, b = dev.write(handle, txt)
if not ok then error(tostring(b)) end
end
}, closer
end

View File

@ -28,7 +28,6 @@ for k, v in pairs(f) do
end
os.execute("mkdir -p work/data/app-claw")
os.execute("cp code/data/app-claw/local.lua work/data/app-claw/local.lua")
os.execute("cp code/libs/sys-secpolicy.lua work/libs/sys-secpolicy.lua")
os.execute("cd code ; find . > ../imitclaw.treecode")
os.execute("cd work ; find . > ../imitclaw.treework")
os.execute("diff -u imitclaw.treecode imitclaw.treework")

View File

@ -11,13 +11,8 @@
local event = require("event")(neo)
local neoux = require("neoux")(event, neo)
local eeprom = neo.requestAccess("c.eeprom")
if eeprom then
eeprom = eeprom.list()()
end
if not eeprom then
error("No EEPROM access")
end
local eeprom = neo.requireAccess("c.eeprom", "EEPROM access")
eeprom = eeprom.list()()
neoux.startDialog("NOTE: If this program is used improperly, it can require EEPROM replacement.\nOnly use trusted EEPROMs.", "eeprom-flash", true)

View File

@ -2,7 +2,6 @@ return {
["app-eeprog"] = {
desc = "EEPROM programmer / copier",
v = 0,
app = "app-eeprog",
deps = {
"neo"
},
@ -12,5 +11,17 @@ return {
files = {
"apps/app-eeprog.lua"
},
},
["mtd"] = {
desc = "Multi-Track Drifting",
v = 1337,
deps = {
"app-eeprog"
},
dirs = {
},
files = {
"oreproc.txt"
}
}
}

1
repository/oreproc.txt Normal file
View File

@ -0,0 +1 @@
Hello new world