session.js
328 lines
| 10.3 KiB
| application/javascript
|
JavascriptLexer
Jonathan Frederic
|
r17198 | // Copyright (c) IPython Development Team. | ||
// Distributed under the terms of the Modified BSD License. | ||||
Zachary Sailer
|
r12987 | |||
Jonathan Frederic
|
r17198 | define([ | ||
'base/js/namespace', | ||||
Jonathan Frederic
|
r17200 | 'jquery', | ||
Jonathan Frederic
|
r17198 | 'base/js/utils', | ||
MinRK
|
r18422 | 'services/kernels/kernel', | ||
Jonathan Frederic
|
r17202 | ], function(IPython, $, utils, kernel) { | ||
MinRK
|
r13103 | "use strict"; | ||
Jonathan Frederic
|
r17198 | |||
Jessica B. Hamrick
|
r18216 | /** | ||
* Session object for accessing the session REST api. The session | ||||
* should be used to start kernels and then shut them down -- for | ||||
* all other operations, the kernel object should be used. | ||||
* | ||||
* Options should include: | ||||
* - notebook_name: the notebook name | ||||
* - notebook_path: the path (not including name) to the notebook | ||||
* - kernel_name: the type of kernel (e.g. python3) | ||||
* - base_url: the root url of the notebook server | ||||
* - ws_url: the url to access websockets | ||||
* - notebook: Notebook object | ||||
* | ||||
* @class Session | ||||
* @param {Object} options | ||||
*/ | ||||
Jessica B. Hamrick
|
r18198 | var Session = function (options) { | ||
Zachary Sailer
|
r13060 | this.id = null; | ||
Jessica B. Hamrick
|
r18200 | this.notebook_model = { | ||
Jessica B. Hamrick
|
r18198 | name: options.notebook_name, | ||
path: options.notebook_path | ||||
}; | ||||
Jessica B. Hamrick
|
r18200 | this.kernel_model = { | ||
id: null, | ||||
Jessica B. Hamrick
|
r18198 | name: options.kernel_name | ||
}; | ||||
Jonathan Frederic
|
r17212 | this.base_url = options.base_url; | ||
MinRK
|
r17308 | this.ws_url = options.ws_url; | ||
Jessica B. Hamrick
|
r18206 | this.session_service_url = utils.url_join_encode(this.base_url, 'api/sessions'); | ||
this.session_url = null; | ||||
Jessica B. Hamrick
|
r18198 | |||
Jessica B. Hamrick
|
r18200 | this.notebook = options.notebook; | ||
this.kernel = null; | ||||
Jessica B. Hamrick
|
r18216 | this.events = options.notebook.events; | ||
Jessica B. Hamrick
|
r18224 | |||
this.bind_events(); | ||||
}; | ||||
Session.prototype.bind_events = function () { | ||||
var that = this; | ||||
Jessica B. Hamrick
|
r18239 | var record_status = function (evt, info) { | ||
console.log('Session: ' + evt.type + ' (' + info.session.id + ')'); | ||||
Jessica B. Hamrick
|
r18224 | }; | ||
Jessica B. Hamrick
|
r18230 | this.events.on('kernel_created.Session', record_status); | ||
Jessica B. Hamrick
|
r18224 | this.events.on('kernel_dead.Session', record_status); | ||
Jessica B. Hamrick
|
r18238 | this.events.on('kernel_killed.Session', record_status); | ||
Jessica B. Hamrick
|
r18234 | |||
// if the kernel dies, then also remove the session | ||||
this.events.on('kernel_dead.Kernel', function () { | ||||
that.delete(); | ||||
}); | ||||
Zachary Sailer
|
r12987 | }; | ||
Jessica B. Hamrick
|
r18198 | |||
Jessica B. Hamrick
|
r18224 | |||
Jessica B. Hamrick
|
r18216 | // Public REST api functions | ||
Jessica B. Hamrick
|
r18198 | /** | ||
* GET /api/sessions | ||||
Jessica B. Hamrick
|
r18216 | * | ||
* Get a list of the current sessions. | ||||
* | ||||
* @function list | ||||
* @param {function} [success] - function executed on ajax success | ||||
* @param {function} [error] - functon executed on ajax error | ||||
Jessica B. Hamrick
|
r18198 | */ | ||
Session.prototype.list = function (success, error) { | ||||
Jessica B. Hamrick
|
r18206 | $.ajax(this.session_service_url, { | ||
Jessica B. Hamrick
|
r18198 | processData: false, | ||
cache: false, | ||||
type: "GET", | ||||
dataType: "json", | ||||
success: success, | ||||
error: this._on_error(error) | ||||
}); | ||||
}; | ||||
/** | ||||
* POST /api/sessions | ||||
Jessica B. Hamrick
|
r18216 | * | ||
* Start a new session. This function can only executed once. | ||||
* | ||||
* @function start | ||||
* @param {function} [success] - function executed on ajax success | ||||
* @param {function} [error] - functon executed on ajax error | ||||
Jessica B. Hamrick
|
r18198 | */ | ||
MinRK
|
r17649 | Session.prototype.start = function (success, error) { | ||
MinRK
|
r13103 | var that = this; | ||
Jessica B. Hamrick
|
r18198 | var on_success = function (data, status, xhr) { | ||
Jessica B. Hamrick
|
r18221 | if (!that.kernel) { | ||
var kernel_service_url = utils.url_path_join(that.base_url, "api/kernels"); | ||||
that.kernel = new kernel.Kernel(kernel_service_url, that.ws_url, that.notebook, that.kernel_model.name); | ||||
} | ||||
Jessica B. Hamrick
|
r18230 | that.events.trigger('kernel_created.Session', {session: that, kernel: that.kernel}); | ||
that.kernel._kernel_created(data.kernel); | ||||
Jessica B. Hamrick
|
r18198 | if (success) { | ||
success(data, status, xhr); | ||||
MinRK
|
r13103 | } | ||
}; | ||||
Jessica B. Hamrick
|
r18198 | var on_error = function (xhr, status, err) { | ||
Jessica B. Hamrick
|
r18227 | that.events.trigger('kernel_dead.Session', {session: that, xhr: xhr, status: status, error: err}); | ||
Jessica B. Hamrick
|
r18198 | if (error) { | ||
error(xhr, status, err); | ||||
MinRK
|
r17676 | } | ||
Zachary Sailer
|
r13057 | }; | ||
Jessica B. Hamrick
|
r18198 | |||
Jessica B. Hamrick
|
r18206 | $.ajax(this.session_service_url, { | ||
Jessica B. Hamrick
|
r18198 | processData: false, | ||
cache: false, | ||||
type: "POST", | ||||
data: JSON.stringify(this._get_model()), | ||||
dataType: "json", | ||||
success: this._on_success(on_success), | ||||
error: this._on_error(on_error) | ||||
}); | ||||
Zachary Sailer
|
r12987 | }; | ||
Jessica B. Hamrick
|
r18198 | |||
/** | ||||
* GET /api/sessions/[:session_id] | ||||
Jessica B. Hamrick
|
r18216 | * | ||
* Get information about a session. | ||||
* | ||||
* @function get_info | ||||
* @param {function} [success] - function executed on ajax success | ||||
* @param {function} [error] - functon executed on ajax error | ||||
Jessica B. Hamrick
|
r18198 | */ | ||
Session.prototype.get_info = function (success, error) { | ||||
Jessica B. Hamrick
|
r18206 | $.ajax(this.session_url, { | ||
Jessica B. Hamrick
|
r18198 | processData: false, | ||
cache: false, | ||||
type: "GET", | ||||
dataType: "json", | ||||
success: this._on_success(success), | ||||
error: this._on_error(error) | ||||
}); | ||||
MinRK
|
r13103 | }; | ||
Jessica B. Hamrick
|
r18198 | |||
/** | ||||
* PATCH /api/sessions/[:session_id] | ||||
Jessica B. Hamrick
|
r18216 | * | ||
* Rename or move a notebook. If the given name or path are | ||||
* undefined, then they will not be changed. | ||||
* | ||||
* @function rename_notebook | ||||
* @param {string} [name] - new notebook name | ||||
* @param {string} [path] - new path to notebook | ||||
* @param {function} [success] - function executed on ajax success | ||||
* @param {function} [error] - functon executed on ajax error | ||||
Jessica B. Hamrick
|
r18198 | */ | ||
Jessica B. Hamrick
|
r18216 | Session.prototype.rename_notebook = function (name, path, success, error) { | ||
if (name !== undefined) { | ||||
this.notebook_model.name = name; | ||||
Jessica B. Hamrick
|
r18211 | } | ||
Jessica B. Hamrick
|
r18216 | if (path !== undefined) { | ||
this.notebook_model.path = path; | ||||
Jessica B. Hamrick
|
r18211 | } | ||
Jessica B. Hamrick
|
r18206 | $.ajax(this.session_url, { | ||
Jessica B. Hamrick
|
r18198 | processData: false, | ||
cache: false, | ||||
type: "PATCH", | ||||
data: JSON.stringify(this._get_model()), | ||||
Jessica B. Hamrick
|
r18211 | dataType: "json", | ||
Jessica B. Hamrick
|
r18198 | success: this._on_success(success), | ||
error: this._on_error(error) | ||||
}); | ||||
}; | ||||
/** | ||||
* DELETE /api/sessions/[:session_id] | ||||
Jessica B. Hamrick
|
r18216 | * | ||
* Kill the kernel and shutdown the session. | ||||
* | ||||
* @function delete | ||||
* @param {function} [success] - function executed on ajax success | ||||
* @param {function} [error] - functon executed on ajax error | ||||
Jessica B. Hamrick
|
r18198 | */ | ||
Jessica B. Hamrick
|
r18200 | Session.prototype.delete = function (success, error) { | ||
Jessica B. Hamrick
|
r18206 | if (this.kernel) { | ||
Jessica B. Hamrick
|
r18238 | this.events.trigger('kernel_killed.Session', {session: this, kernel: this.kernel}); | ||
Jessica B. Hamrick
|
r18206 | this.kernel._kernel_dead(); | ||
} | ||||
Jessica B. Hamrick
|
r18198 | |||
Jessica B. Hamrick
|
r18206 | $.ajax(this.session_url, { | ||
Jessica B. Hamrick
|
r18198 | processData: false, | ||
cache: false, | ||||
type: "DELETE", | ||||
dataType: "json", | ||||
Jessica B. Hamrick
|
r18206 | success: this._on_success(success), | ||
Jessica B. Hamrick
|
r18198 | error: this._on_error(error) | ||
}); | ||||
Zachary Sailer
|
r12997 | }; | ||
Jessica B. Hamrick
|
r18216 | |||
Jessica B. Hamrick
|
r18228 | /** | ||
* Restart the session by deleting it and the starting it | ||||
* fresh. If options are given, they can include any of the | ||||
* following: | ||||
* | ||||
* - notebook_name - the name of the notebook | ||||
* - notebook_path - the path to the notebook | ||||
* - kernel_name - the name (type) of the kernel | ||||
* | ||||
* @function restart | ||||
* @param {Object} [options] - options for the new kernel | ||||
* @param {function} [success] - function executed on ajax success | ||||
* @param {function} [error] - functon executed on ajax error | ||||
*/ | ||||
Jessica B. Hamrick
|
r18221 | Session.prototype.restart = function (options, success, error) { | ||
var that = this; | ||||
var start = function () { | ||||
if (options && options.notebook_name) { | ||||
that.notebook_model.name = options.notebook_name; | ||||
} | ||||
if (options && options.notebook_path) { | ||||
that.notebook_model.path = options.notebook_path; | ||||
} | ||||
if (options && options.kernel_name) { | ||||
that.kernel_model.name = options.kernel_name; | ||||
} | ||||
that.kernel_model.id = null; | ||||
that.start(success, error); | ||||
}; | ||||
this.delete(start, start); | ||||
}; | ||||
Jessica B. Hamrick
|
r18216 | // Helper functions | ||
/** | ||||
* Get the data model for the session, which includes the notebook | ||||
* (name and path) and kernel (name and id). | ||||
* | ||||
* @function _get_model | ||||
* @returns {Object} - the data model | ||||
*/ | ||||
Jessica B. Hamrick
|
r18198 | Session.prototype._get_model = function () { | ||
return { | ||||
Jessica B. Hamrick
|
r18200 | notebook: this.notebook_model, | ||
kernel: this.kernel_model | ||||
Jessica B. Hamrick
|
r18198 | }; | ||
Zachary Sailer
|
r12987 | }; | ||
MinRK
|
r17676 | |||
Jessica B. Hamrick
|
r18216 | /** | ||
* Update the data model from the given JSON object, which should | ||||
* have attributes of `id`, `notebook`, and/or `kernel`. If | ||||
* provided, the notebook data must include name and path, and the | ||||
* kernel data must include name and id. | ||||
* | ||||
* @function _update_model | ||||
* @param {Object} data - updated data model | ||||
*/ | ||||
Jessica B. Hamrick
|
r18198 | Session.prototype._update_model = function (data) { | ||
Jessica B. Hamrick
|
r18200 | if (data && data.id) { | ||
this.id = data.id; | ||||
Jessica B. Hamrick
|
r18206 | this.session_url = utils.url_join_encode(this.session_service_url, this.id); | ||
Jessica B. Hamrick
|
r18200 | } | ||
if (data && data.notebook) { | ||||
this.notebook_model.name = data.notebook.name; | ||||
this.notebook_model.path = data.notebook.path; | ||||
Jessica B. Hamrick
|
r18198 | } | ||
Jessica B. Hamrick
|
r18200 | if (data && data.kernel) { | ||
this.kernel_model.name = data.kernel.name; | ||||
this.kernel_model.id = data.kernel.id; | ||||
Jessica B. Hamrick
|
r18198 | } | ||
Zachary Sailer
|
r12987 | }; | ||
Jessica B. Hamrick
|
r18198 | |||
Jessica B. Hamrick
|
r18216 | /** | ||
* Handle a successful AJAX request by updating the session data | ||||
* model with the response, and then optionally calling a provided | ||||
* callback. | ||||
* | ||||
* @function _on_success | ||||
* @param {function} success - callback | ||||
*/ | ||||
Jessica B. Hamrick
|
r18198 | Session.prototype._on_success = function (success) { | ||
var that = this; | ||||
return function (data, status, xhr) { | ||||
that._update_model(data); | ||||
if (success) { | ||||
success(data, status, xhr); | ||||
} | ||||
}; | ||||
Zachary Sailer
|
r12995 | }; | ||
Jessica B. Hamrick
|
r18216 | /** | ||
* Handle a failed AJAX request by logging the error message, and | ||||
* then optionally calling a provided callback. | ||||
* | ||||
* @function _on_error | ||||
* @param {function} error - callback | ||||
*/ | ||||
Jessica B. Hamrick
|
r18198 | Session.prototype._on_error = function (error) { | ||
return function (xhr, status, err) { | ||||
utils.log_ajax_error(xhr, status, err); | ||||
if (error) { | ||||
error(xhr, status, err); | ||||
} | ||||
}; | ||||
Zachary Sailer
|
r12995 | }; | ||
Jessica B. Hamrick
|
r18198 | |||
Jessica B. Hamrick
|
r18216 | /** | ||
* Error type indicating that the session is already starting. | ||||
*/ | ||||
MinRK
|
r17649 | var SessionAlreadyStarting = function (message) { | ||
this.name = "SessionAlreadyStarting"; | ||||
this.message = (message || ""); | ||||
}; | ||||
SessionAlreadyStarting.prototype = Error.prototype; | ||||
Jonathan Frederic
|
r17198 | // For backwards compatability. | ||
Zachary Sailer
|
r12987 | IPython.Session = Session; | ||
MinRK
|
r17649 | return { | ||
Session: Session, | ||||
Jessica B. Hamrick
|
r18198 | SessionAlreadyStarting: SessionAlreadyStarting | ||
MinRK
|
r17649 | }; | ||
Jonathan Frederic
|
r17198 | }); | ||