mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-02-17 10:27:41 +00:00
Jsonrpc: clean up previous change
* lisp/jsonrpc.el (jsonrpc-connection): Rework slot names. (jsonrpc-connection-receive): Rework. (jsonrpc--call-deferred): Fix typo. (jsonrpc--process-sentinel) (jsonrpc--remove): Use new slot names. (jsonrpc--continue): Rework. (jsonrpc--async-request-1): Rework. (jsonrpc--event): Remember to remove :jsonrpc-json from foreign-message (jsonrpc--connection-receive): Revamp. (jsonrpc--connection-send) (jsonrpc--connection-reply): Rework. (jsonrpc--log-event): Revamp. (jsonrpc-continuation-count): Use new slot name.
This commit is contained in:
parent
27d2395879
commit
dceffddbfe
1 changed files with 194 additions and 149 deletions
343
lisp/jsonrpc.el
343
lisp/jsonrpc.el
|
|
@ -68,9 +68,9 @@
|
|||
:initform nil
|
||||
:accessor jsonrpc-last-error
|
||||
:documentation "Last JSONRPC error message received from endpoint.")
|
||||
(-request-continuations
|
||||
(-continuations
|
||||
:initform nil
|
||||
:accessor jsonrpc--request-continuations
|
||||
:accessor jsonrpc--continuations
|
||||
:documentation "An alist of request IDs to continuation specs.")
|
||||
(-events-buffer
|
||||
:initform nil
|
||||
|
|
@ -221,7 +221,7 @@ JSONRPC message."
|
|||
|
||||
(defun jsonrpc-forget-pending-continuations (connection)
|
||||
"Stop waiting for responses from the current JSONRPC CONNECTION."
|
||||
(setf (jsonrpc--request-continuations connection) nil))
|
||||
(setf (jsonrpc--continuations connection) nil))
|
||||
|
||||
(defvar jsonrpc-inhibit-debug-on-error nil
|
||||
"Inhibit `debug-on-error' when answering requests.
|
||||
|
|
@ -231,67 +231,96 @@ error and replying to the endpoint with an JSONRPC-error. This
|
|||
variable can be set around calls like `jsonrpc-request' to
|
||||
circumvent that.")
|
||||
|
||||
(defun jsonrpc-connection-receive (conn message)
|
||||
"Process MESSAGE just received from CONN.
|
||||
(defun jsonrpc-connection-receive (conn foreign-message)
|
||||
"Process FOREIGN-MESSAGE just received from CONN.
|
||||
This function will destructure MESSAGE and call the appropriate
|
||||
dispatcher in CONN."
|
||||
(cl-destructuring-bind (&rest whole &key method id error params result _jsonrpc)
|
||||
(jsonrpc-convert-from-endpoint conn message)
|
||||
(jsonrpc-convert-from-endpoint conn foreign-message)
|
||||
(unwind-protect
|
||||
(with-slots (last-error
|
||||
(rdispatcher -request-dispatcher)
|
||||
(ndispatcher -notification-dispatcher)
|
||||
(sr-alist -sync-request-alist))
|
||||
conn
|
||||
(setf last-error error)
|
||||
(cond
|
||||
(;; A remote request
|
||||
(and method id)
|
||||
(let* ((debug-on-error (and debug-on-error
|
||||
(not jsonrpc-inhibit-debug-on-error)))
|
||||
(reply
|
||||
(condition-case-unless-debug _ignore
|
||||
(condition-case oops
|
||||
`(:result ,(funcall rdispatcher conn (intern method)
|
||||
params))
|
||||
(jsonrpc-error
|
||||
`(:error
|
||||
(:code
|
||||
,(or (alist-get 'jsonrpc-error-code (cdr oops))
|
||||
-32603)
|
||||
:message ,(or (alist-get 'jsonrpc-error-message
|
||||
(cdr oops))
|
||||
"Internal error")))))
|
||||
(error
|
||||
'(:error (:code -32603 :message "Internal error"))))))
|
||||
(apply #'jsonrpc--reply conn id method reply)))
|
||||
(;; A remote notification
|
||||
method
|
||||
(funcall ndispatcher conn (intern method) params))
|
||||
(id
|
||||
(let ((cont
|
||||
;; remove the continuation
|
||||
(jsonrpc--remove conn id)))
|
||||
(pcase-let ((`(,_ ,method ,_ ,_ ,_) cont))
|
||||
(if (keywordp method)
|
||||
(setq method (substring (symbol-name method) 1)))
|
||||
(setq whole (plist-put whole :method method)))
|
||||
(cond (;; A remote response, but it can't run yet,
|
||||
;; because there's an outstanding sync request
|
||||
;; (bug#67945)
|
||||
(and sr-alist (not (eq id (caar sr-alist))))
|
||||
(push (cons cont (list result error))
|
||||
(cdr (car sr-alist))))
|
||||
(;; A remote response that can run
|
||||
(jsonrpc--continue conn id cont result error)))))))
|
||||
(jsonrpc--run-event-hook
|
||||
conn 'server
|
||||
:json (plist-get message :jsonrpc-json)
|
||||
:kind (cond ((and method id) 'request)
|
||||
(method 'notification)
|
||||
(id 'reply))
|
||||
:message whole
|
||||
:foreign-message message)
|
||||
(let* ((log-plist (list :json (plist-get foreign-message :jsonrpc-json)
|
||||
:kind (cond ((and method id) 'request)
|
||||
(method 'notification)
|
||||
(id 'reply))
|
||||
:message whole
|
||||
:foreign-message foreign-message))
|
||||
(response-p (and (null method) id))
|
||||
(cont (and response-p (jsonrpc--remove conn id))))
|
||||
(cl-remf foreign-message :jsonrpc-json)
|
||||
;; Do this pre-processing of the response so we can always
|
||||
;; log richer information _before_ any non-local calls
|
||||
;; further ahead. Putting the `jsonrpc--event' as
|
||||
;; an unwind-form would make us log after the fact.
|
||||
(when cont
|
||||
(pcase-let ((`(,_ ,method ,_ ,_ ,_) cont))
|
||||
(if (keywordp method)
|
||||
(setq method (substring (symbol-name method) 1)))
|
||||
;; TODO: also set the depth
|
||||
(setq whole (plist-put whole :method method))))
|
||||
|
||||
;; Do the logging
|
||||
(apply #'jsonrpc--event conn 'server log-plist)
|
||||
(with-slots (last-error
|
||||
(rdispatcher -request-dispatcher)
|
||||
(ndispatcher -notification-dispatcher)
|
||||
(sr-alist -sync-request-alist))
|
||||
conn
|
||||
(setf last-error error)
|
||||
(cond
|
||||
(;; A remote response whose request has been cancelled
|
||||
;; (i.e. timeout or C-g)
|
||||
;;
|
||||
(and response-p (null cont))
|
||||
(jsonrpc--event
|
||||
conn 'internal
|
||||
:log-text
|
||||
(format "Response to request %s which has been cancelled"
|
||||
id)
|
||||
:id id)
|
||||
;; TODO: food for thought: this seems to be also where
|
||||
;; notifying the server of the cancellation would come
|
||||
;; in.
|
||||
)
|
||||
(;; A remote response that can't run yet (bug#67945)
|
||||
(and response-p
|
||||
(and sr-alist (not (eq id (caar sr-alist)))))
|
||||
(jsonrpc--event
|
||||
conn 'internal
|
||||
:log-text
|
||||
(format "anxious continuation to %s can't run, held up by %s"
|
||||
id
|
||||
(mapcar #'car sr-alist)))
|
||||
(push (cons cont (list result error))
|
||||
(cdr (car sr-alist))))
|
||||
(;; A remote response that can continue now
|
||||
response-p
|
||||
(jsonrpc--continue conn id cont result error))
|
||||
(;; A remote request
|
||||
(and method id)
|
||||
(let* ((debug-on-error (and debug-on-error
|
||||
(not jsonrpc-inhibit-debug-on-error)))
|
||||
(reply
|
||||
(condition-case-unless-debug _ignore
|
||||
(condition-case oops
|
||||
`(:result ,(funcall rdispatcher conn (intern method)
|
||||
params))
|
||||
(jsonrpc-error
|
||||
`(:error
|
||||
(:code
|
||||
,(or (alist-get 'jsonrpc-error-code (cdr oops))
|
||||
-32603)
|
||||
:message ,(or (alist-get 'jsonrpc-error-message
|
||||
(cdr oops))
|
||||
"Internal error")))))
|
||||
(error
|
||||
'(:error (:code -32603 :message "Internal error"))))))
|
||||
(apply #'jsonrpc--reply conn id method reply)))
|
||||
(;; A remote notification
|
||||
method
|
||||
(funcall ndispatcher conn (intern method) params))
|
||||
(t
|
||||
(jsonrpc--event conn 'internal
|
||||
:log-text "Malformed message" )))))
|
||||
(jsonrpc--call-deferred conn))))
|
||||
|
||||
|
||||
|
|
@ -408,15 +437,18 @@ ignored."
|
|||
(setq canceled t))
|
||||
`(canceled ,cancel-on-input-retval))
|
||||
(t (while t (accept-process-output nil 30)))))
|
||||
;; In normal operation, cancellation is handled by the
|
||||
;; timeout function and response filter, but we still have
|
||||
;; to protect against user-quit (C-g) or the
|
||||
;; `cancel-on-input' case.
|
||||
;; In normal operation, continuations for error/success is
|
||||
;; handled by `jsonrpc-continue'. Timeouts also remove
|
||||
;; the continuation...
|
||||
(pcase-let* ((`(,id ,_) id-and-timer))
|
||||
;; Discard the continuation
|
||||
;; ...but we still have to guard against exist explicit
|
||||
;; user-quit (C-g) or the `cancel-on-input' case, so
|
||||
;; discard the continuation.
|
||||
(jsonrpc--remove connection id (list deferred (current-buffer)))
|
||||
;; We still call `jsonrpc--continue' to run any
|
||||
;; "anxious" continuations.
|
||||
;; ...finally, whatever may have happened to this sync
|
||||
;; request, it might have been holding up any outer
|
||||
;; "anxious" continuations. The following ensures we
|
||||
;; cll them.
|
||||
(jsonrpc--continue connection id)))))
|
||||
(when (eq 'error (car retval))
|
||||
(signal 'jsonrpc-error
|
||||
|
|
@ -527,8 +559,8 @@ connection object, called when the process dies.")
|
|||
((stringp method) method)
|
||||
(t (error "[jsonrpc] invalid method %s" method))))))
|
||||
(let* ((kind (cond ((or result-supplied-p error) 'reply)
|
||||
(id 'request)
|
||||
(method 'notification)))
|
||||
(id 'request)
|
||||
(method 'notification)))
|
||||
(converted (jsonrpc-convert-to-endpoint connection args kind))
|
||||
(json (jsonrpc--json-encode converted))
|
||||
(headers
|
||||
|
|
@ -540,7 +572,7 @@ connection object, called when the process dies.")
|
|||
(cl-loop for (header . value) in headers
|
||||
concat (concat header ": " value "\r\n") into header-section
|
||||
finally return (format "%s\r\n%s" header-section json)))
|
||||
(jsonrpc--run-event-hook
|
||||
(jsonrpc--event
|
||||
connection
|
||||
'client
|
||||
:json json
|
||||
|
|
@ -624,7 +656,7 @@ With optional CLEANUP, kill any associated buffers."
|
|||
(defun jsonrpc--call-deferred (connection)
|
||||
"Call CONNECTION's deferred actions, who may again defer themselves."
|
||||
(when-let ((actions (hash-table-values (jsonrpc--deferred-actions connection))))
|
||||
(jsonrpc--run-event-hook
|
||||
(jsonrpc--event
|
||||
connection 'internal
|
||||
:log-text (format "re-attempting deferred requests %s"
|
||||
(mapcar (apply-partially #'nth 2) actions)))
|
||||
|
|
@ -641,7 +673,7 @@ With optional CLEANUP, kill any associated buffers."
|
|||
;; Cancel outstanding timers
|
||||
(mapc (jsonrpc-lambda (_id _method _success-fn _error-fn timer)
|
||||
(when timer (cancel-timer timer)))
|
||||
(jsonrpc--request-continuations connection))
|
||||
(jsonrpc--continuations connection))
|
||||
(maphash (lambda (_ triplet)
|
||||
(pcase-let ((`(,_ ,timer ,_) triplet))
|
||||
(when timer (cancel-timer timer))))
|
||||
|
|
@ -651,7 +683,7 @@ With optional CLEANUP, kill any associated buffers."
|
|||
;; Call all outstanding error handlers
|
||||
(mapc (jsonrpc-lambda (_id _method _success-fn error-fn _timer)
|
||||
(funcall error-fn '(:code -1 :message "Server died")))
|
||||
(jsonrpc--request-continuations connection))
|
||||
(jsonrpc--continuations connection))
|
||||
(jsonrpc--message "Server exited with status %s" (process-exit-status proc))
|
||||
(delete-process proc)
|
||||
(when-let (p (slot-value connection '-autoport-inferior)) (delete-process p))
|
||||
|
|
@ -746,48 +778,53 @@ With optional CLEANUP, kill any associated buffers."
|
|||
"Cancel CONN's continuations for ID, including its timer, if it exists.
|
||||
Also cancel \"deferred actions\" if DEFERRED-SPEC.
|
||||
Return the full continuation (ID SUCCESS-FN ERROR-FN TIMER)"
|
||||
(with-slots ((conts -request-continuations) (defs -deferred-actions)) conn
|
||||
(with-slots ((conts -continuations) (defs -deferred-actions)) conn
|
||||
(if deferred-spec (remhash deferred-spec defs))
|
||||
(when-let ((ass (assq id conts)))
|
||||
(cl-destructuring-bind (_ _ _ _ timer) ass
|
||||
(cancel-timer timer))
|
||||
(cancel-timer timer))
|
||||
(setf conts (delete ass conts))
|
||||
ass)))
|
||||
|
||||
(defun jsonrpc--schedule (conn id method success-fn error-fn timer)
|
||||
(push (list id method success-fn error-fn timer)
|
||||
(jsonrpc--request-continuations conn)))
|
||||
(jsonrpc--continuations conn)))
|
||||
|
||||
(defun jsonrpc--continue (conn id &optional cont result error)
|
||||
(pcase-let* ((`(,cont-id ,_method ,success-fn ,error-fn ,_timer)
|
||||
cont)
|
||||
(head (pop (jsonrpc--sync-request-alist conn)))
|
||||
(anxious (cdr head)))
|
||||
(cond (anxious
|
||||
(when (not (= (car head) id)) ; sanity check
|
||||
(error "internal error: please report this bug"))
|
||||
;; If there are "anxious" `jsonrpc-request' continuations
|
||||
;; that should already have been run, they should run now.
|
||||
;; The main continuation -- if it exists -- should run
|
||||
;; before them. This order is important to preserve the
|
||||
;; throw to the catch tags in `jsonrpc-request' in
|
||||
;; order (bug#67945).
|
||||
(cl-flet ((later (f arg) (run-at-time 0 nil f arg)))
|
||||
(when cont-id
|
||||
(if error (later error-fn error)
|
||||
(later success-fn result)))
|
||||
(cl-loop for (acont ares aerr) in anxious
|
||||
for (_id _method success-fn error-fn) = acont
|
||||
if aerr do (later error-fn aerr)
|
||||
else do (later success-fn ares))))
|
||||
(cont-id
|
||||
;; Else, just run the normal one, with plain funcall.
|
||||
(if error (funcall error-fn error)
|
||||
(funcall success-fn result)))
|
||||
(t
|
||||
;; For clarity. This happens if the `jsonrpc-request' was
|
||||
;; canceled
|
||||
))))
|
||||
(cond
|
||||
(anxious
|
||||
(when (not (= (car head) id)) ; sanity check
|
||||
(error "internal error: please report this bug"))
|
||||
;; If there are "anxious" `jsonrpc-request' continuations
|
||||
;; that should already have been run, they should run now.
|
||||
;; The main continuation -- if it exists -- should run
|
||||
;; before them. This order is important to preserve the
|
||||
;; throw to the catch tags in `jsonrpc-request' in
|
||||
;; order (bug#67945).
|
||||
(cl-flet ((later (f arg) (run-at-time 0 nil f arg)))
|
||||
(when cont-id
|
||||
(if error (later error-fn error)
|
||||
(later success-fn result)))
|
||||
(cl-loop
|
||||
for (acont ares aerr) in anxious
|
||||
for (anx-id _method success-fn error-fn) = acont
|
||||
do (jsonrpc--event
|
||||
conn 'internal
|
||||
:log-text (format "anxious continuation to %s running now" anx-id))
|
||||
if aerr do (later error-fn aerr)
|
||||
else do (later success-fn ares))))
|
||||
(cont-id
|
||||
;; Else, just run the normal one, with plain funcall.
|
||||
(if error (funcall error-fn error)
|
||||
(funcall success-fn result)))
|
||||
(t
|
||||
;; For clarity. This happens if the `jsonrpc-request' was
|
||||
;; cancelled
|
||||
))))
|
||||
|
||||
(cl-defun jsonrpc--async-request-1 (connection
|
||||
method
|
||||
|
|
@ -817,20 +854,20 @@ TIMEOUT is nil)."
|
|||
timeout nil
|
||||
(lambda ()
|
||||
(jsonrpc--remove connection id (list deferred buf))
|
||||
(if timeout-fn (funcall timeout-fn)
|
||||
(jsonrpc--run-event-hook
|
||||
connection 'internal
|
||||
:log-text (format "timed-out '%s' (id=%s)" method id)
|
||||
:id id))))))))))
|
||||
(jsonrpc--event
|
||||
connection 'internal
|
||||
:log-text (format "timed-out request '%s'" method)
|
||||
:id id)
|
||||
(when timeout-fn (funcall timeout-fn))))))))))
|
||||
(when deferred
|
||||
(if (jsonrpc-connection-ready-p connection deferred)
|
||||
;; Server is ready, we jump below and send it immediately.
|
||||
(remhash (list deferred buf) (jsonrpc--deferred-actions connection))
|
||||
;; Otherwise, save in `jsonrpc--deferred-actions' and exit non-locally
|
||||
(unless old-id
|
||||
(jsonrpc--run-event-hook
|
||||
(jsonrpc--event
|
||||
connection 'internal
|
||||
:log-text (format "deferring '%s' (id=%s)" method id)
|
||||
:log-text (format "deferring request '%s'" method)
|
||||
:id id))
|
||||
(puthash (list deferred buf)
|
||||
(list (lambda ()
|
||||
|
|
@ -858,13 +895,13 @@ TIMEOUT is nil)."
|
|||
connection id method
|
||||
(or success-fn
|
||||
(lambda (&rest _ignored)
|
||||
(jsonrpc--run-event-hook
|
||||
(jsonrpc--event
|
||||
connection 'internal
|
||||
:log-text (format "success ignored")
|
||||
:id id)))
|
||||
(or error-fn
|
||||
(jsonrpc-lambda (&key code message &allow-other-keys)
|
||||
(jsonrpc--run-event-hook
|
||||
(jsonrpc--event
|
||||
connection 'internal
|
||||
:log-text (format "error %s ignored: %s ignored"
|
||||
code message)
|
||||
|
|
@ -892,15 +929,20 @@ TIMEOUT is nil)."
|
|||
(apply #'format format args)
|
||||
:warning)))
|
||||
|
||||
(cl-defun jsonrpc--run-event-hook (connection
|
||||
origin
|
||||
&rest plist
|
||||
&key _kind _json _message _foreign-message _log-text
|
||||
&allow-other-keys)
|
||||
(cl-defun jsonrpc--event (connection
|
||||
origin
|
||||
&rest plist
|
||||
&key _kind _json _message _foreign-message _log-text
|
||||
&allow-other-keys)
|
||||
(with-current-buffer (jsonrpc-events-buffer connection)
|
||||
(run-hook-wrapped 'jsonrpc-event-hook
|
||||
(lambda (fn)
|
||||
(apply fn connection origin plist)))))
|
||||
(condition-case oops
|
||||
(apply fn connection origin plist)
|
||||
(error
|
||||
(jsonrpc--message "event hook '%s' errored (%s). Removing it"
|
||||
fn oops)
|
||||
(remove-hook 'jsonrpc-event-hook fn)))))))
|
||||
|
||||
(defvar jsonrpc-event-hook (list #'jsonrpc--log-event)
|
||||
"Hook run when JSON-RPC events are emitted.
|
||||
|
|
@ -931,9 +973,9 @@ Do not use this hook to write JSON-RPC protocols, use other parts
|
|||
of the API instead.")
|
||||
|
||||
(cl-defun jsonrpc--log-event (connection origin
|
||||
&key kind message
|
||||
&key _kind message
|
||||
foreign-message log-text json
|
||||
type
|
||||
type ((:id ref-id))
|
||||
&allow-other-keys)
|
||||
"Log a JSONRPC-related event. Installed in `jsonrpc-event-hook'."
|
||||
(let* ((props (slot-value connection '-events-buffer-config))
|
||||
|
|
@ -942,32 +984,35 @@ of the API instead.")
|
|||
(when (or (null max) (cl-plusp max))
|
||||
(cl-destructuring-bind (&key method id error &allow-other-keys) message
|
||||
(let* ((inhibit-read-only t)
|
||||
(depth (length (jsonrpc--sync-request-alist connection)))
|
||||
(depth (length
|
||||
(jsonrpc--sync-request-alist connection)))
|
||||
(preamble (format "[jsonrpc] %s[%s]%s "
|
||||
(pcase type ('error "E") ('debug "D")
|
||||
(_ (pcase origin
|
||||
('internal "i")
|
||||
(_ "e"))))
|
||||
(format-time-string "%H:%M:%S.%3N")
|
||||
(if (eq origin 'internal)
|
||||
(if ref-id (format " [%s]" ref-id) "")
|
||||
(format " %s%s %s%s"
|
||||
(make-string (* 2 depth) ? )
|
||||
(pcase origin
|
||||
('client "-->")
|
||||
('server "<--")
|
||||
(_ ""))
|
||||
(or method "")
|
||||
(if id (format "[%s]" id) "")))))
|
||||
(msg
|
||||
(cond ((eq format 'full)
|
||||
(format "[jsonrpc] %s[%s]%s %s\n"
|
||||
(pcase type ('error "E") ('debug "D") (_ "e"))
|
||||
(format-time-string "%H:%M:%S.%3N")
|
||||
(if (eq origin 'internal)
|
||||
""
|
||||
(format " %s%s %s%s"
|
||||
(make-string (* 2 depth) ? )
|
||||
(pcase origin
|
||||
('client "-->")
|
||||
('server "<--")
|
||||
(_ ""))
|
||||
(or method "")
|
||||
(if id (format "(%s)" id) "")))
|
||||
(or json log-text)))
|
||||
(format "%s%s\n" preamble (or json log-text)))
|
||||
((eq format 'short)
|
||||
(format "%s%s\n" preamble (or log-text "")))
|
||||
(t
|
||||
(format "[%s]%s%s %s:\n%s"
|
||||
(concat (format "%s" (or origin 'internal))
|
||||
(if origin (format "-%s" (or kind 'message))))
|
||||
(if id (format " (id:%s)" id) "")
|
||||
(if error " ERROR" "")
|
||||
(format-time-string "%H:%M:%S.%3N")
|
||||
(if foreign-message (pp-to-string foreign-message)
|
||||
log-text))))))
|
||||
(format "%s%s" preamble
|
||||
(or (and foreign-message
|
||||
(concat "\n" (pp-to-string
|
||||
foreign-message)))
|
||||
(concat log-text "\n")))))))
|
||||
(goto-char (point-max))
|
||||
;; XXX: could use `run-at-time' to delay server logs
|
||||
;; slightly to play nice with verbose servers' stderr.
|
||||
|
|
@ -976,13 +1021,13 @@ of the API instead.")
|
|||
(insert-before-markers msg)
|
||||
;; Trim the buffer if it's too large
|
||||
(when max
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(while (> (buffer-size) max)
|
||||
(delete-region (point) (progn (forward-line 1)
|
||||
(forward-sexp 1)
|
||||
(forward-line 2)
|
||||
(point)))))))))))
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(while (> (buffer-size) max)
|
||||
(delete-region (point) (progn (forward-line 1)
|
||||
(forward-sexp 1)
|
||||
(forward-line 2)
|
||||
(point)))))))))))
|
||||
|
||||
(defun jsonrpc--forwarding-buffer (name prefix conn)
|
||||
"Helper for `jsonrpc-process-connection' helpers.
|
||||
|
|
@ -1092,7 +1137,7 @@ CONNECT-ARGS are passed as additional arguments to
|
|||
|
||||
(defun jsonrpc-continuation-count (conn)
|
||||
"Number of outstanding continuations for CONN."
|
||||
(length (jsonrpc--request-continuations conn)))
|
||||
(length (jsonrpc--continuations conn)))
|
||||
|
||||
(provide 'jsonrpc)
|
||||
;;; jsonrpc.el ends here
|
||||
|
|
|
|||
Loading…
Reference in a new issue