mirror of
https://github.com/koreader/koreader
synced 2024-11-02 15:40:16 +00:00
6fa8e1d2fd
An attempt was made in the original code, but the whole thing was designed in the hope of actually switching to turbo, so it was super janky without it. Anyway, we now actually have a sane way to set socket timeouts, so, use that, and set them very tight for now. This is fairly critical right now, because the server is down, and the default timeouts are ~30s. That happens to be *above* the debounce threshold, so you can't even hope for that to help you. Meaning, right now, you get a 2 * 30s block on resume with auto sync. That's... Very Not Good(TM). That becomes a single 2s one after this.
180 lines
5.4 KiB
Lua
180 lines
5.4 KiB
Lua
local UIManager = require("ui/uimanager")
|
|
local logger = require("logger")
|
|
local socketutil = require("socketutil")
|
|
|
|
-- Push/Pull
|
|
local PROGRESS_TIMEOUTS = { 2, 5 }
|
|
-- Login/Register
|
|
local AUTH_TIMEOUTS = { 5, 10 }
|
|
|
|
local KOSyncClient = {
|
|
service_spec = nil,
|
|
custom_url = nil,
|
|
}
|
|
|
|
function KOSyncClient:new(o)
|
|
if o == nil then o = {} end
|
|
setmetatable(o, self)
|
|
self.__index = self
|
|
if o.init then o:init() end
|
|
return o
|
|
end
|
|
|
|
function KOSyncClient:init()
|
|
local Spore = require("Spore")
|
|
self.client = Spore.new_from_spec(self.service_spec, {
|
|
base_url = self.custom_url,
|
|
})
|
|
package.loaded["Spore.Middleware.GinClient"] = {}
|
|
require("Spore.Middleware.GinClient").call = function(_, req)
|
|
req.headers["accept"] = "application/vnd.koreader.v1+json"
|
|
end
|
|
package.loaded["Spore.Middleware.KOSyncAuth"] = {}
|
|
require("Spore.Middleware.KOSyncAuth").call = function(args, req)
|
|
req.headers["x-auth-user"] = args.username
|
|
req.headers["x-auth-key"] = args.userkey
|
|
end
|
|
package.loaded["Spore.Middleware.AsyncHTTP"] = {}
|
|
require("Spore.Middleware.AsyncHTTP").call = function(args, req)
|
|
-- disable async http if Turbo looper is missing
|
|
if not UIManager.looper then return end
|
|
req:finalize()
|
|
local result
|
|
require("httpclient"):new():request({
|
|
url = req.url,
|
|
method = req.method,
|
|
body = req.env.spore.payload,
|
|
on_headers = function(headers)
|
|
for header, value in pairs(req.headers) do
|
|
if type(header) == "string" then
|
|
headers:add(header, value)
|
|
end
|
|
end
|
|
end,
|
|
}, function(res)
|
|
result = res
|
|
-- Turbo HTTP client uses code instead of status
|
|
-- change to status so that Spore can understand
|
|
result.status = res.code
|
|
coroutine.resume(args.thread)
|
|
end)
|
|
return coroutine.create(function() coroutine.yield(result) end)
|
|
end
|
|
end
|
|
|
|
function KOSyncClient:register(username, password)
|
|
self.client:reset_middlewares()
|
|
self.client:enable("Format.JSON")
|
|
self.client:enable("GinClient")
|
|
socketutil:set_timeout(AUTH_TIMEOUTS[1], AUTH_TIMEOUTS[2])
|
|
local ok, res = pcall(function()
|
|
return self.client:register({
|
|
username = username,
|
|
password = password,
|
|
})
|
|
end)
|
|
socketutil:reset_timeout()
|
|
if ok then
|
|
return res.status == 201, res.body
|
|
else
|
|
logger.dbg("KOSyncClient:register failure:", res)
|
|
return false, res.body
|
|
end
|
|
end
|
|
|
|
function KOSyncClient:authorize(username, password)
|
|
self.client:reset_middlewares()
|
|
self.client:enable("Format.JSON")
|
|
self.client:enable("GinClient")
|
|
self.client:enable("KOSyncAuth", {
|
|
username = username,
|
|
userkey = password,
|
|
})
|
|
socketutil:set_timeout(AUTH_TIMEOUTS[1], AUTH_TIMEOUTS[2])
|
|
local ok, res = pcall(function()
|
|
return self.client:authorize()
|
|
end)
|
|
socketutil:reset_timeout()
|
|
if ok then
|
|
return res.status == 200, res.body
|
|
else
|
|
logger.dbg("KOSyncClient:authorize failure:", res)
|
|
return false, res.body
|
|
end
|
|
end
|
|
|
|
function KOSyncClient:update_progress(
|
|
username,
|
|
password,
|
|
document,
|
|
progress,
|
|
percentage,
|
|
device,
|
|
device_id,
|
|
callback)
|
|
self.client:reset_middlewares()
|
|
self.client:enable("Format.JSON")
|
|
self.client:enable("GinClient")
|
|
self.client:enable("KOSyncAuth", {
|
|
username = username,
|
|
userkey = password,
|
|
})
|
|
-- Set *very* tight timeouts to avoid blocking for too long...
|
|
socketutil:set_timeout(PROGRESS_TIMEOUTS[1], PROGRESS_TIMEOUTS[2])
|
|
local co = coroutine.create(function()
|
|
local ok, res = pcall(function()
|
|
return self.client:update_progress({
|
|
document = document,
|
|
progress = tostring(progress),
|
|
percentage = percentage,
|
|
device = device,
|
|
device_id = device_id,
|
|
})
|
|
end)
|
|
if ok then
|
|
callback(res.status == 200, res.body)
|
|
else
|
|
logger.dbg("KOSyncClient:update_progress failure:", res)
|
|
callback(false, res.body)
|
|
end
|
|
end)
|
|
self.client:enable("AsyncHTTP", {thread = co})
|
|
coroutine.resume(co)
|
|
if UIManager.looper then UIManager:setInputTimeout() end
|
|
socketutil:reset_timeout()
|
|
end
|
|
|
|
function KOSyncClient:get_progress(
|
|
username,
|
|
password,
|
|
document,
|
|
callback)
|
|
self.client:reset_middlewares()
|
|
self.client:enable("Format.JSON")
|
|
self.client:enable("GinClient")
|
|
self.client:enable("KOSyncAuth", {
|
|
username = username,
|
|
userkey = password,
|
|
})
|
|
socketutil:set_timeout(PROGRESS_TIMEOUTS[1], PROGRESS_TIMEOUTS[2])
|
|
local co = coroutine.create(function()
|
|
local ok, res = pcall(function()
|
|
return self.client:get_progress({
|
|
document = document,
|
|
})
|
|
end)
|
|
if ok then
|
|
callback(res.status == 200, res.body)
|
|
else
|
|
logger.dbg("KOSyncClient:get_progress failure:", res)
|
|
callback(false, res.body)
|
|
end
|
|
end)
|
|
self.client:enable("AsyncHTTP", {thread = co})
|
|
coroutine.resume(co)
|
|
if UIManager.looper then UIManager:setInputTimeout() end
|
|
socketutil:reset_timeout()
|
|
end
|
|
|
|
return KOSyncClient
|