Fixed Non-ASCII attachment filename will crash when downloading.

Thanks to xet7 !

Fixes #2759
This commit is contained in:
Lauri Ojansivu 2021-04-29 13:26:49 +03:00
parent 843ff8eaaa
commit c2da477735
277 changed files with 30568 additions and 52 deletions

View file

@ -0,0 +1,5 @@
language: node_js
node_js:
- "0.10"
before_install:
- "curl -L http://git.io/s0Zu-w | /bin/sh"

View file

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2014 [@raix](https://github.com/raix), aka Morten N.O. Nørgaard Henriksen, mh@gi-software.com, and [@aldeed](https://github.com/aldeed), aka Eric Dobbertin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1,8 @@
wekan-cfs-data-man [![Build Status](https://travis-ci.org/CollectionFS/Meteor-data-man.svg?branch=master)](https://travis-ci.org/CollectionFS/Meteor-data-man)
=========================
Who can handle your arbitrary data? The DataMan can.
This is a package used by CollectionFS to attach data to file objects. Could be used for other things, though.
[Public API](api.md)

View file

@ -0,0 +1,309 @@
## data-man Public API ##
A data manager, allowing you to attach various types of data and get it back in various other types
_API documentation automatically generated by [docmeteor](https://github.com/raix/docmeteor)._
-
### <a name="DataMan"></a>new DataMan(data, [type])&nbsp;&nbsp;<sub><i>Client</i></sub> ###
__Arguments__
* __data__ *{[File](#File)|[Blob](#Blob)|ArrayBuffer|Uint8Array|String}*
The data that you want to manipulate.
* __type__ *{String}* (Optional)
The data content (MIME) type, if known. Required if the first argument is an ArrayBuffer, Uint8Array, or URL
> ```DataMan = function DataMan(data, type) { ...``` [client/data-man-api.js:8](client/data-man-api.js#L8)
-
### <a name="DataMan.prototype.getBlob"></a>*dataman*.getBlob(callback)&nbsp;&nbsp;<sub><i>Client</i></sub> ###
*This method __getBlob__ is defined in `prototype` of `DataMan`*
__Arguments__
* __callback__ *{Function}*
callback(error, blob)
__Returns__ *{undefined}*
Passes a Blob representing this data to a callback.
> ```DataMan.prototype.getBlob = function dataManGetBlob(callback) { ...``` [client/data-man-api.js:52](client/data-man-api.js#L52)
-
### <a name="DataMan.prototype.getBinary"></a>*dataman*.getBinary([start], [end], callback)&nbsp;&nbsp;<sub><i>Client</i></sub> ###
*This method __getBinary__ is defined in `prototype` of `DataMan`*
__Arguments__
* __start__ *{Number}* (Optional)
First byte position to read.
* __end__ *{Number}* (Optional)
Last byte position to read.
* __callback__ *{Function}*
callback(error, binaryData)
__Returns__ *{undefined}*
Passes a Uint8Array representing this data to a callback.
> ```DataMan.prototype.getBinary = function dataManGetBinary(start, end, callback) { ...``` [client/data-man-api.js:84](client/data-man-api.js#L84)
-
### <a name="DataMan.prototype.saveAs"></a>*dataman*.saveAs([filename])&nbsp;&nbsp;<sub><i>Client</i></sub> ###
*This method __saveAs__ is defined in `prototype` of `DataMan`*
__Arguments__
* __filename__ *{String}* (Optional)
__Returns__ *{undefined}*
Tells the browser to save the data like a normal downloaded file,
using the provided filename.
> ```DataMan.prototype.saveAs = function dataManSaveAs(filename) { ...``` [client/data-man-api.js:146](client/data-man-api.js#L146)
-
### <a name="DataMan.prototype.getDataUri"></a>*dataman*.getDataUri(callback)&nbsp;&nbsp;<sub><i>Client</i></sub> ###
*This method __getDataUri__ is defined in `prototype` of `DataMan`*
__Arguments__
* __callback__ *{function}*
callback(err, dataUri)
> ```DataMan.prototype.getDataUri = function dataManGetDataUri(callback) { ...``` [client/data-man-api.js:166](client/data-man-api.js#L166)
-
### <a name="DataMan.prototype.type"></a>*dataman*.type()&nbsp;&nbsp;<sub><i>Client</i></sub> ###
*This method __type__ is defined in `prototype` of `DataMan`*
Returns the type of the data.
> ```DataMan.prototype.type = function dataManType() { ...``` [client/data-man-api.js:227](client/data-man-api.js#L227)
-
### <a name="DataMan"></a>new DataMan(data, [type])&nbsp;&nbsp;<sub><i>Server</i></sub> ###
__Arguments__
* __data__ *{Buffer|ArrayBuffer|Uint8Array|String}*
The data that you want to manipulate.
* __type__ *{String}* (Optional)
The data content (MIME) type, if known. Required if the first argument is a Buffer, ArrayBuffer, Uint8Array, or URL
> ```DataMan = function DataMan(data, type) { ...``` [server/data-man-api.js:10](server/data-man-api.js#L10)
-
### <a name="DataMan.prototype.getBuffer"></a>*dataman*.getBuffer([callback])&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method __getBuffer__ is defined in `prototype` of `DataMan`*
__Arguments__
* __callback__ *{function}* (Optional)
callback(err, buffer)
__Returns__ *{Buffer|undefined}*
Returns a Buffer representing this data, or passes the Buffer to a callback.
> ```DataMan.prototype.getBuffer = function dataManGetBuffer(callback) { ...``` [server/data-man-api.js:54](server/data-man-api.js#L54)
-
### <a name="DataMan.prototype.saveToFile"></a>*dataman*.saveToFile()&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method __saveToFile__ is defined in `prototype` of `DataMan`*
__Returns__ *{undefined}*
Saves this data to a filepath on the local filesystem.
> ```DataMan.prototype.saveToFile = function dataManSaveToFile(filePath) { ...``` [server/data-man-api.js:66](server/data-man-api.js#L66)
-
### <a name="DataMan.prototype.getDataUri"></a>*dataman*.getDataUri([callback])&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method __getDataUri__ is defined in `prototype` of `DataMan`*
__Arguments__
* __callback__ *{function}* (Optional)
callback(err, dataUri)
If no callback, returns the data URI.
> ```DataMan.prototype.getDataUri = function dataManGetDataUri(callback) { ...``` [server/data-man-api.js:84](server/data-man-api.js#L84)
-
### <a name="DataMan.prototype.createReadStream"></a>*dataman*.createReadStream()&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method __createReadStream__ is defined in `prototype` of `DataMan`*
Returns a read stream for the data.
> ```DataMan.prototype.createReadStream = function dataManCreateReadStream() { ...``` [server/data-man-api.js:95](server/data-man-api.js#L95)
-
### <a name="DataMan.prototype.size"></a>*dataman*.size([callback])&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method __size__ is defined in `prototype` of `DataMan`*
__Arguments__
* __callback__ *{function}* (Optional)
callback(err, size)
If no callback, returns the size in bytes of the data.
> ```DataMan.prototype.size = function dataManSize(callback) { ...``` [server/data-man-api.js:106](server/data-man-api.js#L106)
-
### <a name="DataMan.prototype.type"></a>*dataman*.type()&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method __type__ is defined in `prototype` of `DataMan`*
Returns the type of the data.
> ```DataMan.prototype.type = function dataManType() { ...``` [server/data-man-api.js:117](server/data-man-api.js#L117)
-
### <a name="DataMan.Buffer"></a>new *dataman*.Buffer(buffer, type)&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method __Buffer__ is defined in `DataMan`*
__Arguments__
* __buffer__ *{Buffer}*
* __type__ *{String}*
The data content (MIME) type.
> ```DataMan.Buffer = function DataManBuffer(buffer, type) { ...``` [server/data-man-buffer.js:10](server/data-man-buffer.js#L10)
-
### <a name="DataMan.DataURI"></a>new *dataman*.DataURI(dataUri)&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method __DataURI__ is defined in `DataMan`*
__Arguments__
* __dataUri__ *{String}*
> ```DataMan.DataURI = function DataManDataURI(dataUri) { ...``` [server/data-man-datauri.js:7](server/data-man-datauri.js#L7)
-
### <a name="DataMan.FilePath"></a>new *dataman*.FilePath(filepath, [type])&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method __FilePath__ is defined in `DataMan`*
__Arguments__
* __filepath__ *{String}*
* __type__ *{String}* (Optional)
The data content (MIME) type. Will lookup from file if not passed.
> ```DataMan.FilePath = function DataManFilePath(filepath, type) { ...``` [server/data-man-filepath.js:11](server/data-man-filepath.js#L11)
-
### <a name="DataMan.URL"></a>new *dataman*.URL(url, type)&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method __URL__ is defined in `DataMan`*
__Arguments__
* __url__ *{String}*
* __type__ *{String}*
The data content (MIME) type.
> ```DataMan.URL = function DataManURL(url, type) { ...``` [server/data-man-url.js:10](server/data-man-url.js#L10)

View file

@ -0,0 +1,166 @@
/* Blob.js
* A Blob implementation.
* 2013-12-27
*
* By Eli Grey, http://eligrey.com
* By Devin Samarin, https://github.com/eboyjr
* License: X11/MIT
* See LICENSE.md
*/
/*global self, unescape */
/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
plusplus: true */
/*! @source http://purl.eligrey.com/github/Blob.js/blob/master/Blob.js */
if (!(typeof Blob === "function" || typeof Blob === "object") || typeof URL === "undefined")
if ((typeof Blob === "function" || typeof Blob === "object") && typeof webkitURL !== "undefined") self.URL = webkitURL;
else var Blob = (function (view) {
"use strict";
var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || view.MSBlobBuilder || (function(view) {
var
get_class = function(object) {
return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1];
}
, FakeBlobBuilder = function BlobBuilder() {
this.data = [];
}
, FakeBlob = function Blob(data, type, encoding) {
this.data = data;
this.size = data.length;
this.type = type;
this.encoding = encoding;
}
, FBB_proto = FakeBlobBuilder.prototype
, FB_proto = FakeBlob.prototype
, FileReaderSync = view.FileReaderSync
, FileException = function(type) {
this.code = this[this.name = type];
}
, file_ex_codes = (
"NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR "
+ "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR"
).split(" ")
, file_ex_code = file_ex_codes.length
, real_URL = view.URL || view.webkitURL || view
, real_create_object_URL = real_URL.createObjectURL
, real_revoke_object_URL = real_URL.revokeObjectURL
, URL = real_URL
, btoa = view.btoa
, atob = view.atob
, ArrayBuffer = view.ArrayBuffer
, Uint8Array = view.Uint8Array
;
FakeBlob.fake = FB_proto.fake = true;
while (file_ex_code--) {
FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1;
}
if (!real_URL.createObjectURL) {
URL = view.URL = {};
}
URL.createObjectURL = function(blob) {
var
type = blob.type
, data_URI_header
;
if (type === null) {
type = "application/octet-stream";
}
if (blob instanceof FakeBlob) {
data_URI_header = "data:" + type;
if (blob.encoding === "base64") {
return data_URI_header + ";base64," + blob.data;
} else if (blob.encoding === "URI") {
return data_URI_header + "," + decodeURIComponent(blob.data);
} if (btoa) {
return data_URI_header + ";base64," + btoa(blob.data);
} else {
return data_URI_header + "," + encodeURIComponent(blob.data);
}
} else if (real_create_object_URL) {
return real_create_object_URL.call(real_URL, blob);
}
};
URL.revokeObjectURL = function(object_URL) {
if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) {
real_revoke_object_URL.call(real_URL, object_URL);
}
};
FBB_proto.append = function(data/*, endings*/) {
var bb = this.data;
// decode data to a binary string
if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) {
var
str = ""
, buf = new Uint8Array(data)
, i = 0
, buf_len = buf.length
;
for (; i < buf_len; i++) {
str += String.fromCharCode(buf[i]);
}
bb.push(str);
} else if (get_class(data) === "Blob" || get_class(data) === "File") {
if (FileReaderSync) {
var fr = new FileReaderSync;
bb.push(fr.readAsBinaryString(data));
} else {
// async FileReader won't work as BlobBuilder is sync
throw new FileException("NOT_READABLE_ERR");
}
} else if (data instanceof FakeBlob) {
if (data.encoding === "base64" && atob) {
bb.push(atob(data.data));
} else if (data.encoding === "URI") {
bb.push(decodeURIComponent(data.data));
} else if (data.encoding === "raw") {
bb.push(data.data);
}
} else {
if (typeof data !== "string") {
data += ""; // convert unsupported types to strings
}
// decode UTF-16 to binary string
bb.push(unescape(encodeURIComponent(data)));
}
};
FBB_proto.getBlob = function(type) {
if (!arguments.length) {
type = null;
}
return new FakeBlob(this.data.join(""), type, "raw");
};
FBB_proto.toString = function() {
return "[object BlobBuilder]";
};
FB_proto.slice = function(start, end, type) {
var args = arguments.length;
if (args < 3) {
type = null;
}
return new FakeBlob(
this.data.slice(start, args > 1 ? end : this.data.length)
, type
, this.encoding
);
};
FB_proto.toString = function() {
return "[object Blob]";
};
return FakeBlobBuilder;
}(view));
return function Blob(blobParts, options) {
var type = options ? (options.type || "") : "";
var builder = new BlobBuilder();
if (blobParts) {
for (var i = 0, len = blobParts.length; i < len; i++) {
builder.append(blobParts[i]);
}
}
return builder.getBlob(type);
};
}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content || this));

View file

@ -0,0 +1,302 @@
/**
* @method DataMan
* @public
* @constructor
* @param {File|Blob|ArrayBuffer|Uint8Array|String} data The data that you want to manipulate.
* @param {String} [type] The data content (MIME) type, if known. Required if the first argument is an ArrayBuffer, Uint8Array, or URL
*/
DataMan = function DataMan(data, type) {
var self = this;
if (!data) {
throw new Error("DataMan constructor requires a data argument");
}
// The end result of all this is that we will have one of the following set:
// - self.blob
// - self.url
// Unless we already have in-memory data, we don't load anything into memory
// and instead rely on obtaining a read stream when the time comes.
if (typeof File !== "undefined" && data instanceof File) {
self.blob = data; // File inherits from Blob so this is OK
self._type = data.type;
} else if (typeof Blob !== "undefined" && data instanceof Blob) {
self.blob = data;
self._type = data.type;
} else if (typeof ArrayBuffer !== "undefined" && data instanceof ArrayBuffer || EJSON.isBinary(data)) {
if (typeof Blob === "undefined") {
throw new Error("Browser must support Blobs to handle an ArrayBuffer or Uint8Array");
}
if (!type) {
throw new Error("DataMan constructor requires a type argument when passed an ArrayBuffer or Uint8Array");
}
self.blob = new Blob([data], {type: type});
self._type = type;
} else if (typeof data === "string") {
if (data.slice(0, 5) === "data:") {
self._type = data.slice(5, data.indexOf(';'));
self.blob = dataURItoBlob(data, self._type);
} else if (data.slice(0, 5) === "http:" || data.slice(0, 6) === "https:") {
if (!type) {
throw new Error("DataMan constructor requires a type argument when passed a URL");
}
self.url = data;
self._type = type;
} else {
throw new Error("DataMan constructor received unrecognized data string");
}
} else {
throw new Error("DataMan constructor received data that it doesn't support");
}
};
/**
* @method DataMan.prototype.getBlob
* @public
* @param {Function} [callback] - callback(error, blob)
* @returns {undefined|Blob}
*
* Passes a Blob representing this data to a callback or returns
* the Blob if no callback is provided. A callback is required
* if getting a Blob for a URL.
*/
DataMan.prototype.getBlob = function dataManGetBlob(callback) {
var self = this;
if (callback) {
if (self.blob) {
callback(null, self.blob);
} else if (self.url) {
var xhr = new XMLHttpRequest();
xhr.open('GET', self.url, true);
xhr.responseType = "blob";
xhr.onload = function(data) {
self.blob = xhr.response;
callback(null, self.blob);
};
xhr.onerror = function(err) {
callback(err);
};
xhr.send();
}
} else {
if (self.url)
throw new Error('DataMan.getBlob requires a callback when managing a URL');
return self.blob;
}
};
/**
* @method DataMan.prototype.getBinary
* @public
* @param {Number} [start] - First byte position to read.
* @param {Number} [end] - Last byte position to read.
* @param {Function} callback - callback(error, binaryData)
* @returns {undefined}
*
* Passes a Uint8Array representing this data to a callback.
*/
DataMan.prototype.getBinary = function dataManGetBinary(start, end, callback) {
var self = this;
if (typeof start === "function") {
callback = start;
}
callback = callback || defaultCallback;
function read(blob) {
if (typeof FileReader === "undefined") {
callback(new Error("Browser does not support FileReader"));
return;
}
var reader = new FileReader();
reader.onload = function(evt) {
callback(null, new Uint8Array(evt.target.result));
};
reader.onerror = function(err) {
callback(err);
};
reader.readAsArrayBuffer(blob);
}
self.getBlob(function (error, blob) {
if (error) {
callback(error);
} else {
if (typeof start === "number" && typeof end === "number") {
var size = blob.size;
// Return the requested chunk of binary data
if (start >= size) {
callback(new Error("DataMan.getBinary: start position beyond end of data (" + size + ")"));
return;
}
end = Math.min(size, end);
var slice = blob.slice || blob.webkitSlice || blob.mozSlice;
if (typeof slice === 'undefined') {
callback(new Error('Browser does not support File.slice'));
return;
}
read(slice.call(blob, start, end, self._type));
} else {
// Return the entire binary data
read(blob);
}
}
});
};
/** @method DataMan.prototype.saveAs
* @public
* @param {String} [filename]
* @return {undefined}
*
* Tells the browser to save the data like a normal downloaded file,
* using the provided filename.
*
*/
DataMan.prototype.saveAs = function dataManSaveAs(filename) {
var self = this;
if (typeof window === "undefined")
throw new Error("window must be defined to use saveLocal");
if (!window.saveAs) {
console.warn('DataMan.saveAs: window.saveAs not supported by this browser - add cfs-filesaver package');
return;
}
self.getBlob(function (error, blob) {
if (error) {
throw error;
} else {
window.saveAs(blob, filename);
}
});
};
/**
* @method DataMan.prototype.getDataUri
* @public
* @param {function} callback callback(err, dataUri)
*/
DataMan.prototype.getDataUri = function dataManGetDataUri(callback) {
// XXX: We could consider using: URL.createObjectURL(blob);
// This will create a reference to the blob data instead of a clone
// This is part of the File API - as the rest - Not sure how to generally
// support from IE10, FF26, Chrome 31, safari 7, opera 19, ios 6, android 4
var self = this;
if (typeof callback !== 'function')
throw new Error("getDataUri requires callback function");
if (typeof FileReader === "undefined") {
callback(new Error("Browser does not support FileReader"));
return;
}
var fileReader = new FileReader();
fileReader.onload = function(event) {
var dataUri = event.target.result;
callback(null, dataUri);
};
fileReader.onerror = function(err) {
callback(err);
};
self.getBlob(function (error, blob) {
if (error) {
callback(error);
} else {
fileReader.readAsDataURL(blob);
}
});
};
/**
* @method DataMan.prototype.size
* @public
* @param {function} [callback] callback(err, size)
*
* Passes the size of the data to the callback, if provided,
* or returns it. A callback is required to get the size of a URL on the client.
*/
DataMan.prototype.size = function dataManSize(callback) {
var self = this;
if (callback) {
if (typeof self._size === "number") {
callback(null, self._size);
} else {
self.getBlob(function (error, blob) {
if (error) {
callback(error);
} else {
self._size = blob.size;
callback(null, self._size);
}
});
}
} else {
if (self.url) {
throw new Error("On the client, DataMan.size requires a callback when getting size for a URL on the client");
} else if (typeof self._size === "number") {
return self._size;
} else {
var blob = self.getBlob();
self._size = blob.size;
return self._size;
}
}
};
/**
* @method DataMan.prototype.type
* @public
*
* Returns the type of the data.
*/
DataMan.prototype.type = function dataManType() {
return this._type;
};
/**
* @method dataURItoBlob
* @private
* @param {String} dataURI The data URI
* @param {String} dataTYPE The content type
* @returns {Blob} A new Blob instance
*
* Converts a data URI to a Blob.
*/
function dataURItoBlob(dataURI, dataTYPE) {
var str = atob(dataURI.split(',')[1]), array = [];
for(var i = 0; i < str.length; i++) array.push(str.charCodeAt(i));
return new Blob([new Uint8Array(array)], {type: dataTYPE});
}
/**
* @method defaultCallback
* @private
* @param {Error} [err]
* @returns {undefined}
*
* Can be used as a default callback for client methods that need a callback.
* Simply throws the provided error if there is one.
*/
function defaultCallback(err) {
if (err) {
// Show gentle error if Meteor error
if (err instanceof Meteor.Error) {
console.error(err.message);
} else {
// Normal error, just throw error
throw err;
}
}
}

View file

@ -0,0 +1,674 @@
## Public and Private API ##
_API documentation automatically generated by [docmeteor](https://github.com/raix/docmeteor)._
***
__File: ["client/Blob.js"](client/Blob.js) Where: {client}__
***
### <a name="if "></a>if {any}&nbsp;&nbsp;<sub><i>Client</i></sub> ###
```
Blob.js
A Blob implementation.
2013-06-20
By Eli Grey, http:
By Devin Samarin, https:
License: X11/MIT
See LICENSE.md
```
> ```if ((typeof Blob !== ``` [client/Blob.js:17](client/Blob.js#L17)
-
### <a name="if "></a>if {any}&nbsp;&nbsp;<sub><i>Client</i></sub> ###
```
global unescape jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
plusplus: true
```
> ```if ((typeof Blob !== ``` [client/Blob.js:17](client/Blob.js#L17)
***
__File: ["client/data-man-api.js"](client/data-man-api.js) Where: {client}__
***
### <a name="DataMan"></a>new DataMan(data, [type])&nbsp;&nbsp;<sub><i>Client</i></sub> ###
__Arguments__
* __data__ *{[File](#File)|[Blob](#Blob)|ArrayBuffer|Uint8Array|String}*
The data that you want to manipulate.
* __type__ *{String}* (Optional)
The data content (MIME) type, if known. Required if the first argument is an ArrayBuffer, Uint8Array, or URL
> ```DataMan = function DataMan(data, type) { ...``` [client/data-man-api.js:8](client/data-man-api.js#L8)
-
### <a name="DataMan.prototype.getBlob"></a>*dataman*.getBlob(callback)&nbsp;&nbsp;<sub><i>Client</i></sub> ###
*This method __getBlob__ is defined in `prototype` of `DataMan`*
__Arguments__
* __callback__ *{Function}*
callback(error, blob)
__Returns__ *{undefined}*
Passes a Blob representing this data to a callback.
> ```DataMan.prototype.getBlob = function dataManGetBlob(callback) { ...``` [client/data-man-api.js:52](client/data-man-api.js#L52)
-
### <a name="DataMan.prototype.getBinary"></a>*dataman*.getBinary([start], [end], callback)&nbsp;&nbsp;<sub><i>Client</i></sub> ###
*This method __getBinary__ is defined in `prototype` of `DataMan`*
__Arguments__
* __start__ *{Number}* (Optional)
First byte position to read.
* __end__ *{Number}* (Optional)
Last byte position to read.
* __callback__ *{Function}*
callback(error, binaryData)
__Returns__ *{undefined}*
Passes a Uint8Array representing this data to a callback.
> ```DataMan.prototype.getBinary = function dataManGetBinary(start, end, callback) { ...``` [client/data-man-api.js:84](client/data-man-api.js#L84)
-
### <a name="DataMan.prototype.saveAs"></a>*dataman*.saveAs([filename])&nbsp;&nbsp;<sub><i>Client</i></sub> ###
*This method __saveAs__ is defined in `prototype` of `DataMan`*
__Arguments__
* __filename__ *{String}* (Optional)
__Returns__ *{undefined}*
Tells the browser to save the data like a normal downloaded file,
using the provided filename.
> ```DataMan.prototype.saveAs = function dataManSaveAs(filename) { ...``` [client/data-man-api.js:146](client/data-man-api.js#L146)
-
### <a name="DataMan.prototype.getDataUri"></a>*dataman*.getDataUri(callback)&nbsp;&nbsp;<sub><i>Client</i></sub> ###
*This method __getDataUri__ is defined in `prototype` of `DataMan`*
__Arguments__
* __callback__ *{function}*
callback(err, dataUri)
> ```DataMan.prototype.getDataUri = function dataManGetDataUri(callback) { ...``` [client/data-man-api.js:166](client/data-man-api.js#L166)
-
### <a name="DataMan.prototype.type"></a>*dataman*.type()&nbsp;&nbsp;<sub><i>Client</i></sub> ###
*This method __type__ is defined in `prototype` of `DataMan`*
Returns the type of the data.
> ```DataMan.prototype.type = function dataManType() { ...``` [client/data-man-api.js:227](client/data-man-api.js#L227)
-
### <a name="dataURItoBlob"></a>dataURItoBlob(dataURI, dataTYPE)&nbsp;&nbsp;<sub><i>undefined</i></sub> ###
*This method is private*
__Arguments__
* __dataURI__ *{String}*
The data URI
* __dataTYPE__ *{String}*
The content type
__Returns__ *{Blob}*
A new Blob instance
Converts a data URI to a Blob.
> ```function dataURItoBlob(dataURI, dataTYPE) { ...``` [client/data-man-api.js:240](client/data-man-api.js#L240)
-
### <a name="defaultCallback"></a>defaultCallback([err])&nbsp;&nbsp;<sub><i>undefined</i></sub> ###
*This method is private*
__Arguments__
* __err__ *{[Error](#Error)}* (Optional)
__Returns__ *{undefined}*
Can be used as a default callback for client methods that need a callback.
Simply throws the provided error if there is one.
> ```function defaultCallback(err) { ...``` [client/data-man-api.js:255](client/data-man-api.js#L255)
***
__File: ["server/data-man-api.js"](server/data-man-api.js) Where: {server}__
***
### <a name="DataMan"></a>new DataMan(data, [type])&nbsp;&nbsp;<sub><i>Server</i></sub> ###
__Arguments__
* __data__ *{Buffer|ArrayBuffer|Uint8Array|String}*
The data that you want to manipulate.
* __type__ *{String}* (Optional)
The data content (MIME) type, if known. Required if the first argument is a Buffer, ArrayBuffer, Uint8Array, or URL
> ```DataMan = function DataMan(data, type) { ...``` [server/data-man-api.js:10](server/data-man-api.js#L10)
-
### <a name="DataMan.prototype.getBuffer"></a>*dataman*.getBuffer([callback])&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method __getBuffer__ is defined in `prototype` of `DataMan`*
__Arguments__
* __callback__ *{function}* (Optional)
callback(err, buffer)
__Returns__ *{Buffer|undefined}*
Returns a Buffer representing this data, or passes the Buffer to a callback.
> ```DataMan.prototype.getBuffer = function dataManGetBuffer(callback) { ...``` [server/data-man-api.js:54](server/data-man-api.js#L54)
-
### <a name="DataMan.prototype.saveToFile"></a>*dataman*.saveToFile()&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method __saveToFile__ is defined in `prototype` of `DataMan`*
__Returns__ *{undefined}*
Saves this data to a filepath on the local filesystem.
> ```DataMan.prototype.saveToFile = function dataManSaveToFile(filePath) { ...``` [server/data-man-api.js:66](server/data-man-api.js#L66)
-
### <a name="DataMan.prototype.getDataUri"></a>*dataman*.getDataUri([callback])&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method __getDataUri__ is defined in `prototype` of `DataMan`*
__Arguments__
* __callback__ *{function}* (Optional)
callback(err, dataUri)
If no callback, returns the data URI.
> ```DataMan.prototype.getDataUri = function dataManGetDataUri(callback) { ...``` [server/data-man-api.js:84](server/data-man-api.js#L84)
-
### <a name="DataMan.prototype.createReadStream"></a>*dataman*.createReadStream()&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method __createReadStream__ is defined in `prototype` of `DataMan`*
Returns a read stream for the data.
> ```DataMan.prototype.createReadStream = function dataManCreateReadStream() { ...``` [server/data-man-api.js:95](server/data-man-api.js#L95)
-
### <a name="DataMan.prototype.size"></a>*dataman*.size([callback])&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method __size__ is defined in `prototype` of `DataMan`*
__Arguments__
* __callback__ *{function}* (Optional)
callback(err, size)
If no callback, returns the size in bytes of the data.
> ```DataMan.prototype.size = function dataManSize(callback) { ...``` [server/data-man-api.js:106](server/data-man-api.js#L106)
-
### <a name="DataMan.prototype.type"></a>*dataman*.type()&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method __type__ is defined in `prototype` of `DataMan`*
Returns the type of the data.
> ```DataMan.prototype.type = function dataManType() { ...``` [server/data-man-api.js:117](server/data-man-api.js#L117)
***
__File: ["server/data-man-buffer.js"](server/data-man-buffer.js) Where: {server}__
***
### <a name="DataMan.Buffer"></a>new *dataman*.Buffer(buffer, type)&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method __Buffer__ is defined in `DataMan`*
__Arguments__
* __buffer__ *{Buffer}*
* __type__ *{String}*
The data content (MIME) type.
> ```DataMan.Buffer = function DataManBuffer(buffer, type) { ...``` [server/data-man-buffer.js:10](server/data-man-buffer.js#L10)
-
### <a name="DataMan.Buffer.prototype.getBuffer"></a>*datamanBuffer*.getBuffer(callback)&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method is private*
*This method __getBuffer__ is defined in `prototype` of `DataMan.Buffer`*
__Arguments__
* __callback__ *{function}*
callback(err, buffer)
__Returns__ *{Buffer|undefined}*
Passes a Buffer representing the data to a callback.
> ```DataMan.Buffer.prototype.getBuffer = function dataManBufferGetBuffer(callback) { ...``` [server/data-man-buffer.js:24](server/data-man-buffer.js#L24)
-
### <a name="DataMan.Buffer.prototype.getDataUri"></a>*datamanBuffer*.getDataUri(callback)&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method is private*
*This method __getDataUri__ is defined in `prototype` of `DataMan.Buffer`*
__Arguments__
* __callback__ *{function}*
callback(err, dataUri)
Passes a data URI representing the data in the buffer to a callback.
> ```DataMan.Buffer.prototype.getDataUri = function dataManBufferGetDataUri(callback) { ...``` [server/data-man-buffer.js:35](server/data-man-buffer.js#L35)
-
### <a name="DataMan.Buffer.prototype.createReadStream"></a>*datamanBuffer*.createReadStream()&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method is private*
*This method __createReadStream__ is defined in `prototype` of `DataMan.Buffer`*
Returns a read stream for the data.
> ```DataMan.Buffer.prototype.createReadStream = function dataManBufferCreateReadStream() { ...``` [server/data-man-buffer.js:51](server/data-man-buffer.js#L51)
-
### <a name="DataMan.Buffer.prototype.size"></a>*datamanBuffer*.size(callback)&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method is private*
*This method __size__ is defined in `prototype` of `DataMan.Buffer`*
__Arguments__
* __callback__ *{function}*
callback(err, size)
Passes the size in bytes of the data in the buffer to a callback.
> ```DataMan.Buffer.prototype.size = function dataManBufferSize(callback) { ...``` [server/data-man-buffer.js:62](server/data-man-buffer.js#L62)
-
### <a name="DataMan.Buffer.prototype.type"></a>*datamanBuffer*.type()&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method is private*
*This method __type__ is defined in `prototype` of `DataMan.Buffer`*
Returns the type of the data.
> ```DataMan.Buffer.prototype.type = function dataManBufferType() { ...``` [server/data-man-buffer.js:80](server/data-man-buffer.js#L80)
***
__File: ["server/data-man-datauri.js"](server/data-man-datauri.js) Where: {server}__
***
### <a name="DataMan.DataURI"></a>new *dataman*.DataURI(dataUri)&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method __DataURI__ is defined in `DataMan`*
__Arguments__
* __dataUri__ *{String}*
> ```DataMan.DataURI = function DataManDataURI(dataUri) { ...``` [server/data-man-datauri.js:7](server/data-man-datauri.js#L7)
***
__File: ["server/data-man-filepath.js"](server/data-man-filepath.js) Where: {server}__
***
### <a name="DataMan.FilePath"></a>new *dataman*.FilePath(filepath, [type])&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method __FilePath__ is defined in `DataMan`*
__Arguments__
* __filepath__ *{String}*
* __type__ *{String}* (Optional)
The data content (MIME) type. Will lookup from file if not passed.
> ```DataMan.FilePath = function DataManFilePath(filepath, type) { ...``` [server/data-man-filepath.js:11](server/data-man-filepath.js#L11)
-
### <a name="DataMan.FilePath.prototype.getBuffer"></a>*datamanFilepath*.getBuffer(callback)&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method is private*
*This method __getBuffer__ is defined in `prototype` of `DataMan.FilePath`*
__Arguments__
* __callback__ *{function}*
callback(err, buffer)
__Returns__ *{Buffer|undefined}*
Passes a Buffer representing the data to a callback.
> ```DataMan.FilePath.prototype.getBuffer = function dataManFilePathGetBuffer(callback) { ...``` [server/data-man-filepath.js:25](server/data-man-filepath.js#L25)
-
### <a name="DataMan.FilePath.prototype.getDataUri"></a>*datamanFilepath*.getDataUri(callback)&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method is private*
*This method __getDataUri__ is defined in `prototype` of `DataMan.FilePath`*
__Arguments__
* __callback__ *{function}*
callback(err, dataUri)
Passes a data URI representing the data to a callback.
> ```DataMan.FilePath.prototype.getDataUri = function dataManFilePathGetDataUri(callback) { ...``` [server/data-man-filepath.js:43](server/data-man-filepath.js#L43)
-
### <a name="DataMan.FilePath.prototype.createReadStream"></a>*datamanFilepath*.createReadStream()&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method is private*
*This method __createReadStream__ is defined in `prototype` of `DataMan.FilePath`*
Returns a read stream for the data.
> ```DataMan.FilePath.prototype.createReadStream = function dataManFilePathCreateReadStream() { ...``` [server/data-man-filepath.js:67](server/data-man-filepath.js#L67)
-
### <a name="DataMan.FilePath.prototype.size"></a>*datamanFilepath*.size(callback)&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method is private*
*This method __size__ is defined in `prototype` of `DataMan.FilePath`*
__Arguments__
* __callback__ *{function}*
callback(err, size)
Passes the size in bytes of the data to a callback.
> ```DataMan.FilePath.prototype.size = function dataManFilePathSize(callback) { ...``` [server/data-man-filepath.js:79](server/data-man-filepath.js#L79)
-
### <a name="DataMan.FilePath.prototype.type"></a>*datamanFilepath*.type()&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method is private*
*This method __type__ is defined in `prototype` of `DataMan.FilePath`*
Returns the type of the data.
> ```DataMan.FilePath.prototype.type = function dataManFilePathType() { ...``` [server/data-man-filepath.js:104](server/data-man-filepath.js#L104)
***
__File: ["server/data-man-url.js"](server/data-man-url.js) Where: {server}__
***
### <a name="DataMan.URL"></a>new *dataman*.URL(url, type)&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method __URL__ is defined in `DataMan`*
__Arguments__
* __url__ *{String}*
* __type__ *{String}*
The data content (MIME) type.
> ```DataMan.URL = function DataManURL(url, type) { ...``` [server/data-man-url.js:10](server/data-man-url.js#L10)
-
### <a name="DataMan.URL.prototype.getBuffer"></a>*datamanUrl*.getBuffer(callback)&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method is private*
*This method __getBuffer__ is defined in `prototype` of `DataMan.URL`*
__Arguments__
* __callback__ *{function}*
callback(err, buffer)
__Returns__ *{Buffer|undefined}*
Passes a Buffer representing the data at the URL to a callback.
> ```DataMan.URL.prototype.getBuffer = function dataManUrlGetBuffer(callback) { ...``` [server/data-man-url.js:24](server/data-man-url.js#L24)
-
### <a name="DataMan.URL.prototype.getDataUri"></a>*datamanUrl*.getDataUri(callback)&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method is private*
*This method __getDataUri__ is defined in `prototype` of `DataMan.URL`*
__Arguments__
* __callback__ *{function}*
callback(err, dataUri)
Passes a data URI representing the data at the URL to a callback.
> ```DataMan.URL.prototype.getDataUri = function dataManUrlGetDataUri(callback) { ...``` [server/data-man-url.js:57](server/data-man-url.js#L57)
-
### <a name="DataMan.URL.prototype.createReadStream"></a>*datamanUrl*.createReadStream()&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method is private*
*This method __createReadStream__ is defined in `prototype` of `DataMan.URL`*
Returns a read stream for the data.
> ```DataMan.URL.prototype.createReadStream = function dataManUrlCreateReadStream() { ...``` [server/data-man-url.js:85](server/data-man-url.js#L85)
-
### <a name="DataMan.URL.prototype.size"></a>*datamanUrl*.size(callback)&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method is private*
*This method __size__ is defined in `prototype` of `DataMan.URL`*
__Arguments__
* __callback__ *{function}*
callback(err, size)
Returns the size in bytes of the data at the URL.
> ```DataMan.URL.prototype.size = function dataManUrlSize(callback) { ...``` [server/data-man-url.js:97](server/data-man-url.js#L97)
-
### <a name="DataMan.URL.prototype.type"></a>*datamanUrl*.type()&nbsp;&nbsp;<sub><i>Server</i></sub> ###
*This method is private*
*This method __type__ is defined in `prototype` of `DataMan.URL`*
Returns the type of the data.
> ```DataMan.URL.prototype.type = function dataManUrlType() { ...``` [server/data-man-url.js:121](server/data-man-url.js#L121)

View file

@ -0,0 +1,48 @@
Package.describe({
name: 'wekan-cfs-data-man',
version: '0.0.6',
summary: 'A data manager, allowing you to attach various types of data and get it back in various other types',
git: 'https://github.com/zcfs/Meteor-data-man.git'
});
Npm.depends({
mime: "1.2.11",
'buffer-stream-reader': "0.1.1",
//request: "2.44.0",
// We use a specific commit from a fork of "request" package for now; we need fix for
// https://github.com/mikeal/request/issues/887 (https://github.com/zcfs/Meteor-CollectionFS/issues/347)
request: "https://github.com/wekan/request",
temp: "0.7.0" // for tests only
});
Package.onUse(function(api) {
api.versionsFrom('1.0');
api.use(['ejson']);
api.use(['wekan-cfs-filesaver@0.0.6'], {weak: true});
api.export('DataMan');
api.addFiles([
'client/Blob.js', //polyfill for browsers without Blob constructor; currently necessary for phantomjs support, too
'client/data-man-api.js'
], 'client');
api.addFiles([
'server/data-man-api.js',
'server/data-man-buffer.js',
'server/data-man-datauri.js',
'server/data-man-filepath.js',
'server/data-man-url.js',
'server/data-man-readstream.js'
], 'server');
});
Package.onTest(function (api) {
api.use(['wekan-cfs-data-man', 'http', 'tinytest', 'test-helpers', 'wekan-cfs-http-methods@0.0.29']);
api.addFiles(['tests/common.js', 'tests/client-tests.js'], 'client');
api.addFiles(['tests/common.js', 'tests/server-tests.js'], 'server');
});

View file

@ -0,0 +1,176 @@
/* global DataMan:true, Buffer */
var fs = Npm.require("fs");
var Readable = Npm.require('stream').Readable;
/**
* @method DataMan
* @public
* @constructor
* @param {Buffer|ArrayBuffer|Uint8Array|String} data The data that you want to manipulate.
* @param {String} [type] The data content (MIME) type, if known. Required if the first argument is a Buffer, ArrayBuffer, Uint8Array, or URL
* @param {Object} [options] Currently used only to pass options for the GET request when `data` is a URL.
*/
DataMan = function DataMan(data, type, options) {
var self = this, buffer;
if (!data) {
throw new Error("DataMan constructor requires a data argument");
}
// The end result of all this is that we will have this.source set to a correct
// data type handler. We are simply detecting what the data arg is.
//
// Unless we already have in-memory data, we don't load anything into memory
// and instead rely on obtaining a read stream when the time comes.
if (typeof Buffer !== "undefined" && data instanceof Buffer) {
if (!type) {
throw new Error("DataMan constructor requires a type argument when passed a Buffer");
}
self.source = new DataMan.Buffer(data, type);
} else if (typeof ArrayBuffer !== "undefined" && data instanceof ArrayBuffer) {
if (typeof Buffer === "undefined") {
throw new Error("Buffer support required to handle an ArrayBuffer");
}
if (!type) {
throw new Error("DataMan constructor requires a type argument when passed an ArrayBuffer");
}
buffer = new Buffer(new Uint8Array(data));
self.source = new DataMan.Buffer(buffer, type);
} else if (EJSON.isBinary(data)) {
if (typeof Buffer === "undefined") {
throw new Error("Buffer support required to handle an ArrayBuffer");
}
if (!type) {
throw new Error("DataMan constructor requires a type argument when passed a Uint8Array");
}
buffer = new Buffer(data);
self.source = new DataMan.Buffer(buffer, type);
} else if (typeof Readable !== "undefined" && data instanceof Readable) {
if (!type) {
throw new Error("DataMan constructor requires a type argument when passed a stream.Readable");
}
self.source = new DataMan.ReadStream(data, type);
} else if (typeof data === "string") {
if (data.slice(0, 5) === "data:") {
self.source = new DataMan.DataURI(data);
} else if (data.slice(0, 5) === "http:" || data.slice(0, 6) === "https:") {
if (!type) {
throw new Error("DataMan constructor requires a type argument when passed a URL");
}
self.source = new DataMan.URL(data, type, options);
} else {
// assume it's a filepath
self.source = new DataMan.FilePath(data, type);
}
} else {
throw new Error("DataMan constructor received data that it doesn't support");
}
};
/**
* @method DataMan.prototype.getBuffer
* @public
* @param {function} [callback] callback(err, buffer)
* @returns {Buffer|undefined}
*
* Returns a Buffer representing this data, or passes the Buffer to a callback.
*/
DataMan.prototype.getBuffer = function dataManGetBuffer(callback) {
var self = this;
return callback ? self.source.getBuffer(callback) : Meteor.wrapAsync(bind(self.source.getBuffer, self.source))();
};
function _saveToFile(readStream, filePath, callback) {
var writeStream = fs.createWriteStream(filePath);
writeStream.on('close', Meteor.bindEnvironment(function () {
callback();
}, function (error) { callback(error); }));
writeStream.on('error', Meteor.bindEnvironment(function (error) {
callback(error);
}, function (error) { callback(error); }));
readStream.pipe(writeStream);
}
/**
* @method DataMan.prototype.saveToFile
* @public
* @param {String} filePath
* @param {Function} callback
* @returns {undefined}
*
* Saves this data to a filepath on the local filesystem.
*/
DataMan.prototype.saveToFile = function dataManSaveToFile(filePath, callback) {
var readStream = this.createReadStream();
return callback ? _saveToFile(readStream, filePath, callback) : Meteor.wrapAsync(_saveToFile)(readStream, filePath);
};
/**
* @method DataMan.prototype.getDataUri
* @public
* @param {function} [callback] callback(err, dataUri)
*
* If no callback, returns the data URI.
*/
DataMan.prototype.getDataUri = function dataManGetDataUri(callback) {
var self = this;
return callback ? self.source.getDataUri(callback) : Meteor.wrapAsync(bind(self.source.getDataUri, self.source))();
};
/**
* @method DataMan.prototype.createReadStream
* @public
*
* Returns a read stream for the data.
*/
DataMan.prototype.createReadStream = function dataManCreateReadStream() {
return this.source.createReadStream();
};
/**
* @method DataMan.prototype.size
* @public
* @param {function} [callback] callback(err, size)
*
* If no callback, returns the size in bytes of the data.
*/
DataMan.prototype.size = function dataManSize(callback) {
var self = this;
return callback ? self.source.size(callback) : Meteor.wrapAsync(bind(self.source.size, self.source))();
};
/**
* @method DataMan.prototype.type
* @public
*
* Returns the type of the data.
*/
DataMan.prototype.type = function dataManType() {
return this.source.type();
};
/*
* "bind" shim; from underscorejs, but we avoid a dependency
*/
var slice = Array.prototype.slice;
var nativeBind = Function.prototype.bind;
var ctor = function(){};
function isFunction(obj) {
return Object.prototype.toString.call(obj) == '[object Function]';
}
function bind(func, context) {
var args, bound;
if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
if (!isFunction(func)) throw new TypeError;
args = slice.call(arguments, 2);
return bound = function() {
if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
ctor.prototype = func.prototype;
var self = new ctor;
ctor.prototype = null;
var result = func.apply(self, args.concat(slice.call(arguments)));
if (Object(result) === result) return result;
return self;
};
}

View file

@ -0,0 +1,82 @@
var bufferStreamReader = Npm.require('buffer-stream-reader');
/**
* @method DataMan.Buffer
* @public
* @constructor
* @param {Buffer} buffer
* @param {String} type The data content (MIME) type.
*/
DataMan.Buffer = function DataManBuffer(buffer, type) {
var self = this;
self.buffer = buffer;
self._type = type;
};
/**
* @method DataMan.Buffer.prototype.getBuffer
* @private
* @param {function} callback callback(err, buffer)
* @returns {Buffer|undefined}
*
* Passes a Buffer representing the data to a callback.
*/
DataMan.Buffer.prototype.getBuffer = function dataManBufferGetBuffer(callback) {
callback(null, this.buffer);
};
/**
* @method DataMan.Buffer.prototype.getDataUri
* @private
* @param {function} callback callback(err, dataUri)
*
* Passes a data URI representing the data in the buffer to a callback.
*/
DataMan.Buffer.prototype.getDataUri = function dataManBufferGetDataUri(callback) {
var self = this;
if (!self._type) {
callback(new Error("DataMan.getDataUri couldn't get a contentType"));
} else {
var dataUri = "data:" + self._type + ";base64," + self.buffer.toString("base64");
callback(null, dataUri);
}
};
/**
* @method DataMan.Buffer.prototype.createReadStream
* @private
*
* Returns a read stream for the data.
*/
DataMan.Buffer.prototype.createReadStream = function dataManBufferCreateReadStream() {
return new bufferStreamReader(this.buffer);
};
/**
* @method DataMan.Buffer.prototype.size
* @param {function} callback callback(err, size)
* @private
*
* Passes the size in bytes of the data in the buffer to a callback.
*/
DataMan.Buffer.prototype.size = function dataManBufferSize(callback) {
var self = this;
if (typeof self._size === "number") {
callback(null, self._size);
return;
}
self._size = self.buffer.length;
callback(null, self._size);
};
/**
* @method DataMan.Buffer.prototype.type
* @private
*
* Returns the type of the data.
*/
DataMan.Buffer.prototype.type = function dataManBufferType() {
return this._type;
};

View file

@ -0,0 +1,14 @@
/**
* @method DataMan.DataURI
* @public
* @constructor
* @param {String} dataUri
*/
DataMan.DataURI = function DataManDataURI(dataUri) {
var self = this;
var pieces = dataUri.match(/^data:(.*);base64,(.*)$/);
var buffer = new Buffer(pieces[2], 'base64');
return new DataMan.Buffer(buffer, pieces[1]);
};
DataMan.DataURI.prototype = DataMan.Buffer.prototype;

View file

@ -0,0 +1,108 @@
var mime = Npm.require('mime');
var fs = Npm.require("fs");
/**
* @method DataMan.FilePath
* @public
* @constructor
* @param {String} filepath
* @param {String} [type] The data content (MIME) type. Will lookup from file if not passed.
*/
DataMan.FilePath = function DataManFilePath(filepath, type) {
var self = this;
self.filepath = filepath;
self._type = type || mime.lookup(filepath);
};
/**
* @method DataMan.FilePath.prototype.getBuffer
* @private
* @param {function} callback callback(err, buffer)
* @returns {Buffer|undefined}
*
* Passes a Buffer representing the data to a callback.
*/
DataMan.FilePath.prototype.getBuffer = function dataManFilePathGetBuffer(callback) {
var self = this;
// Call node readFile
fs.readFile(self.filepath, Meteor.bindEnvironment(function(err, buffer) {
callback(err, buffer);
}, function(err) {
callback(err);
}));
};
/**
* @method DataMan.FilePath.prototype.getDataUri
* @private
* @param {function} callback callback(err, dataUri)
*
* Passes a data URI representing the data to a callback.
*/
DataMan.FilePath.prototype.getDataUri = function dataManFilePathGetDataUri(callback) {
var self = this;
self.getBuffer(function (error, buffer) {
if (error) {
callback(error);
} else {
if (!self._type) {
callback(new Error("DataMan.getDataUri couldn't get a contentType"));
} else {
var dataUri = "data:" + self._type + ";base64," + buffer.toString("base64");
buffer = null;
callback(null, dataUri);
}
}
});
};
/**
* @method DataMan.FilePath.prototype.createReadStream
* @private
*
* Returns a read stream for the data.
*/
DataMan.FilePath.prototype.createReadStream = function dataManFilePathCreateReadStream() {
// Stream from filesystem
return fs.createReadStream(this.filepath);
};
/**
* @method DataMan.FilePath.prototype.size
* @param {function} callback callback(err, size)
* @private
*
* Passes the size in bytes of the data to a callback.
*/
DataMan.FilePath.prototype.size = function dataManFilePathSize(callback) {
var self = this;
if (typeof self._size === "number") {
callback(null, self._size);
return;
}
// We can get the size without buffering
fs.stat(self.filepath, Meteor.bindEnvironment(function (error, stats) {
if (stats && typeof stats.size === "number") {
self._size = stats.size;
callback(null, self._size);
} else {
callback(error);
}
}, function (error) {
callback(error);
}));
};
/**
* @method DataMan.FilePath.prototype.type
* @private
*
* Returns the type of the data.
*/
DataMan.FilePath.prototype.type = function dataManFilePathType() {
return this._type;
};

View file

@ -0,0 +1,80 @@
/* global DataMan */
var PassThrough = Npm.require('stream').PassThrough;
/**
* @method DataMan.ReadStream
* @public
* @constructor
* @param {ReadStream} stream
* @param {String} type The data content (MIME) type.
*/
DataMan.ReadStream = function DataManBuffer(stream, type) {
var self = this;
// Create a bufferable / paused new stream...
var pt = new PassThrough();
// Pipe provided read stream into pass-through stream
stream.pipe(pt);
// Set pass-through stream reference
self.stream = pt;
// Set type as provided
self._type = type;
};
/**
* @method DataMan.ReadStream.prototype.getBuffer
* @private
* @param {function} callback callback(err, buffer)
* @returns {undefined}
*
* Passes a Buffer representing the data to a callback.
*/
DataMan.ReadStream.prototype.getBuffer = function dataManReadStreamGetBuffer(/*callback*/) {
// TODO implement as passthrough stream?
};
/**
* @method DataMan.ReadStream.prototype.getDataUri
* @private
* @param {function} callback callback(err, dataUri)
*
* Passes a data URI representing the data in the stream to a callback.
*/
DataMan.ReadStream.prototype.getDataUri = function dataManReadStreamGetDataUri(/*callback*/) {
// TODO implement as passthrough stream?
};
/**
* @method DataMan.ReadStream.prototype.createReadStream
* @private
*
* Returns a read stream for the data.
*/
DataMan.ReadStream.prototype.createReadStream = function dataManReadStreamCreateReadStream() {
return this.stream;
};
/**
* @method DataMan.ReadStream.prototype.size
* @param {function} callback callback(err, size)
* @private
*
* Passes the size in bytes of the data in the stream to a callback.
*/
DataMan.ReadStream.prototype.size = function dataManReadStreamSize(callback) {
callback(0); // will determine from stream later
};
/**
* @method DataMan.ReadStream.prototype.type
* @private
*
* Returns the type of the data.
*/
DataMan.ReadStream.prototype.type = function dataManReadStreamType() {
return this._type;
};

View file

@ -0,0 +1,133 @@
var request = Npm.require("request");
/**
* @method DataMan.URL
* @public
* @constructor
* @param {String} url
* @param {String} type The data content (MIME) type.
*/
DataMan.URL = function DataManURL(url, type, options) {
var self = this;
options = options || {};
self.url = url;
self._type = type;
// This is some code borrowed from the http package. Hopefully
// we can eventually use HTTP pkg directly instead of 'request'
// once it supports streams and buffers and such. (`request` takes
// and `auth` option, too, but not of the same form as `HTTP`.)
if (options.auth) {
if (options.auth.indexOf(':') < 0)
throw new Error('auth option should be of the form "username:password"');
options.headers = options.headers || {};
options.headers['Authorization'] = "Basic "+
(new Buffer(options.auth, "ascii")).toString("base64");
delete options.auth;
}
self.urlOpts = options;
};
/**
* @method DataMan.URL.prototype.getBuffer
* @private
* @param {function} callback callback(err, buffer)
* @returns {Buffer|undefined}
*
* Passes a Buffer representing the data at the URL to a callback.
*/
DataMan.URL.prototype.getBuffer = function dataManUrlGetBuffer(callback) {
var self = this;
request(_.extend({
url: self.url,
method: "GET",
encoding: null,
jar: false
}, self.urlOpts), Meteor.bindEnvironment(function(err, res, body) {
if (err) {
callback(err);
} else {
self._type = res.headers['content-type'];
callback(null, body);
}
}, function(err) {
callback(err);
}));
};
/**
* @method DataMan.URL.prototype.getDataUri
* @private
* @param {function} callback callback(err, dataUri)
*
* Passes a data URI representing the data at the URL to a callback.
*/
DataMan.URL.prototype.getDataUri = function dataManUrlGetDataUri(callback) {
var self = this;
self.getBuffer(function (error, buffer) {
if (error) {
callback(error);
} else {
if (!self._type) {
callback(new Error("DataMan.getDataUri couldn't get a contentType"));
} else {
var dataUri = "data:" + self._type + ";base64," + buffer.toString("base64");
callback(null, dataUri);
}
}
});
};
/**
* @method DataMan.URL.prototype.createReadStream
* @private
*
* Returns a read stream for the data.
*/
DataMan.URL.prototype.createReadStream = function dataManUrlCreateReadStream() {
var self = this;
// Stream from URL
return request(_.extend({
url: self.url,
method: "GET"
}, self.urlOpts));
};
/**
* @method DataMan.URL.prototype.size
* @param {function} callback callback(err, size)
* @private
*
* Returns the size in bytes of the data at the URL.
*/
DataMan.URL.prototype.size = function dataManUrlSize(callback) {
var self = this;
if (typeof self._size === "number") {
callback(null, self._size);
return;
}
self.getBuffer(function (error, buffer) {
if (error) {
callback(error);
} else {
self._size = buffer.length;
callback(null, self._size);
}
});
};
/**
* @method DataMan.URL.prototype.type
* @private
*
* Returns the type of the data.
*/
DataMan.URL.prototype.type = function dataManUrlType() {
return this._type;
};

View file

@ -0,0 +1,296 @@
var blobData;
var arrayBufferData;
var binaryData;
var dataUriData;
var urlData;
// Init with Blob
Tinytest.addAsync('cfs-data - client - Init with Blob', function(test, onComplete) {
var blob = new Blob(['Hello World'], {type : 'text/plain'});
blobData = new DataMan(blob);
test.instanceOf(blobData.blob, Blob);
test.equal(blobData.type(), "text/plain");
onComplete();
});
// Init with ArrayBuffer
Tinytest.addAsync('cfs-data - client - Init with ArrayBuffer', function(test, onComplete) {
arrayBufferData = new DataMan(str2ab('Hello World'), "text/plain");
// Should be converted upon init to a Blob
test.instanceOf(arrayBufferData.blob, Blob);
test.equal(arrayBufferData.type(), "text/plain");
onComplete();
});
// Init with Binary
Tinytest.addAsync('cfs-data - client - Init with Binary', function(test, onComplete) {
binaryData = new DataMan(new Uint8Array(str2ab('Hello World')), "text/plain");
// Should be converted upon init to a Blob
test.instanceOf(arrayBufferData.blob, Blob);
test.equal(binaryData.type(), "text/plain");
onComplete();
});
// Init with data URI string
Tinytest.addAsync('cfs-data - client - Init with data URI string', function(test, onComplete) {
var dataUri = 'data:text/plain;base64,SGVsbG8gV29ybGQ='; //'Hello World'
dataUriData = new DataMan(dataUri);
// Should be converted upon init to a Blob
test.instanceOf(dataUriData.blob, Blob);
test.equal(dataUriData.type(), "text/plain"); //should be extracted from data URI
onComplete();
});
// Init with URL string
Tinytest.addAsync('cfs-data - client - Init with URL string', function(test, onComplete) {
urlData = new DataMan(Meteor.absoluteUrl('test'), "text/plain"); //'Hello World'
// URLs are not converted to Blobs upon init
test.equal(urlData.url, Meteor.absoluteUrl('test'));
test.equal(urlData.type(), "text/plain");
onComplete();
});
// getBlob
Tinytest.addAsync('cfs-data - client - getBlob', function(test, onComplete) {
var total = 10, done = 0;
function continueIfDone() {
done++;
if (total === done) {
onComplete();
}
}
function testBlob(error, blob, testType) {
test.isFalse(!!error, testType + ' got error: ' + (error && error.message));
test.instanceOf(blob, Blob, testType + ' got no blob');
if (blob instanceof Blob) {
var reader = new FileReader();
reader.addEventListener("load", function(event) {
test.equal(reader.result, 'Hello World', testType + ' got back blob with incorrect data');
continueIfDone();
}, false);
reader.addEventListener("error", function(err) {
test.equal(reader.error, null, testType + ' error reading blob as text');
continueIfDone();
}, false);
reader.readAsText(blob, 'utf-8');
} else {
continueIfDone();
}
}
// from Blob
blobData.getBlob(function (error, blob) {
testBlob(error, blob, 'getBlob from Blob');
});
// from Blob (no callback)
testBlob(false, blobData.getBlob(), 'getBlob from Blob');
// from ArrayBuffer
arrayBufferData.getBlob(function (error, blob) {
testBlob(error, blob, 'getBlob from ArrayBuffer');
});
// from ArrayBuffer (no callback)
testBlob(false, arrayBufferData.getBlob(), 'getBlob from ArrayBuffer');
// from binary
binaryData.getBlob(function (error, blob) {
testBlob(error, blob, 'getBlob from binary');
});
// from binary (no callback)
testBlob(false, binaryData.getBlob(), 'getBlob from binary');
// from data URI
dataUriData.getBlob(function (error, blob) {
testBlob(error, blob, 'getBlob from data URI');
});
// from data URI (no callback)
testBlob(false, dataUriData.getBlob(), 'getBlob from data URI');
// from URL
urlData.getBlob(function (error, blob) {
testBlob(error, blob, 'getBlob from URL');
});
// from URL (no callback)
test.throws(function () {
// callback is required for URLs on the client
urlData.getBlob();
});
continueIfDone();
});
// getBinary
Tinytest.addAsync('cfs-data - client - getBinary', function(test, onComplete) {
var total = 5, done = 0;
function continueIfDone() {
done++;
if (total === done) {
onComplete();
}
}
function testBinary(error, binary, testType) {
test.isFalse(!!error, testType + ' got error: ' + (error && error.message));
test.isTrue(EJSON.isBinary(binary), testType + ' got no binary');
if (EJSON.isBinary(binary)) {
test.equal(bin2str(binary), 'Hello World', testType + ' got back binary with incorrect data');
continueIfDone();
} else {
continueIfDone();
}
}
// from Blob
blobData.getBinary(function (error, binary) {
testBinary(error, binary, 'getBinary from Blob');
});
// from ArrayBuffer
arrayBufferData.getBinary(function (error, binary) {
testBinary(error, binary, 'getBinary from ArrayBuffer');
});
// from binary
binaryData.getBinary(function (error, binary) {
testBinary(error, binary, 'getBinary from binary');
});
// from data URI
dataUriData.getBinary(function (error, binary) {
testBinary(error, binary, 'getBinary from data URI');
});
// from URL
urlData.getBinary(function (error, binary) {
testBinary(error, binary, 'getBinary from URL');
});
});
// getDataUri
Tinytest.addAsync('cfs-data - client - getDataUri', function(test, onComplete) {
var total = 5, done = 0;
function testURI(error, uri, testType) {
test.isFalse(!!error, testType + ' got error: ' + (error && error.message));
test.equal(typeof uri, "string", testType + ' got no URI string');
test.equal(uri, 'data:text/plain;base64,SGVsbG8gV29ybGQ=', testType + ' got invalid URI');
done++;
if (total === done) {
onComplete();
}
}
// from Blob
blobData.getDataUri(function (error, uri) {
testURI(error, uri, 'getDataUri from Blob');
});
// from ArrayBuffer
arrayBufferData.getDataUri(function (error, uri) {
testURI(error, uri, 'getDataUri from ArrayBuffer');
});
// from binary
binaryData.getDataUri(function (error, uri) {
testURI(error, uri, 'getDataUri from binary');
});
// from data URI
dataUriData.getDataUri(function (error, uri) {
testURI(error, uri, 'getDataUri from data URI');
});
// from URL
urlData.getDataUri(function (error, uri) {
testURI(error, uri, 'getDataUri from URL');
});
});
// size
Tinytest.addAsync('cfs-data - client - size', function(test, onComplete) {
var total = 10, done = 0;
function continueIfDone() {
done++;
if (total === done) {
onComplete();
}
}
function testSize(error, size, testType) {
test.isFalse(!!error, testType + ' got error: ' + (error && error.message));
test.equal(size, 11, testType + ' got wrong size');
continueIfDone();
}
// from Blob
blobData.size(function (error, size) {
testSize(error, size, 'size from Blob');
});
// from Blob (no callback)
testSize(false, blobData.size(), 'size from Blob');
// from ArrayBuffer
arrayBufferData.size(function (error, size) {
testSize(error, size, 'size from ArrayBuffer');
});
// from ArrayBuffer (no callback)
testSize(false, arrayBufferData.size(), 'size from ArrayBuffer');
// from binary
binaryData.size(function (error, size) {
testSize(error, size, 'size from binary');
});
// from binary (no callback)
testSize(false, binaryData.size(), 'size from binary');
// from data URI
dataUriData.size(function (error, size) {
testSize(error, size, 'size from data URI');
});
// from data URI (no callback)
testSize(false, dataUriData.size(), 'size from data URI');
// from URL
urlData.size(function (error, size) {
testSize(error, size, 'size from URL');
});
// from URL (no callback)
test.throws(function () {
// callback is required for URLs on the client
urlData.size();
});
continueIfDone();
});
//Test API:
//test.isFalse(v, msg)
//test.isTrue(v, msg)
//test.equalactual, expected, message, not
//test.length(obj, len)
//test.include(s, v)
//test.isNaN(v, msg)
//test.isUndefined(v, msg)
//test.isNotNull
//test.isNull
//test.throws(func)
//test.instanceOf(obj, klass)
//test.notEqual(actual, expected, message)
//test.runId()
//test.exception(exception)
//test.expect_fail()
//test.ok(doc)
//test.fail(doc)
//test.equal(a, b, msg)

View file

@ -0,0 +1,38 @@
// ab2str = function ab2str(buf) {
// return String.fromCharCode(new Uint8Array(buf));
// }
bin2str = function bin2str(bufView) {
var length = bufView.length;
var result = '';
for (var i = 0; i<length; i+=65535) {
var addition = 65535;
if(i + 65535 > length) {
addition = length - i;
}
try {
// this fails on phantomjs due to old webkit bug; hence the try/catch
result += String.fromCharCode.apply(null, bufView.subarray(i,i+addition));
} catch (e) {
var dataArray = [];
for (var j = i; j < i+addition; j++) {
dataArray.push(bufView[j]);
}
result += String.fromCharCode.apply(null, dataArray);
}
}
return result;
};
ab2str = function ab2str(buffer) {
return bin2str(new Uint8Array(buffer));
};
str2ab = function str2ab(str) {
var buf = new ArrayBuffer(str.length);
var bufView = new Uint8Array(buf);
for (var i=0, strLen=str.length; i<strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
};

View file

@ -0,0 +1,366 @@
var fs = Npm.require('fs');
var temp = Npm.require('temp');
// Automatically track and cleanup files at exit
temp.track();
// Set up HTTP method URL used by client tests
HTTP.methods({
'test': {
get: function () {
var buf = new Buffer('Hello World');
this.setContentType('text/plain');
return buf;
},
head: function () {
var buf = new Buffer('Hello World');
this.setContentType('text/plain');
this.addHeader('Content-Length', buf.length);
buf = null;
}
}
});
// Save temp file for testing with
function openTempFile(name, callback) {
return temp.open(name, callback);
}
var openTempFileSync = Meteor.wrapAsync(openTempFile);
var info = openTempFileSync(null);
var tempFilePath = info.path;
fs.writeSync(info.fd, 'Hello World');
fs.closeSync(info.fd);
var bufferData;
var arrayBufferData;
var binaryData;
var dataUriData;
var urlData;
var filePathData;
var streamData;
// Init with Buffer
Tinytest.addAsync('cfs-data - server - Init with Buffer', function(test, onComplete) {
bufferData = new DataMan(new Buffer('Hello World'), "text/plain");
test.instanceOf(bufferData.source, DataMan.Buffer);
test.equal(bufferData.type(), "text/plain");
onComplete();
});
// Init with ArrayBuffer
Tinytest.addAsync('cfs-data - server - Init with ArrayBuffer', function(test, onComplete) {
arrayBufferData = new DataMan(str2ab('Hello World'), "text/plain");
// Should be converted upon init to a Buffer
test.instanceOf(arrayBufferData.source, DataMan.Buffer);
test.equal(arrayBufferData.type(), "text/plain");
onComplete();
});
// Init with Binary
Tinytest.addAsync('cfs-data - server - Init with Binary', function(test, onComplete) {
binaryData = new DataMan(new Uint8Array(str2ab('Hello World')), "text/plain");
// Should be converted upon init to a Buffer
test.instanceOf(arrayBufferData.source, DataMan.Buffer);
test.equal(binaryData.type(), "text/plain");
onComplete();
});
// Init with data URI string
Tinytest.addAsync('cfs-data - server - Init with data URI string', function(test, onComplete) {
var dataUri = 'data:text/plain;base64,SGVsbG8gV29ybGQ='; //'Hello World'
dataUriData = new DataMan(dataUri);
// Data URIs are not converted to Buffers upon init
test.instanceOf(dataUriData.source, DataMan.DataURI);
test.equal(dataUriData.type(), "text/plain"); //should be extracted from data URI
onComplete();
});
// Init with URL string
Tinytest.addAsync('cfs-data - server - Init with URL string', function(test, onComplete) {
var url = Meteor.absoluteUrl('test');
urlData = new DataMan(url, "text/plain"); //'Hello World'
// URLs are not converted to Buffers upon init
test.instanceOf(urlData.source, DataMan.URL);
test.equal(urlData.type(), "text/plain");
onComplete();
});
// Init with filepath string
Tinytest.addAsync('cfs-data - server - Init with filepath string', function(test, onComplete) {
filePathData = new DataMan(tempFilePath, "text/plain");
// filepaths are not converted to Buffers upon init
test.instanceOf(filePathData.source, DataMan.FilePath);
test.equal(filePathData.type(), "text/plain");
onComplete();
});
// Init with readable stream
Tinytest.addAsync('cfs-data - server - Init with readable stream', function(test, onComplete) {
streamData = new DataMan(fs.createReadStream(tempFilePath), "text/plain");
// filepaths are not converted to Buffers upon init
test.instanceOf(streamData.source, DataMan.ReadStream);
test.equal(streamData.type(), "text/plain");
onComplete();
});
// getBuffer
Tinytest.addAsync('cfs-data - server - getBuffer', function(test, onComplete) {
var total = 12, done = 0;
function testBuffer(error, buffer, testType) {
test.isFalse(!!error, testType + ' got error: ' + (error && error.message));
test.instanceOf(buffer, Buffer);
if (buffer instanceof Buffer) {
test.equal(buffer.toString(), 'Hello World', testType + ' got back buffer with incorrect data');
}
done++;
if (total === done) {
onComplete();
}
}
// from Buffer (async)
bufferData.getBuffer(function (error, buffer) {
testBuffer(error, buffer, 'getBuffer from Buffer async');
});
// from Buffer (sync)
testBuffer(null, bufferData.getBuffer(), 'getBuffer from Buffer sync');
// from ArrayBuffer (async)
arrayBufferData.getBuffer(function (error, buffer) {
testBuffer(error, buffer, 'getBuffer from ArrayBuffer async');
});
// from ArrayBuffer (sync)
testBuffer(null, arrayBufferData.getBuffer(), 'getBuffer from ArrayBuffer sync');
// from binary (async)
binaryData.getBuffer(function (error, buffer) {
testBuffer(error, buffer, 'getBuffer from binary async');
});
// from binary (sync)
testBuffer(null, binaryData.getBuffer(), 'getBuffer from binary sync');
// from data URI (async)
dataUriData.getBuffer(function (error, buffer) {
testBuffer(error, buffer, 'getBuffer from data URI async');
});
// from data URI (sync)
testBuffer(null, dataUriData.getBuffer(), 'getBuffer from data URI sync');
// from URL (async)
urlData.getBuffer(function (error, buffer) {
testBuffer(error, buffer, 'getBuffer from URL async');
});
// from URL (sync)
testBuffer(null, urlData.getBuffer(), 'getBuffer from URL sync');
// from filepath (async)
filePathData.getBuffer(function (error, buffer) {
testBuffer(error, buffer, 'getBuffer filepath async');
});
// from filepath (sync)
testBuffer(null, filePathData.getBuffer(), 'getBuffer filepath sync');
});
// getDataUri
Tinytest.addAsync('cfs-data - server - getDataUri', function(test, onComplete) {
var total = 12, done = 0;
function testURI(error, uri, testType) {
test.isFalse(!!error, testType + ' got error: ' + (error && error.message));
test.equal(typeof uri, "string", testType + ' got no URI string');
test.equal(uri, 'data:text/plain;base64,SGVsbG8gV29ybGQ=', testType + ' got invalid URI');
done++;
if (total === done) {
onComplete();
}
}
// from Buffer (async)
bufferData.getDataUri(function (error, uri) {
testURI(error, uri, 'getDataUri from Buffer async');
});
// from Buffer (sync)
testURI(null, bufferData.getDataUri(), 'getDataUri from Buffer sync');
// from ArrayBuffer (async)
arrayBufferData.getDataUri(function (error, uri) {
testURI(error, uri, 'getDataUri from ArrayBuffer async');
});
// from ArrayBuffer (sync)
testURI(null, arrayBufferData.getDataUri(), 'getDataUri from ArrayBuffer sync');
// from binary (async)
binaryData.getDataUri(function (error, uri) {
testURI(error, uri, 'getDataUri from binary async');
});
// from binary (sync)
testURI(null, binaryData.getDataUri(), 'getDataUri from binary sync');
// from data URI (async)
dataUriData.getDataUri(function (error, uri) {
testURI(error, uri, 'getDataUri from data URI async');
});
// from data URI (sync)
testURI(null, dataUriData.getDataUri(), 'getDataUri from data URI sync');
// from URL (async)
urlData.getDataUri(function (error, uri) {
testURI(error, uri, 'getDataUri from URL async');
});
// from URL (sync)
testURI(null, urlData.getDataUri(), 'getDataUri from URL sync');
// from filepath (async)
filePathData.getDataUri(function (error, uri) {
testURI(error, uri, 'getDataUri filepath async');
});
// from filepath (sync)
testURI(null, filePathData.getDataUri(), 'getDataUri filepath sync');
});
// size
Tinytest.addAsync('cfs-data - server - size', function(test, onComplete) {
var total = 6, done = 0;
function testSize(size, testType) {
test.equal(size, 11, testType + ' got wrong size');
done++;
if (total === done) {
onComplete();
}
}
// from Buffer
testSize(bufferData.size(), 'size from Buffer');
// from ArrayBuffer
testSize(arrayBufferData.size(), 'size from ArrayBuffer');
// from binary
testSize(binaryData.size(), 'size from binary');
// from data URI
testSize(dataUriData.size(), 'size from data URI');
// from URL
testSize(urlData.size(), 'size from URL');
// from filepath
testSize(filePathData.size(), 'size from filepath');
});
// saveToFile
// Since saveToFile uses createReadStream, this tests that function also
Tinytest.addAsync('cfs-data - server - saveToFile', function(test, onComplete) {
var total = 12, done = 0;
function testSave(dataInstance) {
var tempName = temp.path({suffix: '.txt'});
dataInstance.saveToFile(tempName, function (error) {
test.isFalse(!!error);
test.equal(fs.readFileSync(tempName, {encoding: 'utf8'}), 'Hello World', 'file was not saved with correct data');
done++;
if (total === done) {
onComplete();
}
});
}
function testSaveSync(dataInstance) {
var tempName = temp.path({suffix: '.txt'});
dataInstance.saveToFile(tempName);
test.equal(fs.readFileSync(tempName, {encoding: 'utf8'}), 'Hello World', 'file was not saved with correct data');
done++;
if (total === done) {
onComplete();
}
}
// from Buffer
testSave(bufferData);
testSaveSync(bufferData);
// from ArrayBuffer
testSave(arrayBufferData);
testSaveSync(arrayBufferData);
// from binary
testSave(binaryData);
testSaveSync(binaryData);
// from data URI
testSave(dataUriData);
testSaveSync(dataUriData);
// from URL
testSave(urlData);
testSaveSync(urlData);
// from filepath
testSave(filePathData);
testSaveSync(filePathData);
});
// Ensure that URL createReadStream can be piped after delay
// https://github.com/mikeal/request/issues/887
Tinytest.addAsync('cfs-data - server - createReadStream delay', function(test, onComplete) {
var readStream = urlData.createReadStream();
// wait for 5 seconds, then pipe
Meteor.setTimeout(function() {
var tempName = temp.path({suffix: '.txt'});
try {
var writeStream = readStream.pipe(fs.createWriteStream(tempName));
writeStream.on('finish', Meteor.bindEnvironment(function() {
test.equal(fs.readFileSync(tempName, {encoding: 'utf8'}), 'Hello World', 'file was not saved with correct data');
onComplete();
}));
writeStream.on('error', Meteor.bindEnvironment(function(err) {
test.isFalse(!!err);
}));
} catch (err) {
test.isFalse(!!err);
onComplete();
}
}, 5000);
});
//Test API:
//test.isFalse(v, msg)
//test.isTrue(v, msg)
//test.equalactual, expected, message, not
//test.length(obj, len)
//test.include(s, v)
//test.isNaN(v, msg)
//test.isUndefined(v, msg)
//test.isNotNull
//test.isNull
//test.throws(func)
//test.instanceOf(obj, klass)
//test.notEqual(actual, expected, message)
//test.runId()
//test.exception(exception)
//test.expect_fail()
//test.ok(doc)
//test.fail(doc)
//test.equal(a, b, msg)