mirror of
https://github.com/vale981/emacs-jupyter
synced 2025-03-06 07:51:39 -05:00
Replace jupyter-channel-ioloop-comm
internals with new impl.
* jupyter-comm-layer.el (jupyter-comm-initialize): Remove default method. This is in preparation for moving over to classless communication. * jupyter-channel-ioloop-comm (jupyter-connection): Require. (jupyter--proxy-channel): New type. (jupyter--make-channel-group, jupyter--channel-alive-p) (jupyter--start-channel, jupyter--stop-channel) (make-jupyter-async-connection): New functions. (jupyter-channel-ioloop-comm): Remove `ioloop-class` slot, update all callers. Remove `channels` slot, update all setters and references. Add `conn` slot which holds a `jupyter-connection`. (jupyter-comm-initialize): Initialize the `conn` slot to the connection returned by `make-jupyter-async-connection`. (jupyter-comm-start, jupyter-comm-stop) (jupyter-comm-alive-p, jupyter-comm-id, jupyter-channel-alive-p) (jupyter-stop-channel, jupyter-start-channel): Replace the body of these functions with their equivalents in `conn`. * jupyter-kernel-process-manager.el (jupyter-make-client): Update `jupyter-channel-ioloop-comm` call. * jupyter-repl.el: (jupyter-connect-repl): Ditto. * test/test-helper.el (initialize-instance) [jupyter-echo-client]: Ditto. Replace setting of `channel` slot with setting the `conn` clot.
This commit is contained in:
parent
7a11c8f0ac
commit
93eeda42a6
5 changed files with 130 additions and 99 deletions
|
@ -47,113 +47,151 @@
|
|||
(require 'jupyter-base)
|
||||
(require 'jupyter-ioloop-comm)
|
||||
(require 'jupyter-channel-ioloop)
|
||||
(require 'jupyter-connection)
|
||||
|
||||
;;; New implementation
|
||||
|
||||
(cl-defstruct jupyter--proxy-channel endpoint alive-p)
|
||||
|
||||
(defun jupyter--make-channel-group (session)
|
||||
(let ((endpoints (jupyter-session-endpoints session)))
|
||||
(append
|
||||
(list 'channel-group t
|
||||
:hb (make-instance
|
||||
'jupyter-hb-channel
|
||||
:session session
|
||||
:endpoint (plist-get endpoints :hb)))
|
||||
(cl-loop
|
||||
for channel in '(:control :shell :iopub :stdin)
|
||||
collect channel
|
||||
collect (make-jupyter--proxy-channel
|
||||
:endpoint (plist-get endpoints channel)
|
||||
:alive-p nil)))))
|
||||
|
||||
(defun jupyter--channel-alive-p (ioloop chgroup channel)
|
||||
(if (eq channel :hb)
|
||||
(let ((hb (plist-get chgroup channel)))
|
||||
(and hb (jupyter-channel-alive-p hb)))
|
||||
(and ioloop (jupyter-ioloop-alive-p ioloop)
|
||||
(jupyter--proxy-channel-alive-p
|
||||
(plist-get chgroup channel)))))
|
||||
|
||||
(defun jupyter--start-channel (ioloop chgroup channel)
|
||||
(unless (jupyter--channel-alive-p ioloop chgroup channel)
|
||||
(if (eq channel :hb) (jupyter-start-channel (plist-get chgroup channel))
|
||||
(let ((endpoint (jupyter--proxy-channel-endpoint
|
||||
(plist-get chgroup channel))))
|
||||
(jupyter-send ioloop 'start-channel channel endpoint)
|
||||
;; Verify that the channel starts
|
||||
(jupyter-with-timeout
|
||||
(nil jupyter-default-timeout
|
||||
(error "Channel not started in ioloop subprocess (%s)" channel))
|
||||
(jupyter--channel-alive-p ioloop chgroup channel))))))
|
||||
|
||||
(defun jupyter--stop-channel (ioloop chgroup channel)
|
||||
(when (jupyter--channel-alive-p ioloop chgroup channel)
|
||||
(if (eq channel :hb) (jupyter-stop-channel (plist-get chgroup channel))
|
||||
(jupyter-send ioloop 'stop-channel channel)
|
||||
;; Verify that the channel stops
|
||||
(jupyter-with-timeout
|
||||
(nil jupyter-default-timeout
|
||||
(error "Channel not stopped in ioloop subprocess (%s)" channel))
|
||||
(not (jupyter--channel-alive-p ioloop chgroup channel))))))
|
||||
|
||||
(defun make-jupyter-async-connection (session handler)
|
||||
"Send kernel messages asynchronously."
|
||||
(require 'jupyter-zmq-channel-ioloop)
|
||||
(let ((channels '(:hb :shell :iopub :stdin))
|
||||
(chgroup (jupyter--make-channel-group session))
|
||||
(ioloop (make-instance 'jupyter-zmq-channel-ioloop)))
|
||||
(jupyter-channel-ioloop-set-session ioloop session)
|
||||
(make-jupyter-connection
|
||||
:hb (plist-get chgroup :hb)
|
||||
:id (lambda ()
|
||||
(format "session=%s" (truncate-string-to-width
|
||||
(jupyter-session-id session)
|
||||
9 nil nil "…")))
|
||||
:start (lambda (&optional channel)
|
||||
(unless (jupyter-ioloop-alive-p ioloop)
|
||||
(jupyter-ioloop-start
|
||||
ioloop (lambda (event)
|
||||
(pcase (car event)
|
||||
;; These channel events are from
|
||||
;; `jupyter-channel-ioloop'
|
||||
('start-channel
|
||||
(setf (jupyter--proxy-channel-alive-p
|
||||
(plist-get chgroup (cadr event)))
|
||||
t))
|
||||
('stop-channel
|
||||
(setf (jupyter--proxy-channel-alive-p
|
||||
(plist-get chgroup (cadr event)))
|
||||
nil))
|
||||
(_
|
||||
(funcall handler event))))))
|
||||
(if channel (jupyter--start-channel ioloop chgroup channel)
|
||||
(cl-loop
|
||||
for channel in channels
|
||||
do (jupyter--start-channel ioloop chgroup channel))))
|
||||
:stop (lambda (&optional channel)
|
||||
(if channel (jupyter--stop-channel ioloop chgroup channel)
|
||||
(cl-loop
|
||||
for channel in channels
|
||||
do (jupyter--stop-channel ioloop chgroup channel))
|
||||
(jupyter-ioloop-stop ioloop))
|
||||
(jupyter-ioloop-stop ioloop))
|
||||
:send (lambda (&rest event)
|
||||
(apply #'jupyter-send ioloop event))
|
||||
:alive-p (lambda (&optional channel)
|
||||
(if channel (jupyter--channel-alive-p ioloop chgroup channel)
|
||||
(cl-loop
|
||||
for channel in channels
|
||||
thereis (jupyter--channel-alive-p ioloop chgroup channel)))))))
|
||||
|
||||
;;; Old implementation
|
||||
|
||||
(cl-defstruct jupyter-proxy-channel endpoint alive-p)
|
||||
|
||||
(defclass jupyter-channel-ioloop-comm (jupyter-ioloop-comm
|
||||
jupyter-hb-comm
|
||||
jupyter-comm-autostop)
|
||||
((ioloop-class :type class :initarg :ioloop-class)
|
||||
(session :type jupyter-session)
|
||||
(channels :type (list-of (or keyword jupyter-proxy-channel)) :initform nil)))
|
||||
|
||||
(cl-defmethod initialize-instance ((comm jupyter-channel-ioloop-comm) &optional _slots)
|
||||
(cl-call-next-method)
|
||||
(unless (slot-boundp comm 'ioloop-class)
|
||||
(oset comm ioloop-class 'jupyter-channel-ioloop))
|
||||
(with-slots (ioloop-class) comm
|
||||
(jupyter-error-if-not-client-class-p ioloop-class 'jupyter-channel-ioloop)
|
||||
(oset comm ioloop (make-instance ioloop-class))))
|
||||
((conn :type jupyter-connection)
|
||||
(session :type jupyter-session)))
|
||||
|
||||
(cl-defmethod jupyter-comm-id ((comm jupyter-channel-ioloop-comm))
|
||||
(format "session=%s" (truncate-string-to-width
|
||||
(jupyter-session-id (oref comm session))
|
||||
9 nil nil "…")))
|
||||
(jupyter-conn-id (oref comm conn)))
|
||||
|
||||
(cl-defmethod jupyter-comm-initialize ((comm jupyter-channel-ioloop-comm)
|
||||
(session jupyter-session))
|
||||
(cl-call-next-method)
|
||||
(let ((endpoints (jupyter-session-endpoints session)))
|
||||
(oset comm session (copy-sequence session))
|
||||
(oset comm hb (make-instance
|
||||
'jupyter-hb-channel
|
||||
:session (oref comm session)
|
||||
:endpoint (plist-get endpoints :hb)))
|
||||
(oset comm channels (cl-loop
|
||||
for channel in '(:stdin :shell :iopub)
|
||||
collect channel and
|
||||
collect (make-jupyter-proxy-channel
|
||||
:endpoint (plist-get endpoints channel)
|
||||
:alive-p nil)))))
|
||||
(session jupyter-session))
|
||||
(oset comm session session)
|
||||
(let ((conn (make-jupyter-async-connection
|
||||
session (lambda (event) (jupyter-event-handler comm event)))))
|
||||
(oset comm conn conn)
|
||||
(oset comm hb (jupyter-connection-hb (oref comm conn)))))
|
||||
|
||||
(cl-defmethod jupyter-comm-start ((comm jupyter-channel-ioloop-comm))
|
||||
(with-slots (ioloop session) comm
|
||||
(unless (jupyter-ioloop-alive-p ioloop)
|
||||
(jupyter-channel-ioloop-set-session ioloop (oref comm session))
|
||||
(jupyter-ioloop-start
|
||||
ioloop (lambda (event)
|
||||
(pcase (car event)
|
||||
;; These channel events are from `jupyter-channel-ioloop'
|
||||
('start-channel
|
||||
(setf (jupyter-proxy-channel-alive-p
|
||||
(plist-get (oref comm channels) (cadr event)))
|
||||
t))
|
||||
('stop-channel
|
||||
(setf (jupyter-proxy-channel-alive-p
|
||||
(plist-get (oref comm channels) (cadr event)))
|
||||
nil))
|
||||
(_ (jupyter-event-handler comm event))))))
|
||||
(cl-loop
|
||||
for channel in '(:hb :shell :iopub :stdin)
|
||||
do (jupyter-start-channel comm channel))))
|
||||
(jupyter-start (oref comm conn)))
|
||||
|
||||
(cl-defmethod jupyter-comm-stop ((comm jupyter-channel-ioloop-comm))
|
||||
(cl-loop
|
||||
for channel in '(:hb :shell :iopub :stdin)
|
||||
do (jupyter-stop-channel comm channel))
|
||||
(cl-call-next-method))
|
||||
(jupyter-stop (oref comm conn)))
|
||||
|
||||
(cl-defmethod jupyter-send ((comm jupyter-channel-ioloop-comm) &rest event)
|
||||
(apply #'jupyter--send (oref comm conn) event))
|
||||
|
||||
;;;; Channel querying methods
|
||||
|
||||
(cl-defmethod jupyter-comm-alive-p ((comm jupyter-channel-ioloop-comm))
|
||||
(cl-loop
|
||||
for channel in '(:shell :iopub :stdin :hb)
|
||||
thereis (jupyter-channel-alive-p comm channel)))
|
||||
(jupyter-alive-p (oref comm conn)))
|
||||
|
||||
(cl-defmethod jupyter-channel-alive-p ((comm jupyter-channel-ioloop-comm) channel)
|
||||
(if (eq channel :hb)
|
||||
(and (slot-boundp comm 'hb)
|
||||
(jupyter-channel-alive-p (oref comm hb)))
|
||||
(with-slots (ioloop) comm
|
||||
(and ioloop (jupyter-ioloop-alive-p ioloop)
|
||||
(jupyter-proxy-channel-alive-p
|
||||
(plist-get (oref comm channels) channel))))))
|
||||
(jupyter-alive-p (oref comm conn) channel))
|
||||
|
||||
;;;; Channel start/stop methods
|
||||
|
||||
(cl-defmethod jupyter-stop-channel ((comm jupyter-channel-ioloop-comm) channel)
|
||||
(when (jupyter-channel-alive-p comm channel)
|
||||
(if (eq channel :hb) (jupyter-stop-channel (oref comm hb))
|
||||
(with-slots (ioloop) comm
|
||||
(jupyter-send ioloop 'stop-channel channel)
|
||||
;; Verify that the channel stops
|
||||
(jupyter-with-timeout
|
||||
(nil jupyter-default-timeout
|
||||
(error "Channel not stopped in ioloop subprocess (%s)" channel))
|
||||
(not (jupyter-channel-alive-p comm channel)))))))
|
||||
(jupyter-stop (oref comm conn) channel))
|
||||
|
||||
(cl-defmethod jupyter-start-channel ((comm jupyter-channel-ioloop-comm) channel)
|
||||
(unless (jupyter-channel-alive-p comm channel)
|
||||
(if (eq channel :hb) (jupyter-start-channel (oref comm hb))
|
||||
(let ((endpoint (jupyter-proxy-channel-endpoint
|
||||
(plist-get (oref comm channels) channel))))
|
||||
(with-slots (ioloop) comm
|
||||
(jupyter-send ioloop 'start-channel channel endpoint)
|
||||
;; Verify that the channel starts
|
||||
(jupyter-with-timeout
|
||||
(nil jupyter-default-timeout
|
||||
(error "Channel not started in ioloop subprocess (%s)" channel))
|
||||
(jupyter-channel-alive-p comm channel)))))))
|
||||
(jupyter-start (oref comm conn) channel))
|
||||
|
||||
(provide 'jupyter-channel-ioloop-comm)
|
||||
|
||||
|
|
|
@ -132,11 +132,6 @@ called if needed. This means that a call to
|
|||
(cl-defgeneric jupyter-comm-initialize ((comm jupyter-comm-layer) &rest _ignore)
|
||||
"Initialize communication on COMM.")
|
||||
|
||||
(cl-defmethod jupyter-comm-initialize ((comm jupyter-comm-layer) &rest _ignore)
|
||||
"Raise an error if COMM is already alive."
|
||||
(when (jupyter-comm-alive-p comm)
|
||||
(error "Can't initialize a live comm")))
|
||||
|
||||
;; TODO: Figure out a better interface for these channel methods or just make
|
||||
;; them unnecessary. The design of `jupyter-comm-layer' only deals with
|
||||
;; "events" and the channel abstraction is an implementation detail that
|
||||
|
|
|
@ -225,15 +225,13 @@ connect to MANAGER's kernel."
|
|||
(with-slots (kernel) manager
|
||||
(prog1 client
|
||||
(require 'jupyter-channel-ioloop-comm)
|
||||
(require 'jupyter-zmq-channel-ioloop)
|
||||
;; TODO: We can also have the manager hold the kcomm object and just
|
||||
;; pass a single kcomm object to all clients using this manager since the
|
||||
;; kcomm broadcasts event to all connected clients. This is more
|
||||
;; efficient as it only uses one subprocess for every client connected to
|
||||
;; a kernel.
|
||||
(oset client kcomm (make-instance
|
||||
'jupyter-channel-ioloop-comm
|
||||
:ioloop-class 'jupyter-zmq-channel-ioloop))
|
||||
'jupyter-channel-ioloop-comm))
|
||||
(jupyter-comm-initialize client (oref kernel session))))))
|
||||
|
||||
(cl-defmethod jupyter-start-kernel :after ((manager jupyter-kernel-process-manager) &rest _args)
|
||||
|
|
|
@ -2165,10 +2165,8 @@ interactively, DISPLAY the new REPL buffer as well."
|
|||
(let ((client (make-instance client-class)))
|
||||
;; FIXME: See note in `jupyter-make-client'
|
||||
(require 'jupyter-channel-ioloop-comm)
|
||||
(require 'jupyter-zmq-channel-ioloop)
|
||||
(oset client kcomm (make-instance
|
||||
'jupyter-channel-ioloop-comm
|
||||
:ioloop-class 'jupyter-zmq-channel-ioloop))
|
||||
'jupyter-channel-ioloop-comm))
|
||||
(jupyter-comm-initialize client file-or-plist)
|
||||
(jupyter-start-channels client)
|
||||
(jupyter-hb-unpause client)
|
||||
|
|
|
@ -89,14 +89,16 @@ handling a message is always
|
|||
(cl-defmethod initialize-instance ((client jupyter-echo-client) &optional _slots)
|
||||
(cl-call-next-method)
|
||||
(oset client messages (make-ring 10))
|
||||
(oset client kcomm (jupyter-channel-ioloop-comm
|
||||
:ioloop-class 'jupyter-zmq-channel-ioloop))
|
||||
(oset client kcomm (jupyter-channel-ioloop-comm))
|
||||
(with-slots (kcomm) client
|
||||
(oset kcomm hb (jupyter-hb-channel))
|
||||
(oset kcomm channels
|
||||
(list :stdin (make-jupyter-proxy-channel)
|
||||
:shell (make-jupyter-proxy-channel)
|
||||
:iopub (make-jupyter-proxy-channel)))))
|
||||
(oset kcomm conn
|
||||
(make-jupyter-connection
|
||||
:hb (jupyter-hb-channel)
|
||||
:start #'ignore
|
||||
:stop #'ignore
|
||||
:send #'ignore
|
||||
:alive-p #'ignore))
|
||||
(oset kcomm hb (jupyter-connection-hb (oref kcomm conn)))))
|
||||
|
||||
(cl-defmethod jupyter-send ((client jupyter-echo-client)
|
||||
channel
|
||||
|
|
Loading…
Add table
Reference in a new issue