You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
|
|
/*global Blob,File*/
/** * Module requirements */
var isArray = require('isarray'); var isBuf = require('./is-buffer'); var toString = Object.prototype.toString; var withNativeBlob = typeof Blob === 'function' || (typeof Blob !== 'undefined' && toString.call(Blob) === '[object BlobConstructor]'); var withNativeFile = typeof File === 'function' || (typeof File !== 'undefined' && toString.call(File) === '[object FileConstructor]');
/** * 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; var pack = packet; pack.data = _deconstructPacket(packetData, buffers); pack.attachments = buffers.length; // number of binary 'attachments'
return {packet: pack, buffers: buffers}; };
function _deconstructPacket(data, buffers) { 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], buffers); } return newData; } else if (typeof data === 'object' && !(data instanceof Date)) { var newData = {}; for (var key in data) { newData[key] = _deconstructPacket(data[key], buffers); } return newData; } return data; }
/** * 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) { packet.data = _reconstructPacket(packet.data, buffers); packet.attachments = undefined; // no longer useful
return packet; };
function _reconstructPacket(data, buffers) { if (!data) return data;
if (data && data._placeholder) { return buffers[data.num]; // appropriate buffer (should be natural order anyway)
} else if (isArray(data)) { for (var i = 0; i < data.length; i++) { data[i] = _reconstructPacket(data[i], buffers); } } else if (typeof data === 'object') { for (var key in data) { data[key] = _reconstructPacket(data[key], buffers); } }
return data; }
/** * 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 ((withNativeBlob && obj instanceof Blob) || (withNativeFile && 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 (typeof obj === 'object' && !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); } };
|