mirror of
https://github.com/wekan/wekan.git
synced 2025-12-23 02:40:14 +01:00
Fixed Non-ASCII attachment filename will crash when downloading.
Thanks to xet7 ! Fixes #2759
This commit is contained in:
parent
843ff8eaaa
commit
c2da477735
277 changed files with 30568 additions and 52 deletions
5
packages/wekan-cfs-data-man/.travis.yml
Normal file
5
packages/wekan-cfs-data-man/.travis.yml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- "0.10"
|
||||
before_install:
|
||||
- "curl -L http://git.io/s0Zu-w | /bin/sh"
|
||||
20
packages/wekan-cfs-data-man/LICENSE.md
Normal file
20
packages/wekan-cfs-data-man/LICENSE.md
Normal 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.
|
||||
8
packages/wekan-cfs-data-man/README.md
Normal file
8
packages/wekan-cfs-data-man/README.md
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
wekan-cfs-data-man [](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)
|
||||
309
packages/wekan-cfs-data-man/api.md
Normal file
309
packages/wekan-cfs-data-man/api.md
Normal 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]) <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) <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) <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]) <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) <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() <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]) <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]) <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() <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]) <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() <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]) <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() <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) <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) <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]) <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) <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)
|
||||
|
||||
|
||||
166
packages/wekan-cfs-data-man/client/Blob.js
Normal file
166
packages/wekan-cfs-data-man/client/Blob.js
Normal 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));
|
||||
302
packages/wekan-cfs-data-man/client/data-man-api.js
Normal file
302
packages/wekan-cfs-data-man/client/data-man-api.js
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
674
packages/wekan-cfs-data-man/internal.api.md
Normal file
674
packages/wekan-cfs-data-man/internal.api.md
Normal 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} <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} <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]) <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) <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) <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]) <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) <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() <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) <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]) <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]) <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]) <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() <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]) <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() <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]) <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() <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) <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) <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) <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() <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) <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() <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) <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]) <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) <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) <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() <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) <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() <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) <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) <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) <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() <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) <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() <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)
|
||||
|
||||
|
||||
48
packages/wekan-cfs-data-man/package.js
Normal file
48
packages/wekan-cfs-data-man/package.js
Normal 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');
|
||||
});
|
||||
176
packages/wekan-cfs-data-man/server/data-man-api.js
Normal file
176
packages/wekan-cfs-data-man/server/data-man-api.js
Normal 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;
|
||||
};
|
||||
}
|
||||
82
packages/wekan-cfs-data-man/server/data-man-buffer.js
Normal file
82
packages/wekan-cfs-data-man/server/data-man-buffer.js
Normal 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;
|
||||
};
|
||||
14
packages/wekan-cfs-data-man/server/data-man-datauri.js
Normal file
14
packages/wekan-cfs-data-man/server/data-man-datauri.js
Normal 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;
|
||||
108
packages/wekan-cfs-data-man/server/data-man-filepath.js
Normal file
108
packages/wekan-cfs-data-man/server/data-man-filepath.js
Normal 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;
|
||||
};
|
||||
80
packages/wekan-cfs-data-man/server/data-man-readstream.js
Normal file
80
packages/wekan-cfs-data-man/server/data-man-readstream.js
Normal 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;
|
||||
};
|
||||
133
packages/wekan-cfs-data-man/server/data-man-url.js
Normal file
133
packages/wekan-cfs-data-man/server/data-man-url.js
Normal 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;
|
||||
};
|
||||
296
packages/wekan-cfs-data-man/tests/client-tests.js
Normal file
296
packages/wekan-cfs-data-man/tests/client-tests.js
Normal 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)
|
||||
38
packages/wekan-cfs-data-man/tests/common.js
Normal file
38
packages/wekan-cfs-data-man/tests/common.js
Normal 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;
|
||||
};
|
||||
366
packages/wekan-cfs-data-man/tests/server-tests.js
Normal file
366
packages/wekan-cfs-data-man/tests/server-tests.js
Normal 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)
|
||||
Loading…
Add table
Add a link
Reference in a new issue