##// END OF EJS Templates
Fix a bug in using promises with comms: this -> that
Jason Grout -
Show More
@@ -1,217 +1,217 b''
1 // Copyright (c) IPython Development Team.
1 // Copyright (c) IPython Development Team.
2 // Distributed under the terms of the Modified BSD License.
2 // Distributed under the terms of the Modified BSD License.
3
3
4 define([
4 define([
5 'base/js/namespace',
5 'base/js/namespace',
6 'jquery',
6 'jquery',
7 'base/js/utils',
7 'base/js/utils',
8 ], function(IPython, $, utils) {
8 ], function(IPython, $, utils) {
9 "use strict";
9 "use strict";
10
10
11 //-----------------------------------------------------------------------
11 //-----------------------------------------------------------------------
12 // CommManager class
12 // CommManager class
13 //-----------------------------------------------------------------------
13 //-----------------------------------------------------------------------
14
14
15 var CommManager = function (kernel) {
15 var CommManager = function (kernel) {
16 this.comms = {};
16 this.comms = {};
17 this.targets = {};
17 this.targets = {};
18 if (kernel !== undefined) {
18 if (kernel !== undefined) {
19 this.init_kernel(kernel);
19 this.init_kernel(kernel);
20 }
20 }
21 };
21 };
22
22
23 CommManager.prototype.init_kernel = function (kernel) {
23 CommManager.prototype.init_kernel = function (kernel) {
24 /**
24 /**
25 * connect the kernel, and register message handlers
25 * connect the kernel, and register message handlers
26 */
26 */
27 this.kernel = kernel;
27 this.kernel = kernel;
28 var msg_types = ['comm_open', 'comm_msg', 'comm_close'];
28 var msg_types = ['comm_open', 'comm_msg', 'comm_close'];
29 for (var i = 0; i < msg_types.length; i++) {
29 for (var i = 0; i < msg_types.length; i++) {
30 var msg_type = msg_types[i];
30 var msg_type = msg_types[i];
31 kernel.register_iopub_handler(msg_type, $.proxy(this[msg_type], this));
31 kernel.register_iopub_handler(msg_type, $.proxy(this[msg_type], this));
32 }
32 }
33 };
33 };
34
34
35 CommManager.prototype.new_comm = function (target_name, data, callbacks, metadata) {
35 CommManager.prototype.new_comm = function (target_name, data, callbacks, metadata) {
36 /**
36 /**
37 * Create a new Comm, register it, and open its Kernel-side counterpart
37 * Create a new Comm, register it, and open its Kernel-side counterpart
38 * Mimics the auto-registration in `Comm.__init__` in the IPython Comm
38 * Mimics the auto-registration in `Comm.__init__` in the IPython Comm
39 */
39 */
40 var comm = new Comm(target_name);
40 var comm = new Comm(target_name);
41 this.register_comm(comm);
41 this.register_comm(comm);
42 comm.open(data, callbacks, metadata);
42 comm.open(data, callbacks, metadata);
43 return comm;
43 return comm;
44 };
44 };
45
45
46 CommManager.prototype.register_target = function (target_name, f) {
46 CommManager.prototype.register_target = function (target_name, f) {
47 /**
47 /**
48 * Register a target function for a given target name
48 * Register a target function for a given target name
49 */
49 */
50 this.targets[target_name] = f;
50 this.targets[target_name] = f;
51 };
51 };
52
52
53 CommManager.prototype.unregister_target = function (target_name, f) {
53 CommManager.prototype.unregister_target = function (target_name, f) {
54 /**
54 /**
55 * Unregister a target function for a given target name
55 * Unregister a target function for a given target name
56 */
56 */
57 delete this.targets[target_name];
57 delete this.targets[target_name];
58 };
58 };
59
59
60 CommManager.prototype.register_comm = function (comm) {
60 CommManager.prototype.register_comm = function (comm) {
61 /**
61 /**
62 * Register a comm in the mapping
62 * Register a comm in the mapping
63 */
63 */
64 this.comms[comm.comm_id] = Promise.resolve(comm);
64 this.comms[comm.comm_id] = Promise.resolve(comm);
65 comm.kernel = this.kernel;
65 comm.kernel = this.kernel;
66 return comm.comm_id;
66 return comm.comm_id;
67 };
67 };
68
68
69 CommManager.prototype.unregister_comm = function (comm) {
69 CommManager.prototype.unregister_comm = function (comm) {
70 /**
70 /**
71 * Remove a comm from the mapping
71 * Remove a comm from the mapping
72 */
72 */
73 delete this.comms[comm.comm_id];
73 delete this.comms[comm.comm_id];
74 };
74 };
75
75
76 // comm message handlers
76 // comm message handlers
77
77
78 CommManager.prototype.comm_open = function (msg) {
78 CommManager.prototype.comm_open = function (msg) {
79 var content = msg.content;
79 var content = msg.content;
80 var that = this;
80 var that = this;
81 var comm_id = content.comm_id;
81 var comm_id = content.comm_id;
82
82
83 this.comms[comm_id] = utils.load_class(content.target_name, content.target_module,
83 this.comms[comm_id] = utils.load_class(content.target_name, content.target_module,
84 this.targets).then(function(target) {
84 this.targets).then(function(target) {
85 var comm = new Comm(content.target_name, comm_id);
85 var comm = new Comm(content.target_name, comm_id);
86 comm.kernel = that.kernel;
86 comm.kernel = that.kernel;
87 try {
87 try {
88 var response = target(comm, msg);
88 var response = target(comm, msg);
89 } catch (e) {
89 } catch (e) {
90 comm.close();
90 comm.close();
91 that.unregister_comm(comm);
91 that.unregister_comm(comm);
92 var wrapped_error = new utils.WrappedError("Exception opening new comm", e);
92 var wrapped_error = new utils.WrappedError("Exception opening new comm", e);
93 console.error(wrapped_error);
93 console.error(wrapped_error);
94 return Promise.reject(wrapped_error);
94 return Promise.reject(wrapped_error);
95 }
95 }
96 // Regardless of the target return value, we need to
96 // Regardless of the target return value, we need to
97 // then return the comm
97 // then return the comm
98 return Promise.resolve(response).then(function() {return comm;});
98 return Promise.resolve(response).then(function() {return comm;});
99 }, utils.reject('Could not open comm', true));
99 }, utils.reject('Could not open comm', true));
100 return this.comms[comm_id];
100 return this.comms[comm_id];
101 };
101 };
102
102
103 CommManager.prototype.comm_close = function(msg) {
103 CommManager.prototype.comm_close = function(msg) {
104 var content = msg.content;
104 var content = msg.content;
105 if (this.comms[content.comm_id] === undefined) {
105 if (this.comms[content.comm_id] === undefined) {
106 console.error('Comm promise not found for comm id ' + content.comm_id);
106 console.error('Comm promise not found for comm id ' + content.comm_id);
107 return;
107 return;
108 }
108 }
109
109 var that = this;
110 this.comms[content.comm_id] = this.comms[content.comm_id].then(function(comm) {
110 this.comms[content.comm_id] = this.comms[content.comm_id].then(function(comm) {
111 this.unregister_comm(comm);
111 that.unregister_comm(comm);
112 try {
112 try {
113 comm.handle_close(msg);
113 comm.handle_close(msg);
114 } catch (e) {
114 } catch (e) {
115 console.log("Exception closing comm: ", e, e.stack, msg);
115 console.log("Exception closing comm: ", e, e.stack, msg);
116 }
116 }
117 // don't return a comm, so that further .then() functions
117 // don't return a comm, so that further .then() functions
118 // get an undefined comm input
118 // get an undefined comm input
119 });
119 });
120 };
120 };
121
121
122 CommManager.prototype.comm_msg = function(msg) {
122 CommManager.prototype.comm_msg = function(msg) {
123 var content = msg.content;
123 var content = msg.content;
124 if (this.comms[content.comm_id] === undefined) {
124 if (this.comms[content.comm_id] === undefined) {
125 console.error('Comm promise not found for comm id ' + content.comm_id);
125 console.error('Comm promise not found for comm id ' + content.comm_id);
126 return;
126 return;
127 }
127 }
128
128
129 this.comms[content.comm_id] = this.comms[content.comm_id].then(function(comm) {
129 this.comms[content.comm_id] = this.comms[content.comm_id].then(function(comm) {
130 try {
130 try {
131 comm.handle_msg(msg);
131 comm.handle_msg(msg);
132 } catch (e) {
132 } catch (e) {
133 console.log("Exception handling comm msg: ", e, e.stack, msg);
133 console.log("Exception handling comm msg: ", e, e.stack, msg);
134 }
134 }
135 return comm;
135 return comm;
136 });
136 });
137 };
137 };
138
138
139 //-----------------------------------------------------------------------
139 //-----------------------------------------------------------------------
140 // Comm base class
140 // Comm base class
141 //-----------------------------------------------------------------------
141 //-----------------------------------------------------------------------
142
142
143 var Comm = function (target_name, comm_id) {
143 var Comm = function (target_name, comm_id) {
144 this.target_name = target_name;
144 this.target_name = target_name;
145 this.comm_id = comm_id || utils.uuid();
145 this.comm_id = comm_id || utils.uuid();
146 this._msg_callback = this._close_callback = null;
146 this._msg_callback = this._close_callback = null;
147 };
147 };
148
148
149 // methods for sending messages
149 // methods for sending messages
150 Comm.prototype.open = function (data, callbacks, metadata) {
150 Comm.prototype.open = function (data, callbacks, metadata) {
151 var content = {
151 var content = {
152 comm_id : this.comm_id,
152 comm_id : this.comm_id,
153 target_name : this.target_name,
153 target_name : this.target_name,
154 data : data || {},
154 data : data || {},
155 };
155 };
156 return this.kernel.send_shell_message("comm_open", content, callbacks, metadata);
156 return this.kernel.send_shell_message("comm_open", content, callbacks, metadata);
157 };
157 };
158
158
159 Comm.prototype.send = function (data, callbacks, metadata, buffers) {
159 Comm.prototype.send = function (data, callbacks, metadata, buffers) {
160 var content = {
160 var content = {
161 comm_id : this.comm_id,
161 comm_id : this.comm_id,
162 data : data || {},
162 data : data || {},
163 };
163 };
164 return this.kernel.send_shell_message("comm_msg", content, callbacks, metadata, buffers);
164 return this.kernel.send_shell_message("comm_msg", content, callbacks, metadata, buffers);
165 };
165 };
166
166
167 Comm.prototype.close = function (data, callbacks, metadata) {
167 Comm.prototype.close = function (data, callbacks, metadata) {
168 var content = {
168 var content = {
169 comm_id : this.comm_id,
169 comm_id : this.comm_id,
170 data : data || {},
170 data : data || {},
171 };
171 };
172 return this.kernel.send_shell_message("comm_close", content, callbacks, metadata);
172 return this.kernel.send_shell_message("comm_close", content, callbacks, metadata);
173 };
173 };
174
174
175 // methods for registering callbacks for incoming messages
175 // methods for registering callbacks for incoming messages
176 Comm.prototype._register_callback = function (key, callback) {
176 Comm.prototype._register_callback = function (key, callback) {
177 this['_' + key + '_callback'] = callback;
177 this['_' + key + '_callback'] = callback;
178 };
178 };
179
179
180 Comm.prototype.on_msg = function (callback) {
180 Comm.prototype.on_msg = function (callback) {
181 this._register_callback('msg', callback);
181 this._register_callback('msg', callback);
182 };
182 };
183
183
184 Comm.prototype.on_close = function (callback) {
184 Comm.prototype.on_close = function (callback) {
185 this._register_callback('close', callback);
185 this._register_callback('close', callback);
186 };
186 };
187
187
188 // methods for handling incoming messages
188 // methods for handling incoming messages
189
189
190 Comm.prototype._callback = function (key, msg) {
190 Comm.prototype._callback = function (key, msg) {
191 var callback = this['_' + key + '_callback'];
191 var callback = this['_' + key + '_callback'];
192 if (callback) {
192 if (callback) {
193 try {
193 try {
194 callback(msg);
194 callback(msg);
195 } catch (e) {
195 } catch (e) {
196 console.log("Exception in Comm callback", e, e.stack, msg);
196 console.log("Exception in Comm callback", e, e.stack, msg);
197 }
197 }
198 }
198 }
199 };
199 };
200
200
201 Comm.prototype.handle_msg = function (msg) {
201 Comm.prototype.handle_msg = function (msg) {
202 this._callback('msg', msg);
202 this._callback('msg', msg);
203 };
203 };
204
204
205 Comm.prototype.handle_close = function (msg) {
205 Comm.prototype.handle_close = function (msg) {
206 this._callback('close', msg);
206 this._callback('close', msg);
207 };
207 };
208
208
209 // For backwards compatability.
209 // For backwards compatability.
210 IPython.CommManager = CommManager;
210 IPython.CommManager = CommManager;
211 IPython.Comm = Comm;
211 IPython.Comm = Comm;
212
212
213 return {
213 return {
214 'CommManager': CommManager,
214 'CommManager': CommManager,
215 'Comm': Comm
215 'Comm': Comm
216 };
216 };
217 });
217 });
General Comments 0
You need to be logged in to leave comments. Login now