Skip to content

Commit 5725215

Browse files
committed
Implement a jupyter-comm-layer using a websocket
The `jupyter-server-kernel-comm` class is re-purposed for this, as mentioned in the previous commit. * jupyter-server.el (jupyter-server--ws-on-message): New function. (jupyter-comm-start, jupyter-comm-stop, jupyter-comm-alive-p, jupyter-send) [jupyter-server-kernel-comm]: New methods.
1 parent 3b3e358 commit 5725215

File tree

1 file changed

+57
-0
lines changed

1 file changed

+57
-0
lines changed

jupyter-server.el

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,8 @@ The kernelspecs are returned in the same form as returned by
332332
(cons nil (plist-get spec :spec)))))))
333333
(plist-get (oref server kernelspecs) :kernelspecs))
334334

335+
;;;; `jupyter-server-kernel-comm'
336+
335337
;; TODO: Remove the need for these methods, they are remnants from an older
336338
;; implementation. They will need to be removed from `jupyter-kernel-client'.
337339
(cl-defmethod jupyter-channel-alive-p ((comm jupyter-server-abstract-kcomm) _channel)
@@ -340,6 +342,61 @@ The kernelspecs are returned in the same form as returned by
340342
(cl-defmethod jupyter-channels-running-p ((comm jupyter-server-abstract-kcomm))
341343
(jupyter-comm-alive-p comm))
342344

345+
(defun jupyter-server--ws-on-message (ws frame)
346+
(cl-case (websocket-frame-opcode frame)
347+
((text binary)
348+
(let* ((msg (jupyter-read-plist-from-string
349+
(websocket-frame-payload frame)))
350+
;; TODO: Get rid of some of these explicit/implicit `intern' calls
351+
(channel (intern (concat ":" (plist-get msg :channel))))
352+
(msg-type (jupyter-message-type-as-keyword
353+
(jupyter-message-type msg)))
354+
(parent-header (plist-get msg :parent_header)))
355+
(plist-put msg :msg_type msg-type)
356+
(plist-put parent-header :msg_type msg-type)
357+
(jupyter-event-handler
358+
(plist-get (websocket-client-data ws) :comm)
359+
;; NOTE: The nil is the identity field expected by a
360+
;; `jupyter-channel-ioloop', it is mimicked here.
361+
(cl-list* 'message channel nil msg))))
362+
(t
363+
(error "Unhandled websocket frame opcode (%s)"
364+
(websocket-frame-opcode frame)))))
365+
366+
(cl-defmethod jupyter-comm-start ((comm jupyter-server-kernel-comm))
367+
(unless (jupyter-comm-alive-p comm)
368+
(with-slots (server id) (oref comm kernel)
369+
(let ((ws (jupyter-api-get-kernel-ws
370+
server id
371+
:on-message #'jupyter-server--ws-on-message)))
372+
(oset comm ws ws)
373+
(plist-put (websocket-client-data ws) :comm comm)))))
374+
375+
(cl-defmethod jupyter-comm-stop ((comm jupyter-server-kernel-comm))
376+
(when (jupyter-comm-alive-p comm)
377+
(websocket-close (oref comm ws))
378+
(plist-put (websocket-client-data (oref comm ws)) :comm nil)
379+
(slot-makeunbound comm 'ws)))
380+
381+
(cl-defmethod jupyter-comm-alive-p ((comm jupyter-server-kernel-comm))
382+
(and (slot-boundp comm 'ws)
383+
(eq (plist-get (websocket-client-data (oref comm ws)) :comm) comm)))
384+
385+
(cl-defmethod jupyter-send ((comm jupyter-server-kernel-comm) _event-type &rest event)
386+
"Use COMM to send an EVENT to the server with type, EVENT-TYPE.
387+
SERVER will direct EVENT to the right kernel based on the kernel
388+
ID of the kernel associated with COMM."
389+
(unless (jupyter-comm-alive-p comm)
390+
(jupyter-comm-start comm))
391+
(cl-destructuring-bind (channel msg-type msg &optional msg-id) event
392+
(with-slots (ws) comm
393+
(websocket-send-text
394+
ws (jupyter-encode-raw-message
395+
(plist-get (websocket-client-data ws) :session) msg-type
396+
:channel (substring (symbol-name channel) 1)
397+
:msg-id msg-id
398+
:content msg)))))
399+
343400
;;;; `jupyter-server-kernel-manager'
344401

345402
(defclass jupyter-server-kernel-manager (jupyter-kernel-manager)

0 commit comments

Comments
 (0)