##// END OF EJS Templates
support binary message from javascript
MinRK -
Show More
@@ -49,7 +49,6 b' def serialize_binary_message(msg):'
49 bmsg = json.dumps(msg, default=date_default).encode('utf8')
49 bmsg = json.dumps(msg, default=date_default).encode('utf8')
50 buffers.insert(0, bmsg)
50 buffers.insert(0, bmsg)
51 nbufs = len(buffers)
51 nbufs = len(buffers)
52 sizes = (len(buf) for buf in buffers)
53 offsets = [4 * (nbufs + 1)]
52 offsets = [4 * (nbufs + 1)]
54 for buf in buffers[:-1]:
53 for buf in buffers[:-1]:
55 offsets.append(offsets[-1] + len(buf))
54 offsets.append(offsets[-1] + len(buf))
@@ -12,7 +12,7 b' from IPython.utils.py3compat import string_types'
12 from IPython.html.utils import url_path_join, url_escape
12 from IPython.html.utils import url_path_join, url_escape
13
13
14 from ...base.handlers import IPythonHandler, json_errors
14 from ...base.handlers import IPythonHandler, json_errors
15 from ...base.zmqhandlers import AuthenticatedZMQStreamHandler
15 from ...base.zmqhandlers import AuthenticatedZMQStreamHandler, deserialize_binary_message
16
16
17 from IPython.core.release import kernel_protocol_version
17 from IPython.core.release import kernel_protocol_version
18
18
@@ -150,7 +150,10 b' class ZMQChannelHandler(AuthenticatedZMQStreamHandler):'
150 self.log.info("%s closed, closing websocket.", self)
150 self.log.info("%s closed, closing websocket.", self)
151 self.close()
151 self.close()
152 return
152 return
153 msg = json.loads(msg)
153 if isinstance(msg, bytes):
154 msg = deserialize_binary_message(msg)
155 else:
156 msg = json.loads(msg)
154 self.session.send(self.zmq_stream, msg)
157 self.session.send(self.zmq_stream, msg)
155
158
156 def on_close(self):
159 def on_close(self):
@@ -129,12 +129,12 b' define(['
129 return this.kernel.send_shell_message("comm_open", content, callbacks, metadata);
129 return this.kernel.send_shell_message("comm_open", content, callbacks, metadata);
130 };
130 };
131
131
132 Comm.prototype.send = function (data, callbacks, metadata) {
132 Comm.prototype.send = function (data, callbacks, metadata, buffers) {
133 var content = {
133 var content = {
134 comm_id : this.comm_id,
134 comm_id : this.comm_id,
135 data : data || {},
135 data : data || {},
136 };
136 };
137 return this.kernel.send_shell_message("comm_msg", content, callbacks, metadata);
137 return this.kernel.send_shell_message("comm_msg", content, callbacks, metadata, buffers);
138 };
138 };
139
139
140 Comm.prototype.close = function (data, callbacks, metadata) {
140 Comm.prototype.close = function (data, callbacks, metadata) {
@@ -70,7 +70,7 b' define(['
70 /**
70 /**
71 * @function _get_msg
71 * @function _get_msg
72 */
72 */
73 Kernel.prototype._get_msg = function (msg_type, content, metadata) {
73 Kernel.prototype._get_msg = function (msg_type, content, metadata, buffers) {
74 var msg = {
74 var msg = {
75 header : {
75 header : {
76 msg_id : utils.uuid(),
76 msg_id : utils.uuid(),
@@ -81,6 +81,7 b' define(['
81 },
81 },
82 metadata : metadata || {},
82 metadata : metadata || {},
83 content : content,
83 content : content,
84 buffers : buffers || [],
84 parent_header : {}
85 parent_header : {}
85 };
86 };
86 return msg;
87 return msg;
@@ -597,12 +598,12 b' define(['
597 *
598 *
598 * @function send_shell_message
599 * @function send_shell_message
599 */
600 */
600 Kernel.prototype.send_shell_message = function (msg_type, content, callbacks, metadata) {
601 Kernel.prototype.send_shell_message = function (msg_type, content, callbacks, metadata, buffers) {
601 if (!this.is_connected()) {
602 if (!this.is_connected()) {
602 throw new Error("kernel is not connected");
603 throw new Error("kernel is not connected");
603 }
604 }
604 var msg = this._get_msg(msg_type, content, metadata);
605 var msg = this._get_msg(msg_type, content, metadata, buffers);
605 this.channels.shell.send(JSON.stringify(msg));
606 this.channels.shell.send(serialize.serialize(msg));
606 this.set_callbacks_for_msg(msg.header.msg_id, callbacks);
607 this.set_callbacks_for_msg(msg.header.msg_id, callbacks);
607 return msg.header.msg_id;
608 return msg.header.msg_id;
608 };
609 };
@@ -753,7 +754,7 b' define(['
753 };
754 };
754 this.events.trigger('input_reply.Kernel', {kernel: this, content: content});
755 this.events.trigger('input_reply.Kernel', {kernel: this, content: content});
755 var msg = this._get_msg("input_reply", content);
756 var msg = this._get_msg("input_reply", content);
756 this.channels.stdin.send(JSON.stringify(msg));
757 this.channels.stdin.send(serialize.serialize(msg));
757 return msg.header.msg_id;
758 return msg.header.msg_id;
758 };
759 };
759
760
@@ -6,42 +6,53 b' define(['
6 'components/utf8/utf8'
6 'components/utf8/utf8'
7 ], function ($, utf8) {
7 ], function ($, utf8) {
8 "use strict";
8 "use strict";
9
9
10 var _deserialize_binary = function(blob, callback) {
10 var _deserialize_array_buffer = function (buf) {
11 var data = new DataView(buf);
12 // read the header: 1 + nbufs 32b integers
13 var nbufs = data.getInt32(0);
14 var offsets = [];
15 var i;
16 for (i = 1; i <= nbufs; i++) {
17 offsets.push(data.getInt32(i * 4));
18 }
19 // have to convert array to string for utf8.js
20 var bytestring = String.fromCharCode.apply(null,
21 new Uint8Array(buf.slice(offsets[0], offsets[1]))
22 );
23 var msg = $.parseJSON(
24 utf8.decode(
25 bytestring
26 )
27 );
28 // the remaining chunks are stored as DataViews in msg.buffers
29 msg.buffers = [];
30 var start, stop;
31 for (i = 1; i < nbufs; i++) {
32 start = offsets[i];
33 stop = offsets[i+1] || buf.byteLength;
34 msg.buffers.push(new DataView(buf.slice(start, stop)));
35 }
36 return msg;
37 };
38
39 var _deserialize_binary = function(data, callback) {
11 // deserialize the binary message format
40 // deserialize the binary message format
12 // callback will be called with a message whose buffers attribute
41 // callback will be called with a message whose buffers attribute
13 // will be an array of DataViews.
42 // will be an array of DataViews.
14 var reader = new FileReader();
43 if (data instanceof Blob) {
15 reader.onload = function () {
44 // data is Blob, have to deserialize from ArrayBuffer in reader callback
16 var buf = this.result; // an ArrayBuffer
45 var reader = new FileReader();
17 var data = new DataView(buf);
46 reader.onload = function () {
18 // read the header: 1 + nbufs 32b integers
47 var msg = _deserialize_array_buffer(this.result);
19 var nbufs = data.getInt32(0);
48 callback(msg);
20 var offsets = [];
49 };
21 var i;
50 reader.readAsArrayBuffer(data);
22 for (i = 1; i <= nbufs; i++) {
51 } else {
23 offsets.push(data.getInt32(i * 4));
52 // data is ArrayBuffer, can deserialize directly
24 }
53 var msg = _deserialize_array_buffer(data);
25 // have to convert array to string for utf8.js
26 var bytestring = String.fromCharCode.apply(null,
27 new Uint8Array(buf.slice(offsets[0], offsets[1]))
28 );
29 var msg = $.parseJSON(
30 utf8.decode(
31 bytestring
32 )
33 );
34 // the remaining chunks are stored as DataViews in msg.buffers
35 msg.buffers = [];
36 var start, stop;
37 for (i = 1; i < nbufs; i++) {
38 start = offsets[i];
39 stop = offsets[i+1] || buf.byteLength;
40 msg.buffers.push(new DataView(buf.slice(start, stop)));
41 }
42 callback(msg);
54 callback(msg);
43 };
55 }
44 reader.readAsArrayBuffer(blob);
45 };
56 };
46
57
47 var deserialize = function (data, callback) {
58 var deserialize = function (data, callback) {
@@ -55,7 +66,63 b' define(['
55 }
66 }
56 };
67 };
57
68
58 return {
69 var _bytes2buf = function (bytestring) {
59 deserialize : deserialize
70 // convert bytestring to UInt8Array
71 var nbytes = bytestring.length;
72 var buf = new Uint8Array(nbytes);
73 for (var i = 0; i < nbytes; i++) {
74 buf[i] = bytestring.charCodeAt(i);
75 }
76 return buf;
77 };
78
79 var _serialize_binary = function (msg) {
80 // implement the binary serialization protocol
81 // serializes JSON message to ArrayBuffer
82 msg = $.extend({}, msg);
83 var offsets = [];
84 var buffers = msg.buffers;
85 delete msg.buffers;
86 var json_utf8 = _bytes2buf(utf8.encode(JSON.stringify(msg)));
87 buffers.unshift(json_utf8);
88 var nbufs = buffers.length;
89 offsets.push(4 * (nbufs + 1));
90 var i;
91 for (i = 0; i + 1 < buffers.length; i++) {
92 offsets.push(offsets[offsets.length-1] + buffers[i].byteLength);
93 }
94 var msg_buf = new Uint8Array(
95 offsets[offsets.length-1] + buffers[buffers.length-1].byteLength
96 );
97 // use DataView.setInt32 for network byte-order
98 var view = new DataView(msg_buf.buffer);
99 // write nbufs to first 4 bytes
100 view.setInt32(0, nbufs);
101 // write offsets to next 4 * nbufs bytes
102 for (i = 0; i < offsets.length; i++) {
103 view.setInt32(4 * (i+1), offsets[i]);
104 }
105 // write all the buffers at their respective offsets
106 for (i = 0; i < buffers.length; i++) {
107 msg_buf.set(new Uint8Array(buffers[i].buffer), offsets[i]);
108 }
109
110 // return raw ArrayBuffer
111 return msg_buf.buffer;
112 };
113
114 var serialize = function (msg) {
115 console.log(msg.buffers, msg.buffers.length);
116 if (msg.buffers && msg.buffers.length) {
117 return _serialize_binary(msg);
118 } else {
119 return JSON.stringify(msg);
120 }
121 };
122
123 var exports = {
124 deserialize : deserialize,
125 serialize: serialize
60 };
126 };
127 return exports;
61 }); No newline at end of file
128 });
General Comments 0
You need to be logged in to leave comments. Login now