From 6fa8e1d2fd227c5b87ad207888632f959edc1164 Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Tue, 22 Aug 2023 16:30:37 +0200 Subject: [PATCH] KOSync: Set sane socket timeouts properly (#10835) 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. --- frontend/socketutil.lua | 2 +- plugins/kosync.koplugin/KOSyncClient.lua | 54 +++++++++++++++--------- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/frontend/socketutil.lua b/frontend/socketutil.lua index 4a62985c3..53ddf2419 100644 --- a/frontend/socketutil.lua +++ b/frontend/socketutil.lua @@ -51,7 +51,7 @@ function socketutil:set_timeout(block_timeout, total_timeout) -- Also update the actual LuaSocket & LuaSec constants, because: -- 1. LuaSocket's `open` does a `settimeout` *after* create with this constant - -- 2. KOSync updates it to a stupidly low value + -- 2. Rogue code might be attempting to enforce them http.TIMEOUT = self.block_timeout https.TIMEOUT = self.block_timeout end diff --git a/plugins/kosync.koplugin/KOSyncClient.lua b/plugins/kosync.koplugin/KOSyncClient.lua index 7d67db4c6..ca35e6e00 100644 --- a/plugins/kosync.koplugin/KOSyncClient.lua +++ b/plugins/kosync.koplugin/KOSyncClient.lua @@ -1,5 +1,11 @@ local UIManager = require("ui/uimanager") -local DEBUG = require("dbg") +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, @@ -15,22 +21,21 @@ function KOSyncClient:new(o) end function KOSyncClient:init() - require("socket.http").TIMEOUT = 1 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" + 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 + 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) + 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() @@ -41,7 +46,7 @@ function KOSyncClient:init() body = req.env.spore.payload, on_headers = function(headers) for header, value in pairs(req.headers) do - if type(header) == 'string' then + if type(header) == "string" then headers:add(header, value) end end @@ -59,37 +64,41 @@ end function KOSyncClient:register(username, password) self.client:reset_middlewares() - self.client:enable('Format.JSON') + 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 - DEBUG(ok, res) + 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("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 - DEBUG("err:", res) + logger.dbg("KOSyncClient:authorize failure:", res) return false, res.body end end @@ -104,12 +113,14 @@ function KOSyncClient:update_progress( device_id, callback) self.client:reset_middlewares() - self.client:enable('Format.JSON') + 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({ @@ -123,13 +134,14 @@ function KOSyncClient:update_progress( if ok then callback(res.status == 200, res.body) else - DEBUG("err:", res) + 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( @@ -138,12 +150,13 @@ function KOSyncClient:get_progress( document, callback) self.client:reset_middlewares() - self.client:enable('Format.JSON') + 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({ @@ -153,13 +166,14 @@ function KOSyncClient:get_progress( if ok then callback(res.status == 200, res.body) else - DEBUG("err:", res) + 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