OC-KittenOS/code/libs/event.lua

105 lines
2.7 KiB
Lua
Raw Normal View History

-- This is released into the public domain.
-- No warranty is provided, implied or otherwise.
-- event: Implements pull/listen semantics in a consistent way for a given process.
-- This is similar in API to OpenOS's event framework, but is per-process.
-- To make this work, a function is shared.
-- 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)
local listeners = {}
local translations = {}
local timers = {}
local oldRA = neo.requestAccess
local function doPush(tp, tag, ...)
if tp == "k.timer" then
local f = timers[tag]
timers[tag] = nil
if f then
f(...)
end
end
local listeners2 = {}
for k, _ in pairs(listeners) do
table.insert(listeners2, k)
end
for _, v in ipairs(listeners2) do
v(tp, tag, ...)
end
end
neo.requestAccess = function (perm, handler)
return oldRA(perm, function (...)
doPush(...)
if handler then
handler(...)
end
end)
end
local function doPull()
local ev = {coroutine.yield()}
doPush(table.unpack(ev))
return ev
end
return {
listen = function (p1, p2)
if type(p2) == "function" then
local t = function (...)
local evn = ...
if evn == p1 then
p2(...)
end
end
translations[p2] = t
listeners[t] = true
else
listeners[p1] = true
end
end,
ignore = function (func)
if translations[func] then
listeners[translations[func]] = nil
translations[func] = nil
end
listeners[func] = nil
end,
-- Arguments are filtering.
-- For example, to filter for timers with a given tag, use pull("k.timer", tag)
-- Note the explicit discouragement of timeout-pulls. Use runAt or the complex form of sleep.
pull = function (...)
local filter = {...}
while true do
local ev = doPull()
local err = false
for i = 1, #filter do
err = err or (filter[i] ~= ev[i])
end
if not err then return table.unpack(ev) end
end
end,
-- Run a function at a specified uptime.
runAt = function (time, func)
timers[neo.scheduleTimer(time)] = func
end,
-- Sleeps until a time (unless time is nil, in which case sleeps forever), but can be woken up before then.
-- This allows using an async API as a synchronous one with optional time-to-failure.
sleepTo = function (time, wakeUpPoll)
local timerHit = false
local oWUP = wakeUpPoll
wakeUpPoll = function ()
if oWUP then
return timerHit or (oWUP())
end
return timerHit
end
if time then
timers[neo.scheduleTimer(time)] = function () timerHit = true end
end
while true do
local ev = doPull()
if wakeUpPoll() then return end
end
end
}
end