| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 | 
							- /**
 
-  * Notes a details about a storage adapter failure within the file record
 
-  * @param {string} storeName
 
-  * @param {number} maxTries
 
-  * @return {undefined}
 
-  * @todo deprecate this
 
-  */
 
- FS.File.prototype.logCopyFailure = function(storeName, maxTries) {
 
-   var self = this;
 
-   // hasStored will update from the fileRecord
 
-   if (self.hasStored(storeName)) {
 
-     throw new Error("logCopyFailure: invalid storeName");
 
-   }
 
-   // Make sure we have a temporary file saved since we will be
 
-   // trying the save again.
 
-   FS.TempStore.ensureForFile(self);
 
-   var now = new Date();
 
-   var currentCount = (self.failures && self.failures.copies && self.failures.copies[storeName] && typeof self.failures.copies[storeName].count === "number") ? self.failures.copies[storeName].count : 0;
 
-   maxTries = maxTries || 5;
 
-   var modifier = {};
 
-   modifier.$set = {};
 
-   modifier.$set['failures.copies.' + storeName + '.lastAttempt'] = now;
 
-   if (currentCount === 0) {
 
-     modifier.$set['failures.copies.' + storeName + '.firstAttempt'] = now;
 
-   }
 
-   modifier.$set['failures.copies.' + storeName + '.count'] = currentCount + 1;
 
-   modifier.$set['failures.copies.' + storeName + '.doneTrying'] = (currentCount + 1 >= maxTries);
 
-   self.update(modifier);
 
- };
 
- /**
 
-  * Has this store permanently failed?
 
-  * @param {String} storeName The name of the store
 
-  * @return {boolean} Has this store failed permanently?
 
-  * @todo deprecate this
 
-  */
 
- FS.File.prototype.failedPermanently = function(storeName) {
 
-   var self = this;
 
-   return !!(self.failures &&
 
-             self.failures.copies &&
 
-             self.failures.copies[storeName] &&
 
-             self.failures.copies[storeName].doneTrying);
 
- };
 
- /**
 
-  * @method FS.File.prototype.createReadStream
 
-  * @public
 
-  * @param {String} [storeName]
 
-  * @returns {stream.Readable} Readable NodeJS stream
 
-  *
 
-  * Returns a readable stream. Where the stream reads from depends on the FS.File instance and whether you pass a store name.
 
-  *
 
-  * * If you pass a `storeName`, a readable stream for the file data saved in that store is returned.
 
-  * * If you don't pass a `storeName` and data is attached to the FS.File instance (on `data` property, which must be a DataMan instance), then a readable stream for the attached data is returned.
 
-  * * If you don't pass a `storeName` and there is no data attached to the FS.File instance, a readable stream for the file data currently in the temporary store (`FS.TempStore`) is returned.
 
-  *
 
-  */
 
- FS.File.prototype.createReadStream = function(storeName) {
 
-   var self = this;
 
-   // If we dont have a store name but got Buffer data?
 
-   if (!storeName && self.data) {
 
-     FS.debug && console.log("fileObj.createReadStream creating read stream for attached data");
 
-     // Stream from attached data if present
 
-     return self.data.createReadStream();
 
-   } else if (!storeName && FS.TempStore && FS.TempStore.exists(self)) {
 
-     FS.debug && console.log("fileObj.createReadStream creating read stream for temp store");
 
-     // Stream from temp store - its a bit slower than regular streams?
 
-     return FS.TempStore.createReadStream(self);
 
-   } else {
 
-     // Stream from the store using storage adapter
 
-     if (self.isMounted()) {
 
-       var storage = self.collection.storesLookup[storeName] || self.collection.primaryStore;
 
-       FS.debug && console.log("fileObj.createReadStream creating read stream for store", storage.name);
 
-       // return stream
 
-       return storage.adapter.createReadStream(self);
 
-     } else {
 
-       throw new Meteor.Error('File not mounted');
 
-     }
 
-   }
 
- };
 
- /**
 
-  * @method FS.File.prototype.createWriteStream
 
-  * @public
 
-  * @param {String} [storeName]
 
-  * @returns {stream.Writeable} Writeable NodeJS stream
 
-  *
 
-  * Returns a writeable stream. Where the stream writes to depends on whether you pass in a store name.
 
-  *
 
-  * * If you pass a `storeName`, a writeable stream for (over)writing the file data in that store is returned.
 
-  * * If you don't pass a `storeName`, a writeable stream for writing to the temp store for this file is returned.
 
-  *
 
-  */
 
- FS.File.prototype.createWriteStream = function(storeName) {
 
-   var self = this;
 
-   // We have to have a mounted file in order for this to work
 
-   if (self.isMounted()) {
 
-     if (!storeName && FS.TempStore && FS.FileWorker) {
 
-       // If we have worker installed - we pass the file to FS.TempStore
 
-       // We dont need the storeName since all stores will be generated from
 
-       // TempStore.
 
-       // This should trigger FS.FileWorker at some point?
 
-       FS.TempStore.createWriteStream(self);
 
-     } else {
 
-       // Stream directly to the store using storage adapter
 
-       var storage = self.collection.storesLookup[storeName] || self.collection.primaryStore;
 
-       return storage.adapter.createWriteStream(self);
 
-     }
 
-   } else {
 
-     throw new Meteor.Error('File not mounted');
 
-   }
 
- };
 
- /**
 
-  * @method FS.File.prototype.copy Makes a copy of the file and underlying data in all stores.
 
-  * @public
 
-  * @returns {FS.File} The new FS.File instance
 
-  */
 
- FS.File.prototype.copy = function() {
 
-   var self = this;
 
-   if (!self.isMounted()) {
 
-     throw new Error("Cannot copy a file that is not associated with a collection");
 
-   }
 
-   // Get the file record
 
-   var fileRecord = self.collection.files.findOne({_id: self._id}, {transform: null}) || {};
 
-   // Remove _id and copy keys from the file record
 
-   delete fileRecord._id;
 
-   // Insert directly; we don't have access to "original" in this case
 
-   var newId = self.collection.files.insert(fileRecord);
 
-   var newFile = self.collection.findOne(newId);
 
-   // Copy underlying files in the stores
 
-   var mod, oldKey;
 
-   for (var name in newFile.copies) {
 
-     if (newFile.copies.hasOwnProperty(name)) {
 
-       oldKey = newFile.copies[name].key;
 
-       if (oldKey) {
 
-         // We need to ask the adapter for the true oldKey because
 
-         // right now gridfs does some extra stuff.
 
-         // TODO GridFS should probably set the full key object
 
-         // (with _id and filename) into `copies.key`
 
-         // so that copies.key can be passed directly to
 
-         // createReadStreamForFileKey
 
-         var sourceFileStorage = self.collection.storesLookup[name];
 
-         if (!sourceFileStorage) {
 
-           throw new Error(name + " is not a valid store name");
 
-         }
 
-         oldKey = sourceFileStorage.adapter.fileKey(self);
 
-         // delete so that new fileKey will be generated in copyStoreData
 
-         delete newFile.copies[name].key;
 
-         mod = mod || {};
 
-         mod["copies." + name + ".key"] = copyStoreData(newFile, name, oldKey);
 
-       }
 
-     }
 
-   }
 
-   // Update keys in the filerecord
 
-   if (mod) {
 
-     newFile.update({$set: mod});
 
-   }
 
-   return newFile;
 
- };
 
- Meteor.methods({
 
-   // Does a HEAD request to URL to get the type, updatedAt,
 
-   // and size prior to actually downloading the data.
 
-   // That way we can do filter checks without actually downloading.
 
-   '_cfs_getUrlInfo': function (url, options) {
 
-     check(url, String);
 
-     check(options, Object);
 
-     this.unblock();
 
-     var response = HTTP.call("HEAD", url, options);
 
-     var headers = response.headers;
 
-     var result = {};
 
-     if (headers['content-type']) {
 
-       result.type = headers['content-type'];
 
-     }
 
-     if (headers['content-length']) {
 
-       result.size = +headers['content-length'];
 
-     }
 
-     if (headers['last-modified']) {
 
-       result.updatedAt = new Date(headers['last-modified']);
 
-     }
 
-     return result;
 
-   },
 
-   // Helper function that checks whether given fileId from collectionName
 
-   //  Is fully uploaded to specify storeName.
 
-   '_cfs_returnWhenStored' : function (collectionName, fileId, storeName) {
 
-     check(collectionName, String);
 
-     check(fileId, String);
 
-     check(storeName, String);
 
-     var collection = FS._collections[collectionName];
 
-     if (!collection) {
 
-       return Meteor.Error('_cfs_returnWhenStored: FSCollection name not exists');
 
-     }
 
-     var file = collection.findOne({_id: fileId});
 
-     if (!file) {
 
-       return Meteor.Error('_cfs_returnWhenStored: FSFile not exists');
 
-     }
 
-     return file.hasStored(storeName);
 
-   }
 
- });
 
- // TODO maybe this should be in cfs-storage-adapter
 
- function _copyStoreData(fileObj, storeName, sourceKey, callback) {
 
-   if (!fileObj.isMounted()) {
 
-     throw new Error("Cannot copy store data for a file that is not associated with a collection");
 
-   }
 
-   var storage = fileObj.collection.storesLookup[storeName];
 
-   if (!storage) {
 
-     throw new Error(storeName + " is not a valid store name");
 
-   }
 
-   // We want to prevent beforeWrite and transformWrite from running, so
 
-   // we interact directly with the store.
 
-   var destinationKey = storage.adapter.fileKey(fileObj);
 
-   var readStream = storage.adapter.createReadStreamForFileKey(sourceKey);
 
-   var writeStream = storage.adapter.createWriteStreamForFileKey(destinationKey);
 
-   writeStream.once('stored', function(result) {
 
-     callback(null, result.fileKey);
 
-   });
 
-   writeStream.once('error', function(error) {
 
-     callback(error);
 
-   });
 
-   readStream.pipe(writeStream);
 
- }
 
- var copyStoreData = Meteor.wrapAsync(_copyStoreData);
 
- /**
 
-  * @method FS.File.prototype.copyData Copies the content of a store directly into another store.
 
-  * @public
 
-  * @param {string} sourceStoreName
 
-  * @param {string} targetStoreName
 
-  * @param {boolean=} move
 
-  */
 
- FS.File.prototype.copyData = function(sourceStoreName, targetStoreName, move){
 
-   move = !!move;
 
-   /**
 
-    * @type {Object.<string,*>}
 
-    */
 
-   var sourceStoreValues = this.copies[sourceStoreName];
 
-   /**
 
-    * @type {string}
 
-    */
 
-   var copyKey = cloneDataToStore(this, sourceStoreName, targetStoreName, move);
 
-   /**
 
-    * @type {Object.<string,*>}
 
-    */
 
-   var targetStoreValues = {};
 
-   for (var v in sourceStoreValues) {
 
-     if (sourceStoreValues.hasOwnProperty(v)) {
 
-       targetStoreValues[v] = sourceStoreValues[v]
 
-     }
 
-   }
 
-   targetStoreValues.key = copyKey;
 
-   targetStoreValues.createdAt = new Date();
 
-   targetStoreValues.updatedAt = new Date();
 
-   /**
 
-    *
 
-    * @type {modifier}
 
-    */
 
-   var modifier = {};
 
-   modifier.$set = {};
 
-   modifier.$set["copies."+targetStoreName] = targetStoreValues;
 
-   if(move){
 
-     modifier.$unset = {};
 
-     modifier.$unset["copies."+sourceStoreName] = "";
 
-   }
 
-   this.update(modifier);
 
- };
 
- /**
 
-  * @method FS.File.prototype.moveData Moves the content of a store directly into another store.
 
-  * @public
 
-  * @param {string} sourceStoreName
 
-  * @param {string} targetStoreName
 
-  */
 
- FS.File.prototype.moveData = function(sourceStoreName, targetStoreName){
 
-   this.copyData(sourceStoreName, targetStoreName, true);
 
- };
 
- // TODO maybe this should be in cfs-storage-adapter
 
- /**
 
-  *
 
-  * @param {FS.File} fileObj
 
-  * @param {string} sourceStoreName
 
-  * @param {string} targetStoreName
 
-  * @param {boolean} move
 
-  * @param callback
 
-  * @private
 
-  */
 
- function _copyDataFromStoreToStore(fileObj, sourceStoreName, targetStoreName, move, callback) {
 
-   if (!fileObj.isMounted()) {
 
-     throw new Error("Cannot copy store data for a file that is not associated with a collection");
 
-   }
 
-   /**
 
-    * @type {FS.StorageAdapter}
 
-    */
 
-   var sourceStorage = fileObj.collection.storesLookup[sourceStoreName];
 
-   /**
 
-    * @type {FS.StorageAdapter}
 
-    */
 
-   var targetStorage = fileObj.collection.storesLookup[targetStoreName];
 
-   if (!sourceStorage) {
 
-     throw new Error(sourceStoreName + " is not a valid store name");
 
-   }
 
-   if (!targetStorage) {
 
-     throw new Error(targetStorage + " is not a valid store name");
 
-   }
 
-   // We want to prevent beforeWrite and transformWrite from running, so
 
-   // we interact directly with the store.
 
-   var sourceKey = sourceStorage.adapter.fileKey(fileObj);
 
-   var targetKey = targetStorage.adapter.fileKey(fileObj);
 
-   var readStream = sourceStorage.adapter.createReadStreamForFileKey(sourceKey);
 
-   var writeStream = targetStorage.adapter.createWriteStreamForFileKey(targetKey);
 
-   writeStream.safeOnce('stored', function(result) {
 
-     if(move && sourceStorage.adapter.remove(fileObj)===false){
 
-       callback("Copied to store:" + targetStoreName
 
-       + " with fileKey: "
 
-       + result.fileKey
 
-       + ", but could not delete from source store: "
 
-       + sourceStoreName);
 
-     }else{
 
-       callback(null, result.fileKey);
 
-     }
 
-   });
 
-   writeStream.once('error', function(error) {
 
-     callback(error);
 
-   });
 
-   readStream.pipe(writeStream);
 
- }
 
- var cloneDataToStore = Meteor.wrapAsync(_copyDataFromStoreToStore);
 
 
  |