// Copyright (c) IPython Development Team.1// Distributed under the terms of the Modified BSD License.23define([4'base/js/namespace',5'jquery',6'base/js/utils',7'services/kernels/kernel',8], function(IPython, $, utils, kernel) {9"use strict";1011/**12* Session object for accessing the session REST api. The session13* should be used to start kernels and then shut them down -- for14* all other operations, the kernel object should be used.15*16* Options should include:17* - notebook_path: the path (not including name) to the notebook18* - kernel_name: the type of kernel (e.g. python3)19* - base_url: the root url of the notebook server20* - ws_url: the url to access websockets21* - notebook: Notebook object22*23* @class Session24* @param {Object} options25*/26var Session = function (options) {27this.id = null;28this.notebook_model = {29path: options.notebook_path30};31this.kernel_model = {32id: null,33name: options.kernel_name34};3536this.base_url = options.base_url;37this.ws_url = options.ws_url;38this.session_service_url = utils.url_join_encode(this.base_url, 'api/sessions');39this.session_url = null;4041this.notebook = options.notebook;42this.kernel = null;43this.events = options.notebook.events;4445this.bind_events();46};4748Session.prototype.bind_events = function () {49var that = this;50var record_status = function (evt, info) {51console.log('Session: ' + evt.type + ' (' + info.session.id + ')');52};5354this.events.on('kernel_created.Session', record_status);55this.events.on('kernel_dead.Session', record_status);56this.events.on('kernel_killed.Session', record_status);5758// if the kernel dies, then also remove the session59this.events.on('kernel_dead.Kernel', function () {60that.delete();61});62};636465// Public REST api functions6667/**68* GET /api/sessions69*70* Get a list of the current sessions.71*72* @function list73* @param {function} [success] - function executed on ajax success74* @param {function} [error] - functon executed on ajax error75*/76Session.prototype.list = function (success, error) {77$.ajax(this.session_service_url, {78processData: false,79cache: false,80type: "GET",81dataType: "json",82success: success,83error: this._on_error(error)84});85};8687/**88* POST /api/sessions89*90* Start a new session. This function can only executed once.91*92* @function start93* @param {function} [success] - function executed on ajax success94* @param {function} [error] - functon executed on ajax error95*/96Session.prototype.start = function (success, error) {97var that = this;98var on_success = function (data, status, xhr) {99if (that.kernel) {100that.kernel.name = that.kernel_model.name;101} else {102var kernel_service_url = utils.url_path_join(that.base_url, "api/kernels");103that.kernel = new kernel.Kernel(kernel_service_url, that.ws_url, that.notebook, that.kernel_model.name);104}105that.events.trigger('kernel_created.Session', {session: that, kernel: that.kernel});106that.kernel._kernel_created(data.kernel);107if (success) {108success(data, status, xhr);109}110};111var on_error = function (xhr, status, err) {112that.events.trigger('kernel_dead.Session', {session: that, xhr: xhr, status: status, error: err});113if (error) {114error(xhr, status, err);115}116};117118$.ajax(this.session_service_url, {119processData: false,120cache: false,121type: "POST",122data: JSON.stringify(this._get_model()),123dataType: "json",124success: this._on_success(on_success),125error: this._on_error(on_error)126});127};128129/**130* GET /api/sessions/[:session_id]131*132* Get information about a session.133*134* @function get_info135* @param {function} [success] - function executed on ajax success136* @param {function} [error] - functon executed on ajax error137*/138Session.prototype.get_info = function (success, error) {139$.ajax(this.session_url, {140processData: false,141cache: false,142type: "GET",143dataType: "json",144success: this._on_success(success),145error: this._on_error(error)146});147};148149/**150* PATCH /api/sessions/[:session_id]151*152* Rename or move a notebook. If the given name or path are153* undefined, then they will not be changed.154*155* @function rename_notebook156* @param {string} [path] - new notebook path157* @param {function} [success] - function executed on ajax success158* @param {function} [error] - functon executed on ajax error159*/160Session.prototype.rename_notebook = function (path, success, error) {161if (path !== undefined) {162this.notebook_model.path = path;163}164165$.ajax(this.session_url, {166processData: false,167cache: false,168type: "PATCH",169data: JSON.stringify(this._get_model()),170dataType: "json",171success: this._on_success(success),172error: this._on_error(error)173});174};175176/**177* DELETE /api/sessions/[:session_id]178*179* Kill the kernel and shutdown the session.180*181* @function delete182* @param {function} [success] - function executed on ajax success183* @param {function} [error] - functon executed on ajax error184*/185Session.prototype.delete = function (success, error) {186if (this.kernel) {187this.events.trigger('kernel_killed.Session', {session: this, kernel: this.kernel});188this.kernel._kernel_dead();189}190191$.ajax(this.session_url, {192processData: false,193cache: false,194type: "DELETE",195dataType: "json",196success: this._on_success(success),197error: this._on_error(error)198});199};200201/**202* Restart the session by deleting it and the starting it203* fresh. If options are given, they can include any of the204* following:205*206* - notebook_path - the path to the notebook207* - kernel_name - the name (type) of the kernel208*209* @function restart210* @param {Object} [options] - options for the new kernel211* @param {function} [success] - function executed on ajax success212* @param {function} [error] - functon executed on ajax error213*/214Session.prototype.restart = function (options, success, error) {215var that = this;216var start = function () {217if (options && options.notebook_path) {218that.notebook_model.path = options.notebook_path;219}220if (options && options.kernel_name) {221that.kernel_model.name = options.kernel_name;222}223that.kernel_model.id = null;224that.start(success, error);225};226this.delete(start, start);227};228229// Helper functions230231/**232* Get the data model for the session, which includes the notebook path233* and kernel (name and id).234*235* @function _get_model236* @returns {Object} - the data model237*/238Session.prototype._get_model = function () {239return {240notebook: this.notebook_model,241kernel: this.kernel_model242};243};244245/**246* Update the data model from the given JSON object, which should247* have attributes of `id`, `notebook`, and/or `kernel`. If248* provided, the notebook data must include name and path, and the249* kernel data must include name and id.250*251* @function _update_model252* @param {Object} data - updated data model253*/254Session.prototype._update_model = function (data) {255if (data && data.id) {256this.id = data.id;257this.session_url = utils.url_join_encode(this.session_service_url, this.id);258}259if (data && data.notebook) {260this.notebook_model.path = data.notebook.path;261}262if (data && data.kernel) {263this.kernel_model.name = data.kernel.name;264this.kernel_model.id = data.kernel.id;265}266};267268/**269* Handle a successful AJAX request by updating the session data270* model with the response, and then optionally calling a provided271* callback.272*273* @function _on_success274* @param {function} success - callback275*/276Session.prototype._on_success = function (success) {277var that = this;278return function (data, status, xhr) {279that._update_model(data);280if (success) {281success(data, status, xhr);282}283};284};285286/**287* Handle a failed AJAX request by logging the error message, and288* then optionally calling a provided callback.289*290* @function _on_error291* @param {function} error - callback292*/293Session.prototype._on_error = function (error) {294return function (xhr, status, err) {295utils.log_ajax_error(xhr, status, err);296if (error) {297error(xhr, status, err);298}299};300};301302/**303* Error type indicating that the session is already starting.304*/305var SessionAlreadyStarting = function (message) {306this.name = "SessionAlreadyStarting";307this.message = (message || "");308};309SessionAlreadyStarting.prototype = Error.prototype;310311// For backwards compatability.312IPython.Session = Session;313314return {315Session: Session,316SessionAlreadyStarting: SessionAlreadyStarting317};318});319320321