Files
neon edc2a2ccfc feat(reader): make KOReader plugin sync non-blocking and resumable
Lifecycle handlers previously blocked on network work, so closing or suspending a book stalled the
device on slow or offline links. Persist snapshots first and drain them through a lifecycle outbox
with connected-state gates and phase-aware retries, so the UI stays responsive and pending work
survives restarts.

Move persistence behind a state manager with atomic flushes, and chunk sweeps, bulk downloads, and
annotation exchange through a background queue with checkpoints and transfer policies, so large
libraries make progress incrementally instead of restarting from scratch after an interruption.

Server side, add bulk manifest and page stats endpoints with batched queries and catalog query
filtering so the plugin can reconcile many books per round trip rather than one request per book.
2026-07-28 02:06:50 +00:00

60 lines
1.4 KiB
Lua

local FakeScheduler = {}
FakeScheduler.__index = FakeScheduler
function FakeScheduler.new()
return setmetatable({
now = 0,
next_id = 0,
pending = {},
}, FakeScheduler)
end
function FakeScheduler:scheduleIn(delay, callback)
self.next_id = self.next_id + 1
table.insert(self.pending, {
id = self.next_id,
at = self.now + delay,
callback = callback,
})
return self.next_id
end
function FakeScheduler:nextTick(callback)
return self:scheduleIn(0, callback)
end
function FakeScheduler:pendingCount()
return #self.pending
end
function FakeScheduler:runOne()
table.sort(self.pending, function(a, b)
if a.at == b.at then return a.id < b.id end
return a.at < b.at
end)
local task = table.remove(self.pending, 1)
if not task then return false end
self.now = task.at
task.callback()
return true
end
function FakeScheduler:advance(seconds)
local target = self.now + seconds
while true do
table.sort(self.pending, function(a, b)
if a.at == b.at then return a.id < b.id end
return a.at < b.at
end)
if not self.pending[1] or self.pending[1].at > target then break end
self:runOne()
end
self.now = target
end
function FakeScheduler:drain()
while self:runOne() do end
end
return FakeScheduler