@@ -384,7 +384,7 @@ def application(self):
384
384
def request (self ):
385
385
return self .session .handler .request
386
386
387
- def _reserialize_reply (self , msg_list ):
387
+ def _reserialize_reply (self , msg_list , channel = None ):
388
388
"""Reserialize a reply message using JSON.
389
389
390
390
This takes the msg list from the ZMQ socket, unserializes it using
@@ -394,20 +394,13 @@ def _reserialize_reply(self, msg_list):
394
394
"""
395
395
idents , msg_list = self .ip_session .feed_identities (msg_list )
396
396
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
406
399
return jsonapi .dumps (msg , default = date_default )
407
400
408
- def _on_zmq_reply (self , msg_list ):
401
+ def _on_zmq_reply (self , msg_list , channel = None ):
409
402
try :
410
- msg = self ._reserialize_reply (msg_list )
403
+ msg = self ._reserialize_reply (msg_list , channel )
411
404
except Exception :
412
405
self .application .log .critical ("Malformed message: %r" % msg_list , exc_info = True )
413
406
else :
@@ -440,6 +433,12 @@ def on_open(self, info):
440
433
self .ip_session = Session (config = cfg )
441
434
self .save_on_message = self .on_message
442
435
self .on_message = self .on_first_message
436
+
437
+ self .initialize ()
438
+
439
+ def initialize (self ):
440
+ """override in subclasses"""
441
+ pass
443
442
444
443
def get_current_user (self ):
445
444
handler = self .session .handler
@@ -465,6 +464,11 @@ def on_first_message(self, cookie):
465
464
logging .warn ("Couldn't authenticate WebSocket connection" )
466
465
raise web .HTTPError (403 )
467
466
self .on_message = self .save_on_message
467
+ self .create_streams ()
468
+
469
+ def create_streams (self ):
470
+ """override in subclass"""
471
+ pass
468
472
469
473
470
474
class IOPubHandler (AuthenticatedZMQStreamHandler ):
@@ -473,28 +477,23 @@ class IOPubHandler(AuthenticatedZMQStreamHandler):
473
477
_beating = False
474
478
iopub_stream = None
475
479
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 ):
483
482
km = self .application .kernel_manager
484
483
self .time_to_dead = km .time_to_dead
485
484
self .first_beat = km .first_beat
485
+
486
+ def create_streams (self ):
487
+ km = self .application .kernel_manager
486
488
kernel_id = self .kernel_id
487
489
try :
488
490
self .iopub_stream = km .create_iopub_stream (kernel_id )
489
491
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 )
495
494
self .close ()
496
495
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' ) )
498
497
self .start_hb (self .kernel_died )
499
498
500
499
def on_message (self , msg ):
@@ -562,36 +561,32 @@ def kernel_died(self):
562
561
self .send (json .dumps (
563
562
{'header' : {'msg_type' : 'status' },
564
563
'parent_header' : {},
565
- 'content' : {'execution_state' :'dead' }
564
+ 'content' : {'execution_state' :'dead' },
565
+ 'channel' : 'iopub' ,
566
566
}
567
567
))
568
568
self .on_close ()
569
569
570
570
571
571
class ShellHandler (AuthenticatedZMQStreamHandler ):
572
572
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 ):
582
577
km = self .application .kernel_manager
583
578
self .max_msg_size = km .max_msg_size
579
+
580
+ def create_streams (self ):
581
+ km = self .application .kernel_manager
584
582
kernel_id = self .kernel_id
585
583
try :
586
584
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 )
592
587
self .close ()
593
588
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' ) )
595
590
596
591
def on_message (self , msg ):
597
592
if len (msg ) < self .max_msg_size :
@@ -603,6 +598,20 @@ def on_close(self):
603
598
if self .shell_stream is not None and not self .shell_stream .closed ():
604
599
self .shell_stream .close ()
605
600
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
+
606
615
607
616
#-----------------------------------------------------------------------------
608
617
# Notebook web service handlers
0 commit comments