##// END OF EJS Templates
Merge pull request #955 from minrk/websocket...
Fernando Perez -
r5301:f6b3d8ff merge
parent child Browse files
Show More
@@ -139,7 +139,16 b' class AuthenticatedHandler(web.RequestHandler):'
139 return True
139 return True
140 else:
140 else:
141 return False
141 return False
142
143 @property
144 def ws_url(self):
145 """websocket url matching the current request
142
146
147 turns http[s]://host[:port] into
148 ws[s]://host[:port]
149 """
150 proto = self.request.protocol.replace('http', 'ws')
151 return "%s://%s" % (proto, self.request.host)
143
152
144
153
145 class ProjectDashboardHandler(AuthenticatedHandler):
154 class ProjectDashboardHandler(AuthenticatedHandler):
@@ -221,8 +230,7 b' class MainKernelHandler(AuthenticatedHandler):'
221 km = self.application.kernel_manager
230 km = self.application.kernel_manager
222 notebook_id = self.get_argument('notebook', default=None)
231 notebook_id = self.get_argument('notebook', default=None)
223 kernel_id = km.start_kernel(notebook_id)
232 kernel_id = km.start_kernel(notebook_id)
224 ws_url = self.application.ipython_app.get_ws_url()
233 data = {'ws_url':self.ws_url,'kernel_id':kernel_id}
225 data = {'ws_url':ws_url,'kernel_id':kernel_id}
226 self.set_header('Location', '/'+kernel_id)
234 self.set_header('Location', '/'+kernel_id)
227 self.finish(jsonapi.dumps(data))
235 self.finish(jsonapi.dumps(data))
228
236
@@ -249,8 +257,7 b' class KernelActionHandler(AuthenticatedHandler):'
249 self.set_status(204)
257 self.set_status(204)
250 if action == 'restart':
258 if action == 'restart':
251 new_kernel_id = km.restart_kernel(kernel_id)
259 new_kernel_id = km.restart_kernel(kernel_id)
252 ws_url = self.application.ipython_app.get_ws_url()
260 data = {'ws_url':self.ws_url,'kernel_id':new_kernel_id}
253 data = {'ws_url':ws_url,'kernel_id':new_kernel_id}
254 self.set_header('Location', '/'+new_kernel_id)
261 self.set_header('Location', '/'+new_kernel_id)
255 self.write(jsonapi.dumps(data))
262 self.write(jsonapi.dumps(data))
256 self.finish()
263 self.finish()
@@ -147,7 +147,6 b' aliases.update({'
147 'port': 'NotebookApp.port',
147 'port': 'NotebookApp.port',
148 'keyfile': 'NotebookApp.keyfile',
148 'keyfile': 'NotebookApp.keyfile',
149 'certfile': 'NotebookApp.certfile',
149 'certfile': 'NotebookApp.certfile',
150 'ws-hostname': 'NotebookApp.ws_hostname',
151 'notebook-dir': 'NotebookManager.notebook_dir',
150 'notebook-dir': 'NotebookManager.notebook_dir',
152 })
151 })
153
152
@@ -155,7 +154,7 b' aliases.update({'
155 # multi-kernel evironment:
154 # multi-kernel evironment:
156 aliases.pop('f', None)
155 aliases.pop('f', None)
157
156
158 notebook_aliases = [u'port', u'ip', u'keyfile', u'certfile', u'ws-hostname',
157 notebook_aliases = [u'port', u'ip', u'keyfile', u'certfile',
159 u'notebook-dir']
158 u'notebook-dir']
160
159
161 #-----------------------------------------------------------------------------
160 #-----------------------------------------------------------------------------
@@ -200,13 +199,6 b' class NotebookApp(BaseIPythonApplication):'
200 help="The port the notebook server will listen on."
199 help="The port the notebook server will listen on."
201 )
200 )
202
201
203 ws_hostname = Unicode(LOCALHOST, config=True,
204 help="""The FQDN or IP for WebSocket connections. The default will work
205 fine when the server is listening on localhost, but this needs to
206 be set if the ip option is used. It will be used as the hostname part
207 of the WebSocket url: ws://hostname/path."""
208 )
209
210 certfile = Unicode(u'', config=True,
202 certfile = Unicode(u'', config=True,
211 help="""The full path to an SSL/TLS certificate file."""
203 help="""The full path to an SSL/TLS certificate file."""
212 )
204 )
@@ -226,14 +218,6 b' class NotebookApp(BaseIPythonApplication):'
226 help="Whether to prevent editing/execution of notebooks."
218 help="Whether to prevent editing/execution of notebooks."
227 )
219 )
228
220
229 def get_ws_url(self):
230 """Return the WebSocket URL for this server."""
231 if self.certfile:
232 prefix = u'wss://'
233 else:
234 prefix = u'ws://'
235 return prefix + self.ws_hostname + u':' + unicode(self.port)
236
237 def parse_command_line(self, argv=None):
221 def parse_command_line(self, argv=None):
238 super(NotebookApp, self).parse_command_line(argv)
222 super(NotebookApp, self).parse_command_line(argv)
239 if argv is None:
223 if argv is None:
@@ -27,7 +27,7 b' var IPython = (function (IPython) {'
27 } else if (typeof(MozWebSocket) !== 'undefined') {
27 } else if (typeof(MozWebSocket) !== 'undefined') {
28 this.WebSocket = MozWebSocket
28 this.WebSocket = MozWebSocket
29 } else {
29 } else {
30 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.');
30 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.');
31 };
31 };
32 };
32 };
33
33
@@ -87,8 +87,37 b' var IPython = (function (IPython) {'
87 IPython.kernel_status_widget.status_idle();
87 IPython.kernel_status_widget.status_idle();
88 };
88 };
89
89
90 Kernel.prototype._websocket_closed = function(ws_url, early){
91 var msg;
92 var parent_item = $('body');
93 if (early) {
94 msg = "Websocket connection to " + ws_url + " could not be established.<br/>" +
95 " You will NOT be able to run code.<br/>" +
96 " Your browser may not be compatible with the websocket version in the server," +
97 " or if the url does not look right, there could be an error in the" +
98 " server's configuration."
99 } else {
100 msg = "Websocket connection closed unexpectedly.<br/>" +
101 " The kernel will no longer be responsive."
102 }
103 var dialog = $('<div/>');
104 dialog.html(msg);
105 parent_item.append(dialog);
106 dialog.dialog({
107 resizable: false,
108 modal: true,
109 title: "Websocket closed",
110 buttons : {
111 "Okay": function () {
112 $(this).dialog('close');
113 }
114 }
115 });
116
117 }
90
118
91 Kernel.prototype.start_channels = function () {
119 Kernel.prototype.start_channels = function () {
120 var that = this;
92 this.stop_channels();
121 this.stop_channels();
93 var ws_url = this.ws_url + this.kernel_url;
122 var ws_url = this.ws_url + this.kernel_url;
94 console.log("Starting WS:", ws_url);
123 console.log("Starting WS:", ws_url);
@@ -97,17 +126,45 b' var IPython = (function (IPython) {'
97 send_cookie = function(){
126 send_cookie = function(){
98 this.send(document.cookie);
127 this.send(document.cookie);
99 }
128 }
129 var already_called_onclose = false; // only alert once
130 ws_closed_early = function(evt){
131 if (already_called_onclose){
132 return;
133 }
134 already_called_onclose = true;
135 if ( ! evt.wasClean ){
136 that._websocket_closed(ws_url, true);
137 }
138 }
139 ws_closed_late = function(evt){
140 if (already_called_onclose){
141 return;
142 }
143 already_called_onclose = true;
144 if ( ! evt.wasClean ){
145 that._websocket_closed(ws_url, false);
146 }
147 }
100 this.shell_channel.onopen = send_cookie;
148 this.shell_channel.onopen = send_cookie;
149 this.shell_channel.onclose = ws_closed_early;
101 this.iopub_channel.onopen = send_cookie;
150 this.iopub_channel.onopen = send_cookie;
151 this.iopub_channel.onclose = ws_closed_early;
152 // switch from early-close to late-close message after 1s
153 setTimeout(function(){
154 that.shell_channel.onclose = ws_closed_late;
155 that.iopub_channel.onclose = ws_closed_late;
156 }, 1000);
102 };
157 };
103
158
104
159
105 Kernel.prototype.stop_channels = function () {
160 Kernel.prototype.stop_channels = function () {
106 if (this.shell_channel !== null) {
161 if (this.shell_channel !== null) {
162 this.shell_channel.onclose = function (evt) {null};
107 this.shell_channel.close();
163 this.shell_channel.close();
108 this.shell_channel = null;
164 this.shell_channel = null;
109 };
165 };
110 if (this.iopub_channel !== null) {
166 if (this.iopub_channel !== null) {
167 this.iopub_channel.onclose = function (evt) {null};
111 this.iopub_channel.close();
168 this.iopub_channel.close();
112 this.iopub_channel = null;
169 this.iopub_channel = null;
113 };
170 };
General Comments 0
You need to be logged in to leave comments. Login now