##// END OF EJS Templates
Move channels into their own object
Jessica B. Hamrick -
Show More
@@ -1,746 +1,746
1 1 // Copyright (c) IPython Development Team.
2 2 // Distributed under the terms of the Modified BSD License.
3 3
4 4 define([
5 5 'base/js/namespace',
6 6 'jquery',
7 7 'base/js/utils',
8 8 'services/kernels/js/comm',
9 9 'widgets/js/init',
10 10 ], function(IPython, $, utils, comm, widgetmanager) {
11 11 "use strict";
12 12
13 13 // Initialization and connection.
14 14 /**
15 15 * A Kernel Class to communicate with the Python kernel
16 16 * @Class Kernel
17 17 */
18 18 var Kernel = function (kernel_service_url, ws_url, notebook, id, name) {
19 19 this.events = notebook.events;
20 20
21 21 this.id = id;
22 22 this.name = name;
23 23
24 this.shell_channel = null;
25 this.iopub_channel = null;
26 this.stdin_channel = null;
24 this.channels = {
25 'shell': null,
26 'iopub': null,
27 'stdin': null
28 };
27 29
28 30 this.kernel_service_url = kernel_service_url;
29 31 this.kernel_url = utils.url_join_encode(this.kernel_service_url, this.id);
30 32 this.ws_url = ws_url || IPython.utils.get_body_data("wsUrl");
31 33 if (!this.ws_url) {
32 34 // trailing 's' in https will become wss for secure web sockets
33 35 this.ws_url = location.protocol.replace('http', 'ws') + "//" + location.host;
34 36 }
35 37
36 38 this.username = "username";
37 39 this.session_id = utils.uuid();
38 40 this._msg_callbacks = {};
39 41
40 42 if (typeof(WebSocket) !== 'undefined') {
41 43 this.WebSocket = WebSocket;
42 44 } else if (typeof(MozWebSocket) !== 'undefined') {
43 45 this.WebSocket = MozWebSocket;
44 46 } else {
45 47 alert('Your browser does not have WebSocket support, please try Chrome, Safari or Firefox β‰₯ 6. Firefox 4 and 5 are also supported by you have to enable WebSockets in about:config.');
46 48 }
47 49
48 50 this.bind_events();
49 51 this.init_iopub_handlers();
50 52 this.comm_manager = new comm.CommManager(this);
51 53 this.widget_manager = new widgetmanager.WidgetManager(this.comm_manager, notebook);
52 54
53 55 this.last_msg_id = null;
54 56 this.last_msg_callbacks = {};
55 57 };
56 58
57 59
58 60 Kernel.prototype._get_msg = function (msg_type, content, metadata) {
59 61 var msg = {
60 62 header : {
61 63 msg_id : utils.uuid(),
62 64 username : this.username,
63 65 session : this.session_id,
64 66 msg_type : msg_type,
65 67 version : "5.0"
66 68 },
67 69 metadata : metadata || {},
68 70 content : content,
69 71 parent_header : {}
70 72 };
71 73 return msg;
72 74 };
73 75
74 76 Kernel.prototype.bind_events = function () {
75 77 var that = this;
76 78 this.events.on('send_input_reply.Kernel', function(evt, data) {
77 79 that.send_input_reply(data);
78 80 });
79 81 };
80 82
81 83 // Initialize the iopub handlers
82 84
83 85 Kernel.prototype.init_iopub_handlers = function () {
84 86 var output_msg_types = ['stream', 'display_data', 'execute_result', 'error'];
85 87 this._iopub_handlers = {};
86 88 this.register_iopub_handler('status', $.proxy(this._handle_status_message, this));
87 89 this.register_iopub_handler('clear_output', $.proxy(this._handle_clear_output, this));
88 90
89 91 for (var i=0; i < output_msg_types.length; i++) {
90 92 this.register_iopub_handler(output_msg_types[i], $.proxy(this._handle_output_message, this));
91 93 }
92 94 };
93 95
94 96 /**
95 97 * GET /api/kernels
96 98 */
97 99 Kernel.prototype.list = function (success, error) {
98 100 $.ajax(this.kernel_service_url, {
99 101 processData: false,
100 102 cache: false,
101 103 type: "GET",
102 104 dataType: "json",
103 105 success: success,
104 106 error: this._on_error(error)
105 107 });
106 108 };
107 109
108 110 /**
109 111 * POST /api/kernels
110 112 */
111 113 Kernel.prototype.start = function (success, error) {
112 114 var that = this;
113 115 var on_success = function (data, status, xhr) {
114 116 that._kernel_started(data);
115 117 if (success) {
116 118 success(data, status, xhr);
117 119 }
118 120 };
119 121
120 122 $.ajax(this.kernel_service_url, {
121 123 processData: false,
122 124 cache: false,
123 125 type: "POST",
124 126 dataType: "json",
125 127 success: this._on_success(on_success),
126 128 error: this._on_error(error)
127 129 });
128 130 };
129 131
130 132 /**
131 133 * GET /api/kernels/[:kernel_id]
132 134 */
133 135 Kernel.prototype.get_info = function (success, error) {
134 136 $.ajax(this.kernel_url, {
135 137 processData: false,
136 138 cache: false,
137 139 type: "GET",
138 140 dataType: "json",
139 141 success: this._on_success(success),
140 142 error: this._on_error(error)
141 143 });
142 144 };
143 145
144 146 /**
145 147 * DELETE /api/kernels/[:kernel_id]
146 148 */
147 149 Kernel.prototype.kill = function (success, error) {
148 150 this._kernel_dead();
149 151 $.ajax(this.kernel_url, {
150 152 processData: false,
151 153 cache: false,
152 154 type: "DELETE",
153 155 dataType: "json",
154 156 success: this._on_success(success),
155 157 error: this._on_error(error)
156 158 });
157 159 };
158 160
159 161 /**
160 162 * POST /api/kernels/[:kernel_id]/interrupt
161 163 */
162 164 Kernel.prototype.interrupt = function (success, error) {
163 165 this.events.trigger('status_interrupting.Kernel', {kernel: this});
164 166 var url = utils.url_join_encode(this.kernel_url, 'interrupt');
165 167 $.ajax(url, {
166 168 processData: false,
167 169 cache: false,
168 170 type: "POST",
169 171 dataType: "json",
170 172 success: this._on_success(success),
171 173 error: this._on_error(error)
172 174 });
173 175 };
174 176
175 177 /**
176 178 * POST /api/kernels/[:kernel_id]/restart
177 179 */
178 180 Kernel.prototype.restart = function (success, error) {
179 181 this.events.trigger('status_restarting.Kernel', {kernel: this});
180 182 this.stop_channels();
181 183
182 184 var that = this;
183 185 var on_success = function (data, status, xhr) {
184 186 that._kernel_started(data, status, xhr);
185 187 if (success) {
186 188 success(data, status, xhr);
187 189 }
188 190 };
189 191
190 192 var url = utils.url_join_encode(this.kernel_url, 'restart');
191 193 $.ajax(url, {
192 194 processData: false,
193 195 cache: false,
194 196 type: "POST",
195 197 dataType: "json",
196 198 success: this._on_success(on_success),
197 199 error: this._on_error(error)
198 200 });
199 201 };
200 202
201 203 /**
202 204 * Not actually a HTTP request, but useful function nonetheless
203 205 * for reconnecting to the kernel if the connection is somehow lost
204 206 */
205 207 Kernel.prototype.reconnect = function () {
206 208 this.events.trigger('status_reconnecting.Kernel');
207 209 var that = this;
208 210 setTimeout(function () {
209 211 that.start_channels();
210 212 }, 5000);
211 213 };
212 214
213 215 Kernel.prototype._on_success = function (success) {
214 216 var that = this;
215 217 return function (data, status, xhr) {
216 218 if (data) {
217 219 that.id = data.id;
218 220 that.name = data.name;
219 221 }
220 222 that.kernel_url = utils.url_join_encode(that.kernel_service_url, that.id);
221 223 if (success) {
222 224 success(data, status, xhr);
223 225 }
224 226 };
225 227 };
226 228
227 229 Kernel.prototype._on_error = function (error) {
228 230 return function (xhr, status, err) {
229 231 utils.log_ajax_error(xhr, status, err);
230 232 if (error) {
231 233 error(xhr, status, err);
232 234 }
233 235 };
234 236 };
235 237
236 238 Kernel.prototype._kernel_started = function (json) {
237 239 console.log("Kernel started: ", json.id);
238 240 this.events.trigger('status_started.Kernel', {kernel: this});
239 241 this.start_channels();
240 242 };
241 243
242 244 Kernel.prototype._kernel_connected = function () {
243 245 var that = this;
246 console.log('Connected to kernel: ', this.id);
244 247 this.events.trigger('status_connected.Kernel');
245 248 this.kernel_info(function () {
246 249 that.events.trigger('status_idle.Kernel');
247 250 });
248 251 };
249 252
250 253 Kernel.prototype._kernel_dead = function () {
251 254 this.events.trigger('status_dead.Kernel');
252 255 this.stop_channels();
253 256 };
254 257
255 258
256 259 /**
257 260 * Start the `shell`and `iopub` channels.
258 261 * Will stop and restart them if they already exist.
259 262 *
260 263 * @method start_channels
261 264 */
262 265 Kernel.prototype.start_channels = function () {
263 266 var that = this;
264 267 this.stop_channels();
265 268 var ws_host_url = this.ws_url + this.kernel_url;
266 269 console.log("Starting WebSockets:", ws_host_url);
267 this.shell_channel = new this.WebSocket(
270 this.channels.shell = new this.WebSocket(
268 271 this.ws_url + utils.url_join_encode(this.kernel_url, "shell")
269 272 );
270 this.stdin_channel = new this.WebSocket(
273 this.channels.stdin = new this.WebSocket(
271 274 this.ws_url + utils.url_join_encode(this.kernel_url, "stdin")
272 275 );
273 this.iopub_channel = new this.WebSocket(
276 this.channels.iopub = new this.WebSocket(
274 277 this.ws_url + utils.url_join_encode(this.kernel_url, "iopub")
275 278 );
276 279
277 280 var already_called_onclose = false; // only alert once
278 281 var ws_closed_early = function(evt){
279 282 if (already_called_onclose){
280 283 return;
281 284 }
282 285 already_called_onclose = true;
283 286 if ( ! evt.wasClean ){
284 287 that._ws_closed(ws_host_url, true);
285 288 }
286 289 };
287 290 var ws_closed_late = function(evt){
288 291 if (already_called_onclose){
289 292 return;
290 293 }
291 294 already_called_onclose = true;
292 295 if ( ! evt.wasClean ){
293 296 that._ws_closed(ws_host_url, false);
294 297 }
295 298 };
296 299 var ws_error = function(evt){
297 300 if (already_called_onclose){
298 301 return;
299 302 }
300 303 already_called_onclose = true;
301 304 that._ws_closed(ws_host_url, false);
302 305 };
303 var channels = [this.shell_channel, this.iopub_channel, this.stdin_channel];
304 for (var i=0; i < channels.length; i++) {
305 channels[i].onopen = $.proxy(this._ws_opened, this);
306 channels[i].onclose = ws_closed_early;
307 channels[i].onerror = ws_error;
306
307 for (var c in this.channels) {
308 this.channels[c].onopen = $.proxy(this._ws_opened, this);
309 this.channels[c].onclose = ws_closed_early;
310 this.channels[c].onerror = ws_error;
308 311 }
309 312 // switch from early-close to late-close message after 1s
310 313 setTimeout(function() {
311 for (var i=0; i < channels.length; i++) {
312 if (channels[i] !== null) {
313 channels[i].onclose = ws_closed_late;
314 for (var c in that.channels) {
315 if (that.channels[c] !== null) {
316 that.channels[c].onclose = ws_closed_late;
314 317 }
315 318 }
316 319 }, 1000);
317 this.shell_channel.onmessage = $.proxy(this._handle_shell_reply, this);
318 this.iopub_channel.onmessage = $.proxy(this._handle_iopub_message, this);
319 this.stdin_channel.onmessage = $.proxy(this._handle_input_request, this);
320 this.channels.shell.onmessage = $.proxy(this._handle_shell_reply, this);
321 this.channels.iopub.onmessage = $.proxy(this._handle_iopub_message, this);
322 this.channels.stdin.onmessage = $.proxy(this._handle_input_request, this);
320 323 };
321 324
322 325 /**
323 326 * Handle a websocket entering the open state
324 327 * sends session and cookie authentication info as first message.
325 328 * Once all sockets are open, signal the Kernel.status_started event.
326 329 * @method _ws_opened
327 330 */
328 331 Kernel.prototype._ws_opened = function (evt) {
329 332 // send the session id so the Session object Python-side
330 333 // has the same identity
331 334 evt.target.send(this.session_id + ':' + document.cookie);
332 335
333 336 if (this.is_connected()) {
334 337 // all events ready, trigger started event.
335 console.log('Connected to kernel: ', this.id);
336 this.events.trigger('status_connected.Kernel', {kernel: this});
338 this._kernel_connected();
337 339 }
338 340 };
339 341
340 342 Kernel.prototype._ws_closed = function(ws_url, early) {
341 343 this.stop_channels();
342 344 this.events.trigger('status_disconnected.Kernel');
343 345 if (!early) {
344 346 this.reconnect();
345 347 } else {
346 348 console.log('WebSocket connection failed: ', ws_url);
347 349 this.events.trigger('early_disconnect.Kernel', ws_url);
348 350 }
349 351 };
350 352
351 353 /**
352 354 * Stop the websocket channels.
353 355 * @method stop_channels
354 356 */
355 357 Kernel.prototype.stop_channels = function () {
356 var channels = [this.shell_channel, this.iopub_channel, this.stdin_channel];
357 for (var i=0; i < channels.length; i++) {
358 if ( channels[i] !== null ) {
359 channels[i].onclose = null;
360 channels[i].close();
358 for (var c in this.channels) {
359 if ( this.channels[c] !== null ) {
360 this.channels[c].onclose = null;
361 this.channels[c].close();
362 this.channels[c] = null;
361 363 }
362 364 }
363 this.shell_channel = this.iopub_channel = this.stdin_channel = null;
364 365 };
365 366
366 367 // Main public methods.
367 368
368 369 Kernel.prototype.is_connected = function () {
369 var channels = [this.shell_channel, this.iopub_channel, this.stdin_channel];
370 for (var i=0; i < channels.length; i++) {
370 for (var c in this.channels) {
371 371 // if any channel is not ready, then we're not connected
372 if (channels[i] === null) {
372 if (this.channels[c] === null) {
373 373 return false;
374 374 }
375 if (channels[i].readyState !== WebSocket.OPEN) {
375 if (this.channels[c].readyState !== WebSocket.OPEN) {
376 376 return false;
377 377 }
378 378 }
379 379 return true;
380 380 };
381 381
382 382 // send a message on the Kernel's shell channel
383 383 Kernel.prototype.send_shell_message = function (msg_type, content, callbacks, metadata) {
384 384 if (!this.is_connected()) {
385 385 throw new Error("kernel is not connected");
386 386 }
387 387 var msg = this._get_msg(msg_type, content, metadata);
388 this.shell_channel.send(JSON.stringify(msg));
388 this.channels.shell.send(JSON.stringify(msg));
389 389 this.set_callbacks_for_msg(msg.header.msg_id, callbacks);
390 390 return msg.header.msg_id;
391 391 };
392 392
393 393 /**
394 394 * Get kernel info
395 395 *
396 396 * @param callback {function}
397 397 * @method kernel_info
398 398 *
399 399 * When calling this method, pass a callback function that expects one argument.
400 400 * The callback will be passed the complete `kernel_info_reply` message documented
401 401 * [here](http://ipython.org/ipython-doc/dev/development/messaging.html#kernel-info)
402 402 */
403 403 Kernel.prototype.kernel_info = function (callback) {
404 404 var callbacks;
405 405 if (callback) {
406 406 callbacks = { shell : { reply : callback } };
407 407 }
408 408 return this.send_shell_message("kernel_info_request", {}, callbacks);
409 409 };
410 410
411 411 /**
412 412 * Get info on an object
413 413 *
414 414 * @param code {string}
415 415 * @param cursor_pos {integer}
416 416 * @param callback {function}
417 417 * @method inspect
418 418 *
419 419 * When calling this method, pass a callback function that expects one argument.
420 420 * The callback will be passed the complete `inspect_reply` message documented
421 421 * [here](http://ipython.org/ipython-doc/dev/development/messaging.html#object-information)
422 422 */
423 423 Kernel.prototype.inspect = function (code, cursor_pos, callback) {
424 424 var callbacks;
425 425 if (callback) {
426 426 callbacks = { shell : { reply : callback } };
427 427 }
428 428
429 429 var content = {
430 430 code : code,
431 431 cursor_pos : cursor_pos,
432 432 detail_level : 0
433 433 };
434 434 return this.send_shell_message("inspect_request", content, callbacks);
435 435 };
436 436
437 437 /**
438 438 * Execute given code into kernel, and pass result to callback.
439 439 *
440 440 * @async
441 441 * @method execute
442 442 * @param {string} code
443 443 * @param [callbacks] {Object} With the following keys (all optional)
444 444 * @param callbacks.shell.reply {function}
445 445 * @param callbacks.shell.payload.[payload_name] {function}
446 446 * @param callbacks.iopub.output {function}
447 447 * @param callbacks.iopub.clear_output {function}
448 448 * @param callbacks.input {function}
449 449 * @param {object} [options]
450 450 * @param [options.silent=false] {Boolean}
451 451 * @param [options.user_expressions=empty_dict] {Dict}
452 452 * @param [options.allow_stdin=false] {Boolean} true|false
453 453 *
454 454 * @example
455 455 *
456 456 * The options object should contain the options for the execute call. Its default
457 457 * values are:
458 458 *
459 459 * options = {
460 460 * silent : true,
461 461 * user_expressions : {},
462 462 * allow_stdin : false
463 463 * }
464 464 *
465 465 * When calling this method pass a callbacks structure of the form:
466 466 *
467 467 * callbacks = {
468 468 * shell : {
469 469 * reply : execute_reply_callback,
470 470 * payload : {
471 471 * set_next_input : set_next_input_callback,
472 472 * }
473 473 * },
474 474 * iopub : {
475 475 * output : output_callback,
476 476 * clear_output : clear_output_callback,
477 477 * },
478 478 * input : raw_input_callback
479 479 * }
480 480 *
481 481 * Each callback will be passed the entire message as a single arugment.
482 482 * Payload handlers will be passed the corresponding payload and the execute_reply message.
483 483 */
484 484 Kernel.prototype.execute = function (code, callbacks, options) {
485 485 var content = {
486 486 code : code,
487 487 silent : true,
488 488 store_history : false,
489 489 user_expressions : {},
490 490 allow_stdin : false
491 491 };
492 492 callbacks = callbacks || {};
493 493 if (callbacks.input !== undefined) {
494 494 content.allow_stdin = true;
495 495 }
496 496 $.extend(true, content, options);
497 497 this.events.trigger('execution_request.Kernel', {kernel: this, content:content});
498 498 return this.send_shell_message("execute_request", content, callbacks);
499 499 };
500 500
501 501 /**
502 502 * When calling this method, pass a function to be called with the `complete_reply` message
503 503 * as its only argument when it arrives.
504 504 *
505 505 * `complete_reply` is documented
506 506 * [here](http://ipython.org/ipython-doc/dev/development/messaging.html#complete)
507 507 *
508 508 * @method complete
509 509 * @param code {string}
510 510 * @param cursor_pos {integer}
511 511 * @param callback {function}
512 512 *
513 513 */
514 514 Kernel.prototype.complete = function (code, cursor_pos, callback) {
515 515 var callbacks;
516 516 if (callback) {
517 517 callbacks = { shell : { reply : callback } };
518 518 }
519 519 var content = {
520 520 code : code,
521 521 cursor_pos : cursor_pos
522 522 };
523 523 return this.send_shell_message("complete_request", content, callbacks);
524 524 };
525 525
526 526 Kernel.prototype.send_input_reply = function (input) {
527 527 if (!this.is_connected()) {
528 528 throw new Error("kernel is not connected");
529 529 }
530 530 var content = {
531 531 value : input
532 532 };
533 533 this.events.trigger('input_reply.Kernel', {kernel: this, content:content});
534 534 var msg = this._get_msg("input_reply", content);
535 this.stdin_channel.send(JSON.stringify(msg));
535 this.channels.stdin.send(JSON.stringify(msg));
536 536 return msg.header.msg_id;
537 537 };
538 538
539 539
540 540 // Reply handlers
541 541
542 542 Kernel.prototype.register_iopub_handler = function (msg_type, callback) {
543 543 this._iopub_handlers[msg_type] = callback;
544 544 };
545 545
546 546 Kernel.prototype.get_iopub_handler = function (msg_type) {
547 547 // get iopub handler for a specific message type
548 548 return this._iopub_handlers[msg_type];
549 549 };
550 550
551 551
552 552 Kernel.prototype.get_callbacks_for_msg = function (msg_id) {
553 553 // get callbacks for a specific message
554 554 if (msg_id == this.last_msg_id) {
555 555 return this.last_msg_callbacks;
556 556 } else {
557 557 return this._msg_callbacks[msg_id];
558 558 }
559 559 };
560 560
561 561
562 562 Kernel.prototype.clear_callbacks_for_msg = function (msg_id) {
563 563 if (this._msg_callbacks[msg_id] !== undefined ) {
564 564 delete this._msg_callbacks[msg_id];
565 565 }
566 566 };
567 567
568 568 Kernel.prototype._finish_shell = function (msg_id) {
569 569 var callbacks = this._msg_callbacks[msg_id];
570 570 if (callbacks !== undefined) {
571 571 callbacks.shell_done = true;
572 572 if (callbacks.iopub_done) {
573 573 this.clear_callbacks_for_msg(msg_id);
574 574 }
575 575 }
576 576 };
577 577
578 578 Kernel.prototype._finish_iopub = function (msg_id) {
579 579 var callbacks = this._msg_callbacks[msg_id];
580 580 if (callbacks !== undefined) {
581 581 callbacks.iopub_done = true;
582 582 if (callbacks.shell_done) {
583 583 this.clear_callbacks_for_msg(msg_id);
584 584 }
585 585 }
586 586 };
587 587
588 588 /* Set callbacks for a particular message.
589 589 * Callbacks should be a struct of the following form:
590 590 * shell : {
591 591 *
592 592 * }
593 593
594 594 */
595 595 Kernel.prototype.set_callbacks_for_msg = function (msg_id, callbacks) {
596 596 this.last_msg_id = msg_id;
597 597 if (callbacks) {
598 598 // shallow-copy mapping, because we will modify it at the top level
599 599 var cbcopy = this._msg_callbacks[msg_id] = this.last_msg_callbacks = {};
600 600 cbcopy.shell = callbacks.shell;
601 601 cbcopy.iopub = callbacks.iopub;
602 602 cbcopy.input = callbacks.input;
603 603 cbcopy.shell_done = (!callbacks.shell);
604 604 cbcopy.iopub_done = (!callbacks.iopub);
605 605 } else {
606 606 this.last_msg_callbacks = {};
607 607 }
608 608 };
609 609
610 610
611 611 Kernel.prototype._handle_shell_reply = function (e) {
612 612 var reply = $.parseJSON(e.data);
613 613 this.events.trigger('shell_reply.Kernel', {kernel: this, reply:reply});
614 614 var content = reply.content;
615 615 var metadata = reply.metadata;
616 616 var parent_id = reply.parent_header.msg_id;
617 617 var callbacks = this.get_callbacks_for_msg(parent_id);
618 618 if (!callbacks || !callbacks.shell) {
619 619 return;
620 620 }
621 621 var shell_callbacks = callbacks.shell;
622 622
623 623 // signal that shell callbacks are done
624 624 this._finish_shell(parent_id);
625 625
626 626 if (shell_callbacks.reply !== undefined) {
627 627 shell_callbacks.reply(reply);
628 628 }
629 629 if (content.payload && shell_callbacks.payload) {
630 630 this._handle_payloads(content.payload, shell_callbacks.payload, reply);
631 631 }
632 632 };
633 633
634 634
635 635 Kernel.prototype._handle_payloads = function (payloads, payload_callbacks, msg) {
636 636 var l = payloads.length;
637 637 // Payloads are handled by triggering events because we don't want the Kernel
638 638 // to depend on the Notebook or Pager classes.
639 639 for (var i=0; i<l; i++) {
640 640 var payload = payloads[i];
641 641 var callback = payload_callbacks[payload.source];
642 642 if (callback) {
643 643 callback(payload, msg);
644 644 }
645 645 }
646 646 };
647 647
648 648 Kernel.prototype._handle_status_message = function (msg) {
649 649 var execution_state = msg.content.execution_state;
650 650 var parent_id = msg.parent_header.msg_id;
651 651
652 652 // dispatch status msg callbacks, if any
653 653 var callbacks = this.get_callbacks_for_msg(parent_id);
654 654 if (callbacks && callbacks.iopub && callbacks.iopub.status) {
655 655 try {
656 656 callbacks.iopub.status(msg);
657 657 } catch (e) {
658 658 console.log("Exception in status msg handler", e, e.stack);
659 659 }
660 660 }
661 661
662 662 if (execution_state === 'busy') {
663 663 this.events.trigger('status_busy.Kernel', {kernel: this});
664 664 } else if (execution_state === 'idle') {
665 665 // signal that iopub callbacks are (probably) done
666 666 // async output may still arrive,
667 667 // but only for the most recent request
668 668 this._finish_iopub(parent_id);
669 669
670 670 // trigger status_idle event
671 671 this.events.trigger('status_idle.Kernel', {kernel: this});
672 672 } else if (execution_state === 'restarting') {
673 673 // autorestarting is distinct from restarting,
674 674 // in that it means the kernel died and the server is restarting it.
675 675 // status_restarting sets the notification widget,
676 676 // autorestart shows the more prominent dialog.
677 677 this.events.trigger('status_autorestarting.Kernel', {kernel: this});
678 678 this.events.trigger('status_restarting.Kernel', {kernel: this});
679 679 } else if (execution_state === 'dead') {
680 680 this.stop_channels();
681 681 this.events.trigger('status_dead.Kernel', {kernel: this});
682 682 this.events.trigger('status_restart_failed.Kernel', {kernel: this});
683 683 }
684 684 };
685 685
686 686
687 687 // handle clear_output message
688 688 Kernel.prototype._handle_clear_output = function (msg) {
689 689 var callbacks = this.get_callbacks_for_msg(msg.parent_header.msg_id);
690 690 if (!callbacks || !callbacks.iopub) {
691 691 return;
692 692 }
693 693 var callback = callbacks.iopub.clear_output;
694 694 if (callback) {
695 695 callback(msg);
696 696 }
697 697 };
698 698
699 699
700 700 // handle an output message (execute_result, display_data, etc.)
701 701 Kernel.prototype._handle_output_message = function (msg) {
702 702 var callbacks = this.get_callbacks_for_msg(msg.parent_header.msg_id);
703 703 if (!callbacks || !callbacks.iopub) {
704 704 return;
705 705 }
706 706 var callback = callbacks.iopub.output;
707 707 if (callback) {
708 708 callback(msg);
709 709 }
710 710 };
711 711
712 712 // dispatch IOPub messages to respective handlers.
713 713 // each message type should have a handler.
714 714 Kernel.prototype._handle_iopub_message = function (e) {
715 715 var msg = $.parseJSON(e.data);
716 716
717 717 var handler = this.get_iopub_handler(msg.header.msg_type);
718 718 if (handler !== undefined) {
719 719 handler(msg);
720 720 }
721 721 };
722 722
723 723
724 724 Kernel.prototype._handle_input_request = function (e) {
725 725 var request = $.parseJSON(e.data);
726 726 var header = request.header;
727 727 var content = request.content;
728 728 var metadata = request.metadata;
729 729 var msg_type = header.msg_type;
730 730 if (msg_type !== 'input_request') {
731 731 console.log("Invalid input request!", request);
732 732 return;
733 733 }
734 734 var callbacks = this.get_callbacks_for_msg(request.parent_header.msg_id);
735 735 if (callbacks) {
736 736 if (callbacks.input) {
737 737 callbacks.input(request);
738 738 }
739 739 }
740 740 };
741 741
742 742 // Backwards compatability.
743 743 IPython.Kernel = Kernel;
744 744
745 745 return {'Kernel': Kernel};
746 746 });
General Comments 0
You need to be logged in to leave comments. Login now