123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- /*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);
- }
- };
|