123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- /*global Blob,File*/
- /**
- * Module requirements
- */
- var isArray = require('isarray');
- var isBuf = require('./is-buffer');
- /**
- * Replaces every Buffer | ArrayBuffer in packet with a numbered placeholder.
- * Anything with blobs or files should be fed through removeBlobs before coming
- * here.
- *
- * @param {Object} packet - socket.io event packet
- * @return {Object} with deconstructed packet and list of buffers
- * @api public
- */
- exports.deconstructPacket = function(packet){
- var buffers = [];
- var packetData = packet.data;
- function _deconstructPacket(data) {
- if (!data) return data;
- if (isBuf(data)) {
- var placeholder = { _placeholder: true, num: buffers.length };
- buffers.push(data);
- return placeholder;
- } else if (isArray(data)) {
- var newData = new Array(data.length);
- for (var i = 0; i < data.length; i++) {
- newData[i] = _deconstructPacket(data[i]);
- }
- return newData;
- } else if ('object' == typeof data && !(data instanceof Date)) {
- var newData = {};
- for (var key in data) {
- newData[key] = _deconstructPacket(data[key]);
- }
- return newData;
- }
- return data;
- }
- var pack = packet;
- pack.data = _deconstructPacket(packetData);
- pack.attachments = buffers.length; // number of binary 'attachments'
- return {packet: pack, buffers: buffers};
- };
- /**
- * Reconstructs a binary packet from its placeholder packet and buffers
- *
- * @param {Object} packet - event packet with placeholders
- * @param {Array} buffers - binary buffers to put in placeholder positions
- * @return {Object} reconstructed packet
- * @api public
- */
- exports.reconstructPacket = function(packet, buffers) {
- var curPlaceHolder = 0;
- function _reconstructPacket(data) {
- if (data && data._placeholder) {
- var buf = buffers[data.num]; // appropriate buffer (should be natural order anyway)
- return buf;
- } else if (isArray(data)) {
- for (var i = 0; i < data.length; i++) {
- data[i] = _reconstructPacket(data[i]);
- }
- return data;
- } else if (data && 'object' == typeof data) {
- for (var key in data) {
- data[key] = _reconstructPacket(data[key]);
- }
- return data;
- }
- return data;
- }
- packet.data = _reconstructPacket(packet.data);
- packet.attachments = undefined; // no longer useful
- return packet;
- };
- /**
- * Asynchronously removes Blobs or Files from data via
- * FileReader's readAsArrayBuffer method. Used before encoding
- * data as msgpack. Calls callback with the blobless data.
- *
- * @param {Object} data
- * @param {Function} callback
- * @api private
- */
- exports.removeBlobs = function(data, callback) {
- function _removeBlobs(obj, curKey, containingObject) {
- if (!obj) return obj;
- // convert any blob
- if ((global.Blob && obj instanceof Blob) ||
- (global.File && obj instanceof File)) {
- pendingBlobs++;
- // async filereader
- var fileReader = new FileReader();
- fileReader.onload = function() { // this.result == arraybuffer
- if (containingObject) {
- containingObject[curKey] = this.result;
- }
- else {
- bloblessData = this.result;
- }
- // if nothing pending its callback time
- if(! --pendingBlobs) {
- callback(bloblessData);
- }
- };
- fileReader.readAsArrayBuffer(obj); // blob -> arraybuffer
- } else if (isArray(obj)) { // handle array
- for (var i = 0; i < obj.length; i++) {
- _removeBlobs(obj[i], i, obj);
- }
- } else if (obj && 'object' == typeof obj && !isBuf(obj)) { // and object
- for (var key in obj) {
- _removeBlobs(obj[key], key, obj);
- }
- }
- }
- var pendingBlobs = 0;
- var bloblessData = data;
- _removeBlobs(bloblessData);
- if (!pendingBlobs) {
- callback(bloblessData);
- }
- };
|