You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							258 lines
						
					
					
						
							9.7 KiB
						
					
					
				
			
		
		
	
	
							258 lines
						
					
					
						
							9.7 KiB
						
					
					
				| "use strict";
 | |
| var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
 | |
|     function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
 | |
|     return new (P || (P = Promise))(function (resolve, reject) {
 | |
|         function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
 | |
|         function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
 | |
|         function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
 | |
|         step((generator = generator.apply(thisArg, _arguments || [])).next());
 | |
|     });
 | |
| };
 | |
| var __importDefault = (this && this.__importDefault) || function (mod) {
 | |
|     return (mod && mod.__esModule) ? mod : { "default": mod };
 | |
| };
 | |
| Object.defineProperty(exports, "__esModule", { value: true });
 | |
| exports.Cache = void 0;
 | |
| /**
 | |
|  * Storage cache
 | |
|  * @module multer-gridfs-storage/cache
 | |
|  */
 | |
| const events_1 = require("events");
 | |
| const mongodb_uri_1 = __importDefault(require("mongodb-uri"));
 | |
| const utils_1 = require("./utils");
 | |
| /**
 | |
|  * Plugin cached connection handling class.
 | |
|  * @version 3.1.0
 | |
|  */
 | |
| class Cache {
 | |
|     constructor() {
 | |
|         this.store = new Map();
 | |
|         this.emitter = new events_1.EventEmitter();
 | |
|         this.emitter.setMaxListeners(0);
 | |
|     }
 | |
|     /**
 | |
|      * Handles creating a new connection from an url and caching if necessary
 | |
|      * @param {object} options - Options to initialize the cache
 | |
|      * @param {string} options.url - The url to cache
 | |
|      * @param {string} options.cacheName - The name of the cache to use
 | |
|      * @param {any} options.init - The connection options provided
 | |
|      **/
 | |
|     initialize(options) {
 | |
|         let { url, cacheName: name } = options;
 | |
|         // If the option is a falsey value or empty object use null as initial value
 | |
|         const init = utils_1.compare(options.init, null) ? null : options.init;
 | |
|         // If a cache under that name does not exist create one
 | |
|         if (!this.store.has(name)) {
 | |
|             this.store.set(name, new Map());
 | |
|         }
 | |
|         // Check if the url has been used for that cache before
 | |
|         let cached = this.store.get(name).get(url);
 | |
|         if (!this.store.get(name).has(url)) {
 | |
|             // If the url matches any equivalent url used before use that connection instead
 | |
|             const eqUrl = this.findUri(name, url);
 | |
|             if (!eqUrl) {
 | |
|                 const store = new Map();
 | |
|                 store.set(0, {
 | |
|                     db: null,
 | |
|                     client: null,
 | |
|                     pending: true,
 | |
|                     opening: false,
 | |
|                     init,
 | |
|                 });
 | |
|                 this.store.get(name).set(url, store);
 | |
|                 return {
 | |
|                     url,
 | |
|                     name,
 | |
|                     index: 0,
 | |
|                 };
 | |
|             }
 | |
|             url = eqUrl;
 | |
|             cached = this.store.get(name).get(url);
 | |
|         }
 | |
|         // Compare connection options to create more only if they are semantically different
 | |
|         for (const [index, value] of cached) {
 | |
|             if (utils_1.compare(value.init, options.init)) {
 | |
|                 return {
 | |
|                     url,
 | |
|                     name,
 | |
|                     index,
 | |
|                 };
 | |
|             }
 | |
|         }
 | |
|         cached.set(cached.size, {
 | |
|             db: null,
 | |
|             client: null,
 | |
|             pending: true,
 | |
|             opening: false,
 | |
|             init,
 | |
|         });
 | |
|         return {
 | |
|             url,
 | |
|             name,
 | |
|             index: cached.size - 1,
 | |
|         };
 | |
|     }
 | |
|     /**
 | |
|      * Search the cache for a space stored under an equivalent url.
 | |
|      *
 | |
|      * Just swapping parameters can cause two url to be deemed different when in fact they are not.
 | |
|      * This method finds an url in the cache where another url could be stored even when they are not strictly equal
 | |
|      * @param cacheName The name of the cache to search
 | |
|      * @param url The mongodb url to compare
 | |
|      * @return The similar url already in the cache
 | |
|      */
 | |
|     findUri(cacheName, url) {
 | |
|         for (const [storedUrl] of this.store.get(cacheName)) {
 | |
|             const parsedUri = mongodb_uri_1.default.parse(storedUrl);
 | |
|             const parsedCache = mongodb_uri_1.default.parse(url);
 | |
|             if (utils_1.compareUris(parsedUri, parsedCache)) {
 | |
|                 return storedUrl;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     /**
 | |
|      * Returns true if the cache has an entry matching the given index
 | |
|      * @param cacheIndex The index to look for
 | |
|      * @return Returns if the cache was found
 | |
|      */
 | |
|     has(cacheIndex) {
 | |
|         return Boolean(this.get(cacheIndex));
 | |
|     }
 | |
|     /**
 | |
|      * Returns the contents of the cache in a given index
 | |
|      * @param cacheIndex {object} The index to look for
 | |
|      * @return {object} The cache contents or null if was not found
 | |
|      */
 | |
|     get(cacheIndex) {
 | |
|         const { name, url, index } = cacheIndex;
 | |
|         if (!this.store.has(name)) {
 | |
|             return null;
 | |
|         }
 | |
|         if (!this.store.get(name).has(url)) {
 | |
|             return null;
 | |
|         }
 | |
|         if (!this.store.get(name).get(url).has(index)) {
 | |
|             return null;
 | |
|         }
 | |
|         return this.store.get(name).get(url).get(index);
 | |
|     }
 | |
|     /**
 | |
|      * Sets the contents of the cache in a given index
 | |
|      * @param cacheIndex The index to look for
 | |
|      * @param value The value to set
 | |
|      */
 | |
|     set(cacheIndex, value) {
 | |
|         const { name, url, index } = cacheIndex;
 | |
|         this.store.get(name).get(url).set(index, value);
 | |
|     }
 | |
|     /**
 | |
|      * Returns true if a given cache is resolving its associated connection
 | |
|      * @param cacheIndex {object} The index to look for
 | |
|      * @return Return true if the connection is not found yet
 | |
|      */
 | |
|     isPending(cacheIndex) {
 | |
|         const cached = this.get(cacheIndex);
 | |
|         return Boolean(cached) && cached.pending;
 | |
|     }
 | |
|     /**
 | |
|      * Return true if a given cache started resolving a connection for itself
 | |
|      * @param cacheIndex {object} The index to look for
 | |
|      * @return Return true if no instances have started creating a connection for this cache
 | |
|      */
 | |
|     isOpening(cacheIndex) {
 | |
|         const cached = this.get(cacheIndex);
 | |
|         return Boolean(cached === null || cached === void 0 ? void 0 : cached.opening);
 | |
|     }
 | |
|     /**
 | |
|      * Sets the database and client for a given cache and resolves all instances waiting for it
 | |
|      * @param cacheIndex {object} The index to look for
 | |
|      * @param db  The database used to store files
 | |
|      * @param [client] The client used to open the connection or null if none is provided
 | |
|      */
 | |
|     resolve(cacheIndex, db, client) {
 | |
|         const cached = this.get(cacheIndex);
 | |
|         cached.db = db;
 | |
|         cached.client = client;
 | |
|         cached.pending = false;
 | |
|         cached.opening = false;
 | |
|         this.emitter.emit('resolve', cacheIndex);
 | |
|     }
 | |
|     /**
 | |
|      * Rejects all instances waiting for this connections
 | |
|      * @param cacheIndex The index to look for
 | |
|      * @param err The error thrown by the driver
 | |
|      */
 | |
|     reject(cacheIndex, error) {
 | |
|         const cached = this.get(cacheIndex);
 | |
|         cached.pending = false;
 | |
|         this.emitter.emit('reject', cacheIndex, error);
 | |
|         this.remove(cacheIndex);
 | |
|     }
 | |
|     /**
 | |
|      * Allows waiting for a connection associated to a given cache
 | |
|      * @param cacheIndex The index to look for
 | |
|      * @return A promise that will resolve when the connection for this cache is created
 | |
|      */
 | |
|     waitFor(cacheIndex) {
 | |
|         return __awaiter(this, void 0, void 0, function* () {
 | |
|             if (!this.isPending(cacheIndex) && !this.isOpening(cacheIndex)) {
 | |
|                 return this.get(cacheIndex);
 | |
|             }
 | |
|             return new Promise((resolve, reject) => {
 | |
|                 const _resolve = (index) => {
 | |
|                     if (utils_1.compare(cacheIndex, index)) {
 | |
|                         this.emitter.removeListener('resolve', _resolve);
 | |
|                         this.emitter.removeListener('reject', _reject);
 | |
|                         resolve(this.get(cacheIndex));
 | |
|                     }
 | |
|                 };
 | |
|                 const _reject = (index, error) => {
 | |
|                     if (utils_1.compare(cacheIndex, index)) {
 | |
|                         this.emitter.removeListener('resolve', _resolve);
 | |
|                         this.emitter.removeListener('reject', _reject);
 | |
|                         reject(error);
 | |
|                     }
 | |
|                 };
 | |
|                 this.emitter.on('resolve', _resolve);
 | |
|                 this.emitter.on('reject', _reject);
 | |
|             });
 | |
|         });
 | |
|     }
 | |
|     /**
 | |
|      * Gives the number of connections created by all cache instances
 | |
|      * @return {number} The number of created connections
 | |
|      */
 | |
|     connections() {
 | |
|         let total = 0;
 | |
|         for (const urlStore of this.store.values()) {
 | |
|             for (const store of urlStore.values()) {
 | |
|                 total += store.size;
 | |
|             }
 | |
|         }
 | |
|         return total;
 | |
|     }
 | |
|     /**
 | |
|      * Removes a cache entry.
 | |
|      *
 | |
|      * > If the cache hasn't resolved yet it will be rejected.
 | |
|      * @param cacheIndex The index to look for
 | |
|      */
 | |
|     remove(cacheIndex) {
 | |
|         if (this.has(cacheIndex)) {
 | |
|             if (this.isPending(cacheIndex)) {
 | |
|                 this.emitter.emit('reject', cacheIndex, new Error('The cache entry was deleted'));
 | |
|             }
 | |
|             const { name, url, index } = cacheIndex;
 | |
|             this.store.get(name).get(url).delete(index);
 | |
|         }
 | |
|     }
 | |
|     /**
 | |
|      * Removes all entries in the cache and all listeners
 | |
|      */
 | |
|     clear() {
 | |
|         this.store = new Map();
 | |
|         this.emitter.removeAllListeners();
 | |
|     }
 | |
| }
 | |
| exports.Cache = Cache;
 | |
| //# sourceMappingURL=cache.js.map
 |