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