fix(sync): trigger auth then resume operation when not authenticated (#69)
* fix(sync): trigger auth then resume operation when not authenticated Problem: `get_access_token()` called `auth()` then immediately tried to load tokens, but `auth()` is async (TCP server + browser redirect), so tokens were never present at that point. All sync operations silently aborted when unauthenticated. Solution: Remove the inline auth attempt from `get_access_token()` and add an `on_complete` callback to `auth()` / `_exchange_code()`. Add a `with_token(callback)` helper in `gtasks.lua` and `gcal.lua` that triggers auth with the sync operation as the continuation, so `push`/`pull`/`sync` resume automatically after the OAuth flow completes. * ci: format
This commit is contained in:
parent
7fb3289b21
commit
0163941a2b
3 changed files with 62 additions and 35 deletions
|
|
@ -136,17 +136,31 @@ local function delete_event(access_token, calendar_id, event_id)
|
||||||
return err
|
return err
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param callback fun(access_token: string): nil
|
||||||
|
local function with_token(callback)
|
||||||
|
oauth.async(function()
|
||||||
|
local token = client:get_access_token()
|
||||||
|
if not token then
|
||||||
|
client:auth(function()
|
||||||
|
oauth.async(function()
|
||||||
|
local fresh = client:get_access_token()
|
||||||
|
if fresh then
|
||||||
|
callback(fresh)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
callback(token)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
function M.auth()
|
function M.auth()
|
||||||
client:auth()
|
client:auth()
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.push()
|
function M.push()
|
||||||
oauth.async(function()
|
with_token(function(access_token)
|
||||||
local access_token = client:get_access_token()
|
|
||||||
if not access_token then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local calendars, cal_err = get_all_calendars(access_token)
|
local calendars, cal_err = get_all_calendars(access_token)
|
||||||
if cal_err or not calendars then
|
if cal_err or not calendars then
|
||||||
log.error(cal_err or 'failed to fetch calendars')
|
log.error(cal_err or 'failed to fetch calendars')
|
||||||
|
|
|
||||||
|
|
@ -337,23 +337,38 @@ local function pull_pass(access_token, tasklists, s, now_ts, by_gtasks_id)
|
||||||
return created, updated
|
return created, updated
|
||||||
end
|
end
|
||||||
|
|
||||||
---@return string? access_token
|
---@param access_token string
|
||||||
---@return table<string, string>? tasklists
|
---@return table<string, string>? tasklists
|
||||||
---@return pending.Store? store
|
---@return pending.Store? s
|
||||||
---@return string? now_ts
|
---@return string? now_ts
|
||||||
local function sync_setup()
|
local function sync_setup(access_token)
|
||||||
local access_token = client:get_access_token()
|
|
||||||
if not access_token then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
local tasklists, tl_err = get_all_tasklists(access_token)
|
local tasklists, tl_err = get_all_tasklists(access_token)
|
||||||
if tl_err or not tasklists then
|
if tl_err or not tasklists then
|
||||||
log.error(tl_err or 'failed to fetch task lists')
|
log.error(tl_err or 'failed to fetch task lists')
|
||||||
return nil
|
return nil, nil, nil
|
||||||
end
|
end
|
||||||
local s = require('pending').store()
|
local s = require('pending').store()
|
||||||
local now_ts = os.date('!%Y-%m-%dT%H:%M:%SZ') --[[@as string]]
|
local now_ts = os.date('!%Y-%m-%dT%H:%M:%SZ') --[[@as string]]
|
||||||
return access_token, tasklists, s, now_ts
|
return tasklists, s, now_ts
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param callback fun(access_token: string): nil
|
||||||
|
local function with_token(callback)
|
||||||
|
oauth.async(function()
|
||||||
|
local token = client:get_access_token()
|
||||||
|
if not token then
|
||||||
|
client:auth(function()
|
||||||
|
oauth.async(function()
|
||||||
|
local fresh = client:get_access_token()
|
||||||
|
if fresh then
|
||||||
|
callback(fresh)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
callback(token)
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.auth()
|
function M.auth()
|
||||||
|
|
@ -361,12 +376,11 @@ function M.auth()
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.push()
|
function M.push()
|
||||||
oauth.async(function()
|
with_token(function(access_token)
|
||||||
local access_token, tasklists, s, now_ts = sync_setup()
|
local tasklists, s, now_ts = sync_setup(access_token)
|
||||||
if not access_token then
|
if not tasklists then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
---@cast tasklists table<string, string>
|
|
||||||
---@cast s pending.Store
|
---@cast s pending.Store
|
||||||
---@cast now_ts string
|
---@cast now_ts string
|
||||||
local by_gtasks_id = build_id_index(s)
|
local by_gtasks_id = build_id_index(s)
|
||||||
|
|
@ -382,12 +396,11 @@ function M.push()
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.pull()
|
function M.pull()
|
||||||
oauth.async(function()
|
with_token(function(access_token)
|
||||||
local access_token, tasklists, s, now_ts = sync_setup()
|
local tasklists, s, now_ts = sync_setup(access_token)
|
||||||
if not access_token then
|
if not tasklists then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
---@cast tasklists table<string, string>
|
|
||||||
---@cast s pending.Store
|
---@cast s pending.Store
|
||||||
---@cast now_ts string
|
---@cast now_ts string
|
||||||
local by_gtasks_id = build_id_index(s)
|
local by_gtasks_id = build_id_index(s)
|
||||||
|
|
@ -403,12 +416,11 @@ function M.pull()
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.sync()
|
function M.sync()
|
||||||
oauth.async(function()
|
with_token(function(access_token)
|
||||||
local access_token, tasklists, s, now_ts = sync_setup()
|
local tasklists, s, now_ts = sync_setup(access_token)
|
||||||
if not access_token then
|
if not tasklists then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
---@cast tasklists table<string, string>
|
|
||||||
---@cast s pending.Store
|
---@cast s pending.Store
|
||||||
---@cast now_ts string
|
---@cast now_ts string
|
||||||
local by_gtasks_id = build_id_index(s)
|
local by_gtasks_id = build_id_index(s)
|
||||||
|
|
|
||||||
|
|
@ -236,12 +236,8 @@ function OAuthClient:get_access_token()
|
||||||
local creds = self:resolve_credentials()
|
local creds = self:resolve_credentials()
|
||||||
local tokens = self:load_tokens()
|
local tokens = self:load_tokens()
|
||||||
if not tokens or not tokens.refresh_token then
|
if not tokens or not tokens.refresh_token then
|
||||||
self:auth()
|
|
||||||
tokens = self:load_tokens()
|
|
||||||
if not tokens then
|
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
end
|
|
||||||
local now = os.time()
|
local now = os.time()
|
||||||
local obtained = tokens.obtained_at or 0
|
local obtained = tokens.obtained_at or 0
|
||||||
local expires = tokens.expires_in or 3600
|
local expires = tokens.expires_in or 3600
|
||||||
|
|
@ -255,8 +251,9 @@ function OAuthClient:get_access_token()
|
||||||
return tokens.access_token
|
return tokens.access_token
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param on_complete? fun(): nil
|
||||||
---@return nil
|
---@return nil
|
||||||
function OAuthClient:auth()
|
function OAuthClient:auth(on_complete)
|
||||||
local creds = self:resolve_credentials()
|
local creds = self:resolve_credentials()
|
||||||
local port = self.port
|
local port = self.port
|
||||||
|
|
||||||
|
|
@ -329,7 +326,7 @@ function OAuthClient:auth()
|
||||||
close_server()
|
close_server()
|
||||||
if code then
|
if code then
|
||||||
vim.schedule(function()
|
vim.schedule(function()
|
||||||
self:_exchange_code(creds, code, code_verifier, port)
|
self:_exchange_code(creds, code, code_verifier, port, on_complete)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
@ -347,8 +344,9 @@ end
|
||||||
---@param code string
|
---@param code string
|
||||||
---@param code_verifier string
|
---@param code_verifier string
|
||||||
---@param port integer
|
---@param port integer
|
||||||
|
---@param on_complete? fun(): nil
|
||||||
---@return nil
|
---@return nil
|
||||||
function OAuthClient:_exchange_code(creds, code, code_verifier, port)
|
function OAuthClient:_exchange_code(creds, code, code_verifier, port, on_complete)
|
||||||
local body = 'client_id='
|
local body = 'client_id='
|
||||||
.. M.url_encode(creds.client_id)
|
.. M.url_encode(creds.client_id)
|
||||||
.. '&client_secret='
|
.. '&client_secret='
|
||||||
|
|
@ -387,6 +385,9 @@ function OAuthClient:_exchange_code(creds, code, code_verifier, port)
|
||||||
decoded.obtained_at = os.time()
|
decoded.obtained_at = os.time()
|
||||||
self:save_tokens(decoded)
|
self:save_tokens(decoded)
|
||||||
log.info(self.name .. ' authorized successfully.')
|
log.info(self.name .. ' authorized successfully.')
|
||||||
|
if on_complete then
|
||||||
|
on_complete()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param opts { name: string, scope: string, port: integer, config_key: string }
|
---@param opts { name: string, scope: string, port: integer, config_key: string }
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue