@@ -384,7 +384,7 @@ def application(self):
384384 def request (self ):
385385 return self .session .handler .request
386386
387- def _reserialize_reply (self , msg_list ):
387+ def _reserialize_reply (self , msg_list , channel = None ):
388388 """Reserialize a reply message using JSON.
389389
390390 This takes the msg list from the ZMQ socket, unserializes it using
@@ -394,20 +394,13 @@ def _reserialize_reply(self, msg_list):
394394 """
395395 idents , msg_list = self .ip_session .feed_identities (msg_list )
396396 msg = self .ip_session .unserialize (msg_list )
397- try :
398- msg ['header' ].pop ('date' )
399- except KeyError :
400- pass
401- try :
402- msg ['parent_header' ].pop ('date' )
403- except KeyError :
404- pass
405- msg .pop ('buffers' )
397+ msg .pop ('buffers' , None )
398+ msg ['channel' ] = channel
406399 return jsonapi .dumps (msg , default = date_default )
407400
408- def _on_zmq_reply (self , msg_list ):
401+ def _on_zmq_reply (self , msg_list , channel = None ):
409402 try :
410- msg = self ._reserialize_reply (msg_list )
403+ msg = self ._reserialize_reply (msg_list , channel )
411404 except Exception :
412405 self .application .log .critical ("Malformed message: %r" % msg_list , exc_info = True )
413406 else :
@@ -440,6 +433,12 @@ def on_open(self, info):
440433 self .ip_session = Session (config = cfg )
441434 self .save_on_message = self .on_message
442435 self .on_message = self .on_first_message
436+
437+ self .initialize ()
438+
439+ def initialize (self ):
440+ """override in subclasses"""
441+ pass
443442
444443 def get_current_user (self ):
445444 handler = self .session .handler
@@ -465,6 +464,11 @@ def on_first_message(self, cookie):
465464 logging .warn ("Couldn't authenticate WebSocket connection" )
466465 raise web .HTTPError (403 )
467466 self .on_message = self .save_on_message
467+ self .create_streams ()
468+
469+ def create_streams (self ):
470+ """override in subclass"""
471+ pass
468472
469473
470474class IOPubHandler (AuthenticatedZMQStreamHandler ):
@@ -473,28 +477,23 @@ class IOPubHandler(AuthenticatedZMQStreamHandler):
473477 _beating = False
474478 iopub_stream = None
475479 hb_stream = None
476-
477- def on_first_message (self , msg ):
478- try :
479- super (IOPubHandler , self ).on_first_message (msg )
480- except web .HTTPError :
481- self .close ()
482- return
480+
481+ def initialize (self ):
483482 km = self .application .kernel_manager
484483 self .time_to_dead = km .time_to_dead
485484 self .first_beat = km .first_beat
485+
486+ def create_streams (self ):
487+ km = self .application .kernel_manager
486488 kernel_id = self .kernel_id
487489 try :
488490 self .iopub_stream = km .create_iopub_stream (kernel_id )
489491 self .hb_stream = km .create_hb_stream (kernel_id )
490- except web .HTTPError :
491- # WebSockets don't response to traditional error codes so we
492- # close the connection.
493- if not self .stream .closed ():
494- self .stream .close ()
492+ except Exception :
493+ logging .error ("Couldn't create streams" , exc_info = True )
495494 self .close ()
496495 else :
497- self .iopub_stream .on_recv (self ._on_zmq_reply )
496+ self .iopub_stream .on_recv (lambda msg : self ._on_zmq_reply ( msg , 'iopub' ) )
498497 self .start_hb (self .kernel_died )
499498
500499 def on_message (self , msg ):
@@ -562,36 +561,32 @@ def kernel_died(self):
562561 self .send (json .dumps (
563562 {'header' : {'msg_type' : 'status' },
564563 'parent_header' : {},
565- 'content' : {'execution_state' :'dead' }
564+ 'content' : {'execution_state' :'dead' },
565+ 'channel' : 'iopub' ,
566566 }
567567 ))
568568 self .on_close ()
569569
570570
571571class ShellHandler (AuthenticatedZMQStreamHandler ):
572572
573- def initialize (self , * args , ** kwargs ):
574- self .shell_stream = None
575-
576- def on_first_message (self , msg ):
577- try :
578- super (ShellHandler , self ).on_first_message (msg )
579- except web .HTTPError :
580- self .close ()
581- return
573+ shell_stream = None
574+ max_msg_size = 65535
575+
576+ def initialize (self ):
582577 km = self .application .kernel_manager
583578 self .max_msg_size = km .max_msg_size
579+
580+ def create_streams (self ):
581+ km = self .application .kernel_manager
584582 kernel_id = self .kernel_id
585583 try :
586584 self .shell_stream = km .create_shell_stream (kernel_id )
587- except web .HTTPError :
588- # WebSockets don't response to traditional error codes so we
589- # close the connection.
590- if not self .stream .closed ():
591- self .stream .close ()
585+ except Exception :
586+ logging .error ("Couldn't create shell stream" , exc_info = True )
592587 self .close ()
593588 else :
594- self .shell_stream .on_recv (self ._on_zmq_reply )
589+ self .shell_stream .on_recv (lambda msg : self ._on_zmq_reply ( msg , 'shell' ) )
595590
596591 def on_message (self , msg ):
597592 if len (msg ) < self .max_msg_size :
@@ -603,6 +598,20 @@ def on_close(self):
603598 if self .shell_stream is not None and not self .shell_stream .closed ():
604599 self .shell_stream .close ()
605600
601+ class IOPubAndShellHandler (ShellHandler , IOPubHandler ):
602+ """single SockJS handler for IOPub + Shell zmq channels"""
603+ def on_close (self ):
604+ ShellHandler .on_close (self )
605+ IOPubHandler .on_close (self )
606+
607+ def initialize (self ):
608+ ShellHandler .initialize (self )
609+ IOPubHandler .initialize (self )
610+
611+ def create_streams (self ):
612+ ShellHandler .create_streams (self )
613+ IOPubHandler .create_streams (self )
614+
606615
607616#-----------------------------------------------------------------------------
608617# Notebook web service handlers
0 commit comments