##// END OF EJS Templates
WebSocket url is now passed to browser when a kernel is started.
Brian E. Granger -
Show More
@@ -61,8 +61,10 b' class MainKernelHandler(web.RequestHandler):'
61 61 km = self.application.kernel_manager
62 62 notebook_id = self.get_argument('notebook', default=None)
63 63 kernel_id = km.start_kernel(notebook_id)
64 ws_url = self.application.ipython_app.get_ws_url()
65 data = {'ws_url':ws_url,'kernel_id':kernel_id}
64 66 self.set_header('Location', '/'+kernel_id)
65 self.finish(jsonapi.dumps(kernel_id))
67 self.finish(jsonapi.dumps(data))
66 68
67 69
68 70 class KernelHandler(web.RequestHandler):
@@ -85,7 +87,10 b' class KernelActionHandler(web.RequestHandler):'
85 87 self.set_status(204)
86 88 if action == 'restart':
87 89 new_kernel_id = km.restart_kernel(kernel_id)
88 self.write(jsonapi.dumps(new_kernel_id))
90 ws_url = self.application.ipython_app.get_ws_url()
91 data = {'ws_url':ws_url,'kernel_id':new_kernel_id}
92 self.set_header('Location', '/'+new_kernel_id)
93 self.write(jsonapi.dumps(data))
89 94 self.finish()
90 95
91 96
@@ -126,21 +131,36 b' class IOPubHandler(ZMQStreamHandler):'
126 131 def initialize(self, *args, **kwargs):
127 132 self._kernel_alive = True
128 133 self._beating = False
134 self.iopub_stream = None
135 self.hb_stream = None
129 136
130 137 def open(self, kernel_id):
131 138 km = self.application.kernel_manager
132 139 self.kernel_id = kernel_id
133 140 self.session = Session()
134 141 self.time_to_dead = km.time_to_dead
135 self.iopub_stream = km.create_iopub_stream(kernel_id)
136 self.hb_stream = km.create_hb_stream(kernel_id)
137 self.iopub_stream.on_recv(self._on_zmq_reply)
138 self.start_hb(self.kernel_died)
142 try:
143 self.iopub_stream = km.create_iopub_stream(kernel_id)
144 self.hb_stream = km.create_hb_stream(kernel_id)
145 except web.HTTPError:
146 # WebSockets don't response to traditional error codes so we
147 # close the connection.
148 if not self.stream.closed():
149 self.stream.close()
150 else:
151 self.iopub_stream.on_recv(self._on_zmq_reply)
152 self.start_hb(self.kernel_died)
139 153
140 154 def on_close(self):
155 # This method can be called twice, once by self.kernel_died and once
156 # from the WebSocket close event. If the WebSocket connection is
157 # closed before the ZMQ streams are setup, they could be None.
141 158 self.stop_hb()
142 self.iopub_stream.close()
143 self.hb_stream.close()
159 if self.iopub_stream is not None and not self.iopub_stream.closed():
160 self.iopub_stream.on_recv(None)
161 self.iopub_stream.close()
162 if self.hb_stream is not None and not self.hb_stream.closed():
163 self.hb_stream.close()
144 164
145 165 def start_hb(self, callback):
146 166 """Start the heartbeating and call the callback if the kernel dies."""
@@ -188,15 +208,22 b' class IOPubHandler(ZMQStreamHandler):'
188 208 class ShellHandler(ZMQStreamHandler):
189 209
190 210 def initialize(self, *args, **kwargs):
191 pass
211 self.shell_stream = None
192 212
193 213 def open(self, kernel_id):
194 214 km = self.application.kernel_manager
195 215 self.max_msg_size = km.max_msg_size
196 216 self.kernel_id = kernel_id
197 self.session = Session()
198 self.shell_stream = self.application.kernel_manager.create_shell_stream(kernel_id)
199 self.shell_stream.on_recv(self._on_zmq_reply)
217 try:
218 self.shell_stream = km.create_shell_stream(kernel_id)
219 except web.HTTPError:
220 # WebSockets don't response to traditional error codes so we
221 # close the connection.
222 if not self.stream.closed():
223 self.stream.close()
224 else:
225 self.session = Session()
226 self.shell_stream.on_recv(self._on_zmq_reply)
200 227
201 228 def on_message(self, msg):
202 229 if len(msg) < self.max_msg_size:
@@ -204,7 +231,9 b' class ShellHandler(ZMQStreamHandler):'
204 231 self.session.send(self.shell_stream, msg)
205 232
206 233 def on_close(self):
207 self.shell_stream.close()
234 # Make sure the stream exists and is not already closed.
235 if self.shell_stream is not None and not self.shell_stream.closed():
236 self.shell_stream.close()
208 237
209 238
210 239 #-----------------------------------------------------------------------------
@@ -300,7 +300,21 b' class MappingKernelManager(KernelManager):'
300 300 # Now save the new kernel/notebook association. We have to save it
301 301 # after the old kernel is killed as that will delete the mapping.
302 302 self.set_kernel_for_notebook(notebook_id, new_kernel_id)
303 self.log.debug("Kernel restarted: %s" % new_kernel_id)
303 self.log.info("Kernel restarted: %s" % new_kernel_id)
304 304 return new_kernel_id
305 305
306 def create_iopub_stream(self, kernel_id):
307 if kernel_id not in self:
308 raise web.HTTPError(404)
309 return super(MappingKernelManager, self).create_iopub_stream(kernel_id)
310
311 def create_shell_stream(self, kernel_id):
312 if kernel_id not in self:
313 raise web.HTTPError(404)
314 return super(MappingKernelManager, self).create_shell_stream(kernel_id)
315
316 def create_hb_stream(self, kernel_id):
317 if kernel_id not in self:
318 raise web.HTTPError(404)
319 return super(MappingKernelManager, self).create_hb_stream(kernel_id)
306 320
@@ -72,7 +72,7 b' ipython notebook --port=5555 --ip=* # Listen on port 5555, all interfaces'
72 72
73 73 class NotebookWebApplication(web.Application):
74 74
75 def __init__(self, kernel_manager, notebook_manager, log):
75 def __init__(self, ipython_app, kernel_manager, notebook_manager, log):
76 76 handlers = [
77 77 (r"/", NBBrowserHandler),
78 78 (r"/new", NewHandler),
@@ -95,6 +95,7 b' class NotebookWebApplication(web.Application):'
95 95 self.kernel_manager = kernel_manager
96 96 self.log = log
97 97 self.notebook_manager = notebook_manager
98 self.ipython_app = ipython_app
98 99
99 100
100 101 #-----------------------------------------------------------------------------
@@ -115,6 +116,7 b' aliases.update({'
115 116 'port': 'IPythonNotebookApp.port',
116 117 'keyfile': 'IPythonNotebookApp.keyfile',
117 118 'certfile': 'IPythonNotebookApp.certfile',
119 'ws-hostname': 'IPythonNotebookApp.ws_hostname',
118 120 'notebook-dir': 'NotebookManager.notebook_dir'
119 121 })
120 122
@@ -160,6 +162,13 b' class IPythonNotebookApp(BaseIPythonApplication):'
160 162 help="The port the notebook server will listen on."
161 163 )
162 164
165 ws_hostname = Unicode(LOCALHOST, config=True,
166 help="""The FQDN or IP for WebSocket connections. The default will work
167 fine when the server is listening on localhost, but this needs to
168 be set if the ip option is used. It will be used as the hostname part
169 of the WebSocket url: ws://hostname/path."""
170 )
171
163 172 certfile = Unicode(u'', config=True,
164 173 help="""The full path to an SSL/TLS certificate file."""
165 174 )
@@ -168,6 +177,14 b' class IPythonNotebookApp(BaseIPythonApplication):'
168 177 help="""The full path to a private key file for usage with SSL/TLS."""
169 178 )
170 179
180 def get_ws_url(self):
181 """Return the WebSocket URL for this server."""
182 if self.certfile:
183 prefix = u'wss://'
184 else:
185 prefix = u'ws://'
186 return prefix + self.ws_hostname + u':' + unicode(self.port)
187
171 188 def parse_command_line(self, argv=None):
172 189 super(IPythonNotebookApp, self).parse_command_line(argv)
173 190 if argv is None:
@@ -202,7 +219,7 b' class IPythonNotebookApp(BaseIPythonApplication):'
202 219 super(IPythonNotebookApp, self).initialize(argv)
203 220 self.init_configurables()
204 221 self.web_app = NotebookWebApplication(
205 self.kernel_manager, self.notebook_manager, self.log
222 self, self.kernel_manager, self.notebook_manager, self.log
206 223 )
207 224 if self.certfile:
208 225 ssl_options = dict(certfile=self.certfile)
@@ -61,9 +61,10 b' var IPython = (function (IPython) {'
61 61 };
62 62
63 63
64 Kernel.prototype._handle_start_kernel = function (kernel_id, callback) {
64 Kernel.prototype._handle_start_kernel = function (json, callback) {
65 65 this.running = true;
66 this.kernel_id = kernel_id;
66 this.kernel_id = json.kernel_id;
67 this.ws_url = json.ws_url;
67 68 this.kernel_url = this.base_url + "/" + this.kernel_id;
68 69 this.start_channels();
69 70 callback();
@@ -73,7 +74,8 b' var IPython = (function (IPython) {'
73 74
74 75 Kernel.prototype.start_channels = function () {
75 76 this.stop_channels();
76 var ws_url = "ws://127.0.0.1:8888" + this.kernel_url;
77 var ws_url = this.ws_url + this.kernel_url;
78 console.log("Starting WS:", ws_url);
77 79 this.shell_channel = new WebSocket(ws_url + "/shell");
78 80 this.iopub_channel = new WebSocket(ws_url + "/iopub");
79 81 };
General Comments 0
You need to be logged in to leave comments. Login now