| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 | 
							- /* global FS, _storageAdapters:true, EventEmitter */
 
- // #############################################################################
 
- //
 
- // STORAGE ADAPTER
 
- //
 
- // #############################################################################
 
- _storageAdapters = {};
 
- FS.StorageAdapter = function(storeName, options, api) {
 
-   var self = this, fileKeyMaker;
 
-   options = options || {};
 
-   // If storeName is the only argument, a string and the SA already found
 
-   // we will just return that SA
 
-   if (arguments.length === 1 && storeName === '' + storeName &&
 
-           typeof _storageAdapters[storeName] !== 'undefined')
 
-     return _storageAdapters[storeName];
 
-   // Verify that the storage adapter defines all the necessary API methods
 
-   if (typeof api === 'undefined') {
 
-     throw new Error('FS.StorageAdapter please define an api');
 
-   }
 
-   
 
-   FS.Utility.each('fileKey,remove,typeName,createReadStream,createWriteStream'.split(','), function(name) {
 
-     if (typeof api[name] === 'undefined') {
 
-       throw new Error('FS.StorageAdapter please define an api. "' + name + '" ' + (api.typeName || ''));
 
-     }
 
-   });
 
-   // Create an internal namespace, starting a name with underscore is only
 
-   // allowed for stores marked with options.internal === true
 
-   if (options.internal !== true && storeName[0] === '_') {
 
-     throw new Error('A storage adapter name may not begin with "_"');
 
-   }
 
-   if (storeName.indexOf('.') !== -1) {
 
-     throw new Error('A storage adapter name may not contain a "."');
 
-   }
 
-   // store reference for easy lookup by storeName
 
-   if (typeof _storageAdapters[storeName] !== 'undefined') {
 
-     throw new Error('Storage name already exists: "' + storeName + '"');
 
-   } else {
 
-     _storageAdapters[storeName] = self;
 
-   }
 
-   // User can customize the file key generation function
 
-   if (typeof options.fileKeyMaker === "function") {
 
-     fileKeyMaker = options.fileKeyMaker;
 
-   } else {
 
-     fileKeyMaker = api.fileKey;
 
-   }
 
-   // User can provide a function to adjust the fileObj
 
-   // before it is written to the store.
 
-   var beforeWrite = options.beforeWrite;
 
-   // extend self with options and other info
 
-   FS.Utility.extend(this, options, {
 
-     name: storeName,
 
-     typeName: api.typeName
 
-   });
 
-   // Create a nicer abstracted adapter interface
 
-   self.adapter = {};
 
-   self.adapter.fileKey = function(fileObj) {
 
-     return fileKeyMaker(fileObj);
 
-   };
 
-   // Return readable stream for fileKey
 
-   self.adapter.createReadStreamForFileKey = function(fileKey, options) {
 
-     if (FS.debug) console.log('createReadStreamForFileKey ' + storeName);
 
-     return FS.Utility.safeStream( api.createReadStream(fileKey, options) );
 
-   };
 
-   // Return readable stream for fileObj
 
-   self.adapter.createReadStream = function(fileObj, options) {
 
-     if (FS.debug) console.log('createReadStream ' + storeName);
 
-     if (self.internal) {
 
-       // Internal stores take a fileKey
 
-       return self.adapter.createReadStreamForFileKey(fileObj, options);
 
-     }
 
-     return FS.Utility.safeStream( self._transform.createReadStream(fileObj, options) );
 
-   };
 
-   function logEventsForStream(stream) {
 
-     if (FS.debug) {
 
-       stream.on('stored', function() {
 
-         console.log('-----------STORED STREAM', storeName);
 
-       });
 
-       stream.on('close', function() {
 
-         console.log('-----------CLOSE STREAM', storeName);
 
-       });
 
-       stream.on('end', function() {
 
-         console.log('-----------END STREAM', storeName);
 
-       });
 
-       stream.on('finish', function() {
 
-         console.log('-----------FINISH STREAM', storeName);
 
-       });
 
-       stream.on('error', function(error) {
 
-         console.log('-----------ERROR STREAM', storeName, error && (error.message || error.code));
 
-       });
 
-     }
 
-   }
 
-   // Return writeable stream for fileKey
 
-   self.adapter.createWriteStreamForFileKey = function(fileKey, options) {
 
-     if (FS.debug) console.log('createWriteStreamForFileKey ' + storeName);
 
-     var writeStream = FS.Utility.safeStream( api.createWriteStream(fileKey, options) );
 
-     logEventsForStream(writeStream);
 
-     return writeStream;
 
-   };
 
-   // Return writeable stream for fileObj
 
-   self.adapter.createWriteStream = function(fileObj, options) {
 
-     if (FS.debug) console.log('createWriteStream ' + storeName + ', internal: ' + !!self.internal);
 
-     
 
-     if (self.internal) {
 
-       // Internal stores take a fileKey
 
-       return self.adapter.createWriteStreamForFileKey(fileObj, options);
 
-     }
 
-     // If we haven't set name, type, or size for this version yet,
 
-     // set it to same values as original version. We don't save
 
-     // these to the DB right away because they might be changed
 
-     // in a transformWrite function.
 
-     if (!fileObj.name({store: storeName})) {
 
-       fileObj.name(fileObj.name(), {store: storeName, save: false});
 
-     }
 
-     if (!fileObj.type({store: storeName})) {
 
-       fileObj.type(fileObj.type(), {store: storeName, save: false});
 
-     }
 
-     if (!fileObj.size({store: storeName})) {
 
-       fileObj.size(fileObj.size(), {store: storeName, save: false});
 
-     }
 
-     // Call user function to adjust file metadata for this store.
 
-     // We support updating name, extension, and/or type based on
 
-     // info returned in an object. Or `fileObj` could be
 
-     // altered directly within the beforeWrite function.
 
-     if (beforeWrite) {
 
-       var fileChanges = beforeWrite(fileObj);
 
-       if (typeof fileChanges === "object") {
 
-         if (fileChanges.extension) {
 
-           fileObj.extension(fileChanges.extension, {store: storeName, save: false});
 
-         } else if (fileChanges.name) {
 
-           fileObj.name(fileChanges.name, {store: storeName, save: false});
 
-         }
 
-         if (fileChanges.type) {
 
-           fileObj.type(fileChanges.type, {store: storeName, save: false});
 
-         }
 
-       }
 
-     }
 
-     var writeStream = FS.Utility.safeStream( self._transform.createWriteStream(fileObj, options) );
 
-     logEventsForStream(writeStream);
 
-     // Its really only the storage adapter who knows if the file is uploaded
 
-     //
 
-     // We have to use our own event making sure the storage process is completed
 
-     // this is mainly
 
-     writeStream.safeOn('stored', function(result) {
 
-       if (typeof result.fileKey === 'undefined') {
 
-         throw new Error('SA ' + storeName + ' type ' + api.typeName + ' did not return a fileKey');
 
-       }
 
-       if (FS.debug) console.log('SA', storeName, 'stored', result.fileKey);
 
-       // Set the fileKey
 
-       fileObj.copies[storeName].key = result.fileKey;
 
-       // Update the size, as provided by the SA, in case it was changed by stream transformation
 
-       if (typeof result.size === "number") {
 
-         fileObj.copies[storeName].size = result.size;
 
-       }
 
-       // Set last updated time, either provided by SA or now
 
-       fileObj.copies[storeName].updatedAt = result.storedAt || new Date();
 
-       // If the file object copy havent got a createdAt then set this
 
-       if (typeof fileObj.copies[storeName].createdAt === 'undefined') {
 
-         fileObj.copies[storeName].createdAt = fileObj.copies[storeName].updatedAt;
 
-       }
 
-       fileObj._saveChanges(storeName);
 
-       // There is code in transform that may have set the original file size, too.
 
-       fileObj._saveChanges('_original');
 
-     });
 
-     // Emit events from SA
 
-     writeStream.once('stored', function(/*result*/) {
 
-       // XXX Because of the way stores inherit from SA, this will emit on every store.
 
-       // Maybe need to rewrite the way we inherit from SA?
 
-       var emitted = self.emit('stored', storeName, fileObj);
 
-       if (FS.debug && !emitted) {
 
-         console.log(fileObj.name() + ' was successfully stored in the ' + storeName + ' store. You are seeing this informational message because you enabled debugging and you have not defined any listeners for the "stored" event on this store.');
 
-       }
 
-     });
 
-     writeStream.on('error', function(error) {
 
-       // XXX We could wrap and clarify error
 
-       // XXX Because of the way stores inherit from SA, this will emit on every store.
 
-       // Maybe need to rewrite the way we inherit from SA?
 
-       var emitted = self.emit('error', storeName, error, fileObj);
 
-       if (FS.debug && !emitted) {
 
-         console.log(error);
 
-       }
 
-     });
 
-     return writeStream;
 
-   };
 
-   //internal
 
-   self._removeAsync = function(fileKey, callback) {
 
-     // Remove the file from the store
 
-     api.remove.call(self, fileKey, callback);
 
-   };
 
-   /**
 
-    * @method FS.StorageAdapter.prototype.remove
 
-    * @public
 
-    * @param {FS.File} fsFile The FS.File instance to be stored.
 
-    * @param {Function} [callback] If not provided, will block and return true or false
 
-    *
 
-    * Attempts to remove a file from the store. Returns true if removed or not
 
-    * found, or false if the file couldn't be removed.
 
-    */
 
-   self.adapter.remove = function(fileObj, callback) {
 
-     if (FS.debug) console.log("---SA REMOVE");
 
-     // Get the fileKey
 
-     var fileKey = (fileObj instanceof FS.File) ? self.adapter.fileKey(fileObj) : fileObj;
 
-     if (callback) {
 
-       return self._removeAsync(fileKey, FS.Utility.safeCallback(callback));
 
-     } else {
 
-       return Meteor.wrapAsync(self._removeAsync)(fileKey);
 
-     }
 
-   };
 
-   self.remove = function(fileObj, callback) {
 
-     // Add deprecation note
 
-     console.warn('Storage.remove is deprecating, use "Storage.adapter.remove"');
 
-     return self.adapter.remove(fileObj, callback);
 
-   };
 
-   if (typeof api.init === 'function') {
 
-     Meteor.wrapAsync(api.init.bind(self))();
 
-   }
 
-   // This supports optional transformWrite and transformRead
 
-   self._transform = new FS.Transform({
 
-     adapter: self.adapter,
 
-     // Optional transformation functions:
 
-     transformWrite: options.transformWrite,
 
-     transformRead: options.transformRead
 
-   });
 
- };
 
- Npm.require('util').inherits(FS.StorageAdapter, EventEmitter);
 
 
  |