-
Notifications
You must be signed in to change notification settings - Fork 47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Move from deferred.el to another asynchronous execution framework #159
Comments
emacs-aio looks promising - see https://nullprogram.com/blog/2019/03/10/. Unfortunately, you can't fully preserve stack traces in Emacs, but perhaps this will still make the code easier to read and not prone to stack overflows. |
I've decided to go with emacs-aio - since it uses the Emacs generator framework, code written using this framework looks just like async/await code in many modern languages, so it will be a lot easier to read than others. I've decided to go with emacs-aio instead of emacs-async-await because it uses Emacs errors instead of a separate (aio-defun org-gcal--get-event-aio (calendar-id event-id)
"Retrieves a Google Calendar event given a CALENDAR-ID and EVENT-ID.
Refreshes the access token if needed.
Returns an ‘aio-promise’ for a ‘request-response' object."
(let* ((a-token (org-gcal--get-access-token))
(response
(aio-await
(org-gcal--aio-request
(concat
(org-gcal-events-url calendar-id)
(concat "/" event-id))
:type "GET"
:headers
`(("Accept" . "application/json")
("Authorization" . ,(format "Bearer %s" a-token)))
:parser 'org-gcal--json-read)))
(_data (request-response-data response))
(status-code (request-response-status-code response))
(error-thrown (request-response-error-thrown response)))
(cond
;; If there is no network connectivity, the response will not
;; include a status code.
((eq status-code nil)
(org-gcal--notify
"Got Error"
"Could not contact remote service. Please check your network connectivity.")
(error "Network connectivity issue"))
((eq 401 (or (plist-get (plist-get (request-response-data response) :error) :code)
status-code))
(org-gcal--notify
"Received HTTP 401"
"OAuth token expired. Now trying to refresh token.")
(aio-await (org-gcal--refresh-token-aio))
(aio-await (org-gcal--get-event-aio calendar-id event-id)))
;; Generic error-handler meant to provide useful information about
;; failure cases not otherwise explicitly specified.
((not (eq error-thrown nil))
(org-gcal--notify
(concat "Status code: " (number-to-string status-code))
(pp-to-string error-thrown))
(error "Got error %S: %S" status-code error-thrown))
;; Fetch was successful.
(t response))))
(aio-defun org-gcal--refresh-token-aio ()
"Refresh OAuth access and return the new access token as a deferred object."
(let* ((response
(aio-await
(org-gcal--aio-request
org-gcal-token-url
:type "POST"
:data `(("client_id" . ,org-gcal-client-id)
("client_secret" . ,org-gcal-client-secret)
("refresh_token" . ,(org-gcal--get-refresh-token))
("grant_type" . "refresh_token"))
:parser 'org-gcal--json-read)))
(data (request-response-data response))
(status-code (request-response-status-code response))
(error-thrown (request-response-error-thrown response)))
(cond
((eq error-thrown nil)
(plist-put org-gcal-token-plist
:access_token
(plist-get data :access_token))
(org-gcal--save-sexp org-gcal-token-plist org-gcal-token-file)
(let ((token (plist-get org-gcal-token-plist :access_token)))
token))
(t
(error "Got error %S: %S" status-code error-thrown)))))
|
I want to accomplish several things with this:
deferred.el
code are generally useless, which makes it hard to debug issues in this library.deferred
chains ordeferred:loop
) there is no tail call elimination, so eventually you will stack overflow. I got around this by throwing and catching errors (seeorg-gcal--sync-buffer-inner
from Enable entries to be managed either by Org or Google Calendar #129), but this also makes the stack hard to follow.The text was updated successfully, but these errors were encountered: