mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-11-01 19:07:02 -04:00 
			
		
		
		
	Update:Remove proper-lockfile dependency
This commit is contained in:
		
							parent
							
								
									b7e546f2f5
								
							
						
					
					
						commit
						e06a015d6e
					
				
							
								
								
									
										44
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										44
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -24,7 +24,6 @@ | ||||
|         "libgen": "^2.1.0", | ||||
|         "node-ffprobe": "^3.0.0", | ||||
|         "node-stream-zip": "^1.15.0", | ||||
|         "proper-lockfile": "^4.1.2", | ||||
|         "recursive-readdir-async": "^1.1.8", | ||||
|         "socket.io": "^4.4.1", | ||||
|         "xml2js": "^0.4.23" | ||||
| @ -1488,16 +1487,6 @@ | ||||
|       "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", | ||||
|       "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" | ||||
|     }, | ||||
|     "node_modules/proper-lockfile": { | ||||
|       "version": "4.1.2", | ||||
|       "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", | ||||
|       "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", | ||||
|       "dependencies": { | ||||
|         "graceful-fs": "^4.2.4", | ||||
|         "retry": "^0.12.0", | ||||
|         "signal-exit": "^3.0.2" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/proxy-addr": { | ||||
|       "version": "2.0.7", | ||||
|       "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", | ||||
| @ -1608,14 +1597,6 @@ | ||||
|         "lowercase-keys": "^2.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/retry": { | ||||
|       "version": "0.12.0", | ||||
|       "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", | ||||
|       "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", | ||||
|       "engines": { | ||||
|         "node": ">= 4" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/safe-buffer": { | ||||
|       "version": "5.2.1", | ||||
|       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", | ||||
| @ -1713,11 +1694,6 @@ | ||||
|         "url": "https://github.com/sponsors/ljharb" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/signal-exit": { | ||||
|       "version": "3.0.7", | ||||
|       "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", | ||||
|       "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" | ||||
|     }, | ||||
|     "node_modules/socket.io": { | ||||
|       "version": "4.5.1", | ||||
|       "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.1.tgz", | ||||
| @ -3084,16 +3060,6 @@ | ||||
|       "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", | ||||
|       "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" | ||||
|     }, | ||||
|     "proper-lockfile": { | ||||
|       "version": "4.1.2", | ||||
|       "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", | ||||
|       "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", | ||||
|       "requires": { | ||||
|         "graceful-fs": "^4.2.4", | ||||
|         "retry": "^0.12.0", | ||||
|         "signal-exit": "^3.0.2" | ||||
|       } | ||||
|     }, | ||||
|     "proxy-addr": { | ||||
|       "version": "2.0.7", | ||||
|       "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", | ||||
| @ -3177,11 +3143,6 @@ | ||||
|         "lowercase-keys": "^2.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "retry": { | ||||
|       "version": "0.12.0", | ||||
|       "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", | ||||
|       "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==" | ||||
|     }, | ||||
|     "safe-buffer": { | ||||
|       "version": "5.2.1", | ||||
|       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", | ||||
| @ -3255,11 +3216,6 @@ | ||||
|         "object-inspect": "^1.9.0" | ||||
|       } | ||||
|     }, | ||||
|     "signal-exit": { | ||||
|       "version": "3.0.7", | ||||
|       "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", | ||||
|       "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" | ||||
|     }, | ||||
|     "socket.io": { | ||||
|       "version": "4.5.1", | ||||
|       "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.1.tgz", | ||||
|  | ||||
| @ -43,7 +43,6 @@ | ||||
|     "libgen": "^2.1.0", | ||||
|     "node-ffprobe": "^3.0.0", | ||||
|     "node-stream-zip": "^1.15.0", | ||||
|     "proper-lockfile": "^4.1.2", | ||||
|     "recursive-readdir-async": "^1.1.8", | ||||
|     "socket.io": "^4.4.1", | ||||
|     "xml2js": "^0.4.23" | ||||
|  | ||||
| @ -1,6 +1,5 @@ | ||||
| const Path = require('path') | ||||
| const njodb = require('./njodb') | ||||
| const jwt = require('jsonwebtoken') | ||||
| const njodb = require('./libs/njodb') | ||||
| const Logger = require('./Logger') | ||||
| const { version } = require('../package.json') | ||||
| const LibraryItem = require('./objects/LibraryItem') | ||||
|  | ||||
| @ -27,7 +27,7 @@ const { | ||||
|     checkSync, | ||||
|     lock, | ||||
|     lockSync | ||||
| } = require("proper-lockfile"); | ||||
| } = require("../properLockfile"); | ||||
| 
 | ||||
| const { | ||||
|     deleteFile, | ||||
							
								
								
									
										40
									
								
								server/libs/properLockfile/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								server/libs/properLockfile/index.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,40 @@ | ||||
| 'use strict'; | ||||
| 
 | ||||
| const lockfile = require('./lib/lockfile'); | ||||
| const { toPromise, toSync, toSyncOptions } = require('./lib/adapter'); | ||||
| 
 | ||||
| async function lock(file, options) { | ||||
|   const release = await toPromise(lockfile.lock)(file, options); | ||||
| 
 | ||||
|   return toPromise(release); | ||||
| } | ||||
| 
 | ||||
| function lockSync(file, options) { | ||||
|   const release = toSync(lockfile.lock)(file, toSyncOptions(options)); | ||||
| 
 | ||||
|   return toSync(release); | ||||
| } | ||||
| 
 | ||||
| function unlock(file, options) { | ||||
|   return toPromise(lockfile.unlock)(file, options); | ||||
| } | ||||
| 
 | ||||
| function unlockSync(file, options) { | ||||
|   return toSync(lockfile.unlock)(file, toSyncOptions(options)); | ||||
| } | ||||
| 
 | ||||
| function check(file, options) { | ||||
|   return toPromise(lockfile.check)(file, options); | ||||
| } | ||||
| 
 | ||||
| function checkSync(file, options) { | ||||
|   return toSync(lockfile.check)(file, toSyncOptions(options)); | ||||
| } | ||||
| 
 | ||||
| module.exports = lock; | ||||
| module.exports.lock = lock; | ||||
| module.exports.unlock = unlock; | ||||
| module.exports.lockSync = lockSync; | ||||
| module.exports.unlockSync = unlockSync; | ||||
| module.exports.check = check; | ||||
| module.exports.checkSync = checkSync; | ||||
							
								
								
									
										85
									
								
								server/libs/properLockfile/lib/adapter.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								server/libs/properLockfile/lib/adapter.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,85 @@ | ||||
| 'use strict'; | ||||
| 
 | ||||
| const fs = require('graceful-fs'); | ||||
| 
 | ||||
| function createSyncFs(fs) { | ||||
|     const methods = ['mkdir', 'realpath', 'stat', 'rmdir', 'utimes']; | ||||
|     const newFs = { ...fs }; | ||||
| 
 | ||||
|     methods.forEach((method) => { | ||||
|         newFs[method] = (...args) => { | ||||
|             const callback = args.pop(); | ||||
|             let ret; | ||||
| 
 | ||||
|             try { | ||||
|                 ret = fs[`${method}Sync`](...args); | ||||
|             } catch (err) { | ||||
|                 return callback(err); | ||||
|             } | ||||
| 
 | ||||
|             callback(null, ret); | ||||
|         }; | ||||
|     }); | ||||
| 
 | ||||
|     return newFs; | ||||
| } | ||||
| 
 | ||||
| // ----------------------------------------------------------
 | ||||
| 
 | ||||
| function toPromise(method) { | ||||
|     return (...args) => new Promise((resolve, reject) => { | ||||
|         args.push((err, result) => { | ||||
|             if (err) { | ||||
|                 reject(err); | ||||
|             } else { | ||||
|                 resolve(result); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         method(...args); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| function toSync(method) { | ||||
|     return (...args) => { | ||||
|         let err; | ||||
|         let result; | ||||
| 
 | ||||
|         args.push((_err, _result) => { | ||||
|             err = _err; | ||||
|             result = _result; | ||||
|         }); | ||||
| 
 | ||||
|         method(...args); | ||||
| 
 | ||||
|         if (err) { | ||||
|             throw err; | ||||
|         } | ||||
| 
 | ||||
|         return result; | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| function toSyncOptions(options) { | ||||
|     // Shallow clone options because we are oging to mutate them
 | ||||
|     options = { ...options }; | ||||
| 
 | ||||
|     // Transform fs to use the sync methods instead
 | ||||
|     options.fs = createSyncFs(options.fs || fs); | ||||
| 
 | ||||
|     // Retries are not allowed because it requires the flow to be sync
 | ||||
|     if ( | ||||
|         (typeof options.retries === 'number' && options.retries > 0) || | ||||
|         (options.retries && typeof options.retries.retries === 'number' && options.retries.retries > 0) | ||||
|     ) { | ||||
|         throw Object.assign(new Error('Cannot use retries with the sync api'), { code: 'ESYNC' }); | ||||
|     } | ||||
| 
 | ||||
|     return options; | ||||
| } | ||||
| 
 | ||||
| module.exports = { | ||||
|     toPromise, | ||||
|     toSync, | ||||
|     toSyncOptions, | ||||
| }; | ||||
							
								
								
									
										342
									
								
								server/libs/properLockfile/lib/lockfile.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										342
									
								
								server/libs/properLockfile/lib/lockfile.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,342 @@ | ||||
| 'use strict'; | ||||
| 
 | ||||
| const path = require('path'); | ||||
| const fs = require('graceful-fs'); | ||||
| const retry = require('../../retry'); | ||||
| const onExit = require('../../signalExit'); | ||||
| const mtimePrecision = require('./mtime-precision'); | ||||
| 
 | ||||
| const locks = {}; | ||||
| 
 | ||||
| function getLockFile(file, options) { | ||||
|     return options.lockfilePath || `${file}.lock`; | ||||
| } | ||||
| 
 | ||||
| function resolveCanonicalPath(file, options, callback) { | ||||
|     if (!options.realpath) { | ||||
|         return callback(null, path.resolve(file)); | ||||
|     } | ||||
| 
 | ||||
|     // Use realpath to resolve symlinks
 | ||||
|     // It also resolves relative paths
 | ||||
|     options.fs.realpath(file, callback); | ||||
| } | ||||
| 
 | ||||
| function acquireLock(file, options, callback) { | ||||
|     const lockfilePath = getLockFile(file, options); | ||||
| 
 | ||||
|     // Use mkdir to create the lockfile (atomic operation)
 | ||||
|     options.fs.mkdir(lockfilePath, (err) => { | ||||
|         if (!err) { | ||||
|             // At this point, we acquired the lock!
 | ||||
|             // Probe the mtime precision
 | ||||
|             return mtimePrecision.probe(lockfilePath, options.fs, (err, mtime, mtimePrecision) => { | ||||
|                 // If it failed, try to remove the lock..
 | ||||
|                 /* istanbul ignore if */ | ||||
|                 if (err) { | ||||
|                     options.fs.rmdir(lockfilePath, () => { }); | ||||
| 
 | ||||
|                     return callback(err); | ||||
|                 } | ||||
| 
 | ||||
|                 callback(null, mtime, mtimePrecision); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         // If error is not EEXIST then some other error occurred while locking
 | ||||
|         if (err.code !== 'EEXIST') { | ||||
|             return callback(err); | ||||
|         } | ||||
| 
 | ||||
|         // Otherwise, check if lock is stale by analyzing the file mtime
 | ||||
|         if (options.stale <= 0) { | ||||
|             return callback(Object.assign(new Error('Lock file is already being held'), { code: 'ELOCKED', file })); | ||||
|         } | ||||
| 
 | ||||
|         options.fs.stat(lockfilePath, (err, stat) => { | ||||
|             if (err) { | ||||
|                 // Retry if the lockfile has been removed (meanwhile)
 | ||||
|                 // Skip stale check to avoid recursiveness
 | ||||
|                 if (err.code === 'ENOENT') { | ||||
|                     return acquireLock(file, { ...options, stale: 0 }, callback); | ||||
|                 } | ||||
| 
 | ||||
|                 return callback(err); | ||||
|             } | ||||
| 
 | ||||
|             if (!isLockStale(stat, options)) { | ||||
|                 return callback(Object.assign(new Error('Lock file is already being held'), { code: 'ELOCKED', file })); | ||||
|             } | ||||
| 
 | ||||
|             // If it's stale, remove it and try again!
 | ||||
|             // Skip stale check to avoid recursiveness
 | ||||
|             removeLock(file, options, (err) => { | ||||
|                 if (err) { | ||||
|                     return callback(err); | ||||
|                 } | ||||
| 
 | ||||
|                 acquireLock(file, { ...options, stale: 0 }, callback); | ||||
|             }); | ||||
|         }); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| function isLockStale(stat, options) { | ||||
|     return stat.mtime.getTime() < Date.now() - options.stale; | ||||
| } | ||||
| 
 | ||||
| function removeLock(file, options, callback) { | ||||
|     // Remove lockfile, ignoring ENOENT errors
 | ||||
|     options.fs.rmdir(getLockFile(file, options), (err) => { | ||||
|         if (err && err.code !== 'ENOENT') { | ||||
|             return callback(err); | ||||
|         } | ||||
| 
 | ||||
|         callback(); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| function updateLock(file, options) { | ||||
|     const lock = locks[file]; | ||||
| 
 | ||||
|     // Just for safety, should never happen
 | ||||
|     /* istanbul ignore if */ | ||||
|     if (lock.updateTimeout) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     lock.updateDelay = lock.updateDelay || options.update; | ||||
|     lock.updateTimeout = setTimeout(() => { | ||||
|         lock.updateTimeout = null; | ||||
| 
 | ||||
|         // Stat the file to check if mtime is still ours
 | ||||
|         // If it is, we can still recover from a system sleep or a busy event loop
 | ||||
|         options.fs.stat(lock.lockfilePath, (err, stat) => { | ||||
|             const isOverThreshold = lock.lastUpdate + options.stale < Date.now(); | ||||
| 
 | ||||
|             // If it failed to update the lockfile, keep trying unless
 | ||||
|             // the lockfile was deleted or we are over the threshold
 | ||||
|             if (err) { | ||||
|                 if (err.code === 'ENOENT' || isOverThreshold) { | ||||
|                     return setLockAsCompromised(file, lock, Object.assign(err, { code: 'ECOMPROMISED' })); | ||||
|                 } | ||||
| 
 | ||||
|                 lock.updateDelay = 1000; | ||||
| 
 | ||||
|                 return updateLock(file, options); | ||||
|             } | ||||
| 
 | ||||
|             const isMtimeOurs = lock.mtime.getTime() === stat.mtime.getTime(); | ||||
| 
 | ||||
|             if (!isMtimeOurs) { | ||||
|                 return setLockAsCompromised( | ||||
|                     file, | ||||
|                     lock, | ||||
|                     Object.assign( | ||||
|                         new Error('Unable to update lock within the stale threshold'), | ||||
|                         { code: 'ECOMPROMISED' } | ||||
|                     )); | ||||
|             } | ||||
| 
 | ||||
|             const mtime = mtimePrecision.getMtime(lock.mtimePrecision); | ||||
| 
 | ||||
|             options.fs.utimes(lock.lockfilePath, mtime, mtime, (err) => { | ||||
|                 const isOverThreshold = lock.lastUpdate + options.stale < Date.now(); | ||||
| 
 | ||||
|                 // Ignore if the lock was released
 | ||||
|                 if (lock.released) { | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|                 // If it failed to update the lockfile, keep trying unless
 | ||||
|                 // the lockfile was deleted or we are over the threshold
 | ||||
|                 if (err) { | ||||
|                     if (err.code === 'ENOENT' || isOverThreshold) { | ||||
|                         return setLockAsCompromised(file, lock, Object.assign(err, { code: 'ECOMPROMISED' })); | ||||
|                     } | ||||
| 
 | ||||
|                     lock.updateDelay = 1000; | ||||
| 
 | ||||
|                     return updateLock(file, options); | ||||
|                 } | ||||
| 
 | ||||
|                 // All ok, keep updating..
 | ||||
|                 lock.mtime = mtime; | ||||
|                 lock.lastUpdate = Date.now(); | ||||
|                 lock.updateDelay = null; | ||||
|                 updateLock(file, options); | ||||
|             }); | ||||
|         }); | ||||
|     }, lock.updateDelay); | ||||
| 
 | ||||
|     // Unref the timer so that the nodejs process can exit freely
 | ||||
|     // This is safe because all acquired locks will be automatically released
 | ||||
|     // on process exit
 | ||||
| 
 | ||||
|     // We first check that `lock.updateTimeout.unref` exists because some users
 | ||||
|     // may be using this module outside of NodeJS (e.g., in an electron app),
 | ||||
|     // and in those cases `setTimeout` return an integer.
 | ||||
|     /* istanbul ignore else */ | ||||
|     if (lock.updateTimeout.unref) { | ||||
|         lock.updateTimeout.unref(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function setLockAsCompromised(file, lock, err) { | ||||
|     // Signal the lock has been released
 | ||||
|     lock.released = true; | ||||
| 
 | ||||
|     // Cancel lock mtime update
 | ||||
|     // Just for safety, at this point updateTimeout should be null
 | ||||
|     /* istanbul ignore if */ | ||||
|     if (lock.updateTimeout) { | ||||
|         clearTimeout(lock.updateTimeout); | ||||
|     } | ||||
| 
 | ||||
|     if (locks[file] === lock) { | ||||
|         delete locks[file]; | ||||
|     } | ||||
| 
 | ||||
|     lock.options.onCompromised(err); | ||||
| } | ||||
| 
 | ||||
| // ----------------------------------------------------------
 | ||||
| 
 | ||||
| function lock(file, options, callback) { | ||||
|     /* istanbul ignore next */ | ||||
|     options = { | ||||
|         stale: 10000, | ||||
|         update: null, | ||||
|         realpath: true, | ||||
|         retries: 0, | ||||
|         fs, | ||||
|         onCompromised: (err) => { throw err; }, | ||||
|         ...options, | ||||
|     }; | ||||
| 
 | ||||
|     options.retries = options.retries || 0; | ||||
|     options.retries = typeof options.retries === 'number' ? { retries: options.retries } : options.retries; | ||||
|     options.stale = Math.max(options.stale || 0, 2000); | ||||
|     options.update = options.update == null ? options.stale / 2 : options.update || 0; | ||||
|     options.update = Math.max(Math.min(options.update, options.stale / 2), 1000); | ||||
| 
 | ||||
|     // Resolve to a canonical file path
 | ||||
|     resolveCanonicalPath(file, options, (err, file) => { | ||||
|         if (err) { | ||||
|             return callback(err); | ||||
|         } | ||||
| 
 | ||||
|         // Attempt to acquire the lock
 | ||||
|         const operation = retry.operation(options.retries); | ||||
| 
 | ||||
|         operation.attempt(() => { | ||||
|             acquireLock(file, options, (err, mtime, mtimePrecision) => { | ||||
|                 if (operation.retry(err)) { | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|                 if (err) { | ||||
|                     return callback(operation.mainError()); | ||||
|                 } | ||||
| 
 | ||||
|                 // We now own the lock
 | ||||
|                 const lock = locks[file] = { | ||||
|                     lockfilePath: getLockFile(file, options), | ||||
|                     mtime, | ||||
|                     mtimePrecision, | ||||
|                     options, | ||||
|                     lastUpdate: Date.now(), | ||||
|                 }; | ||||
| 
 | ||||
|                 // We must keep the lock fresh to avoid staleness
 | ||||
|                 updateLock(file, options); | ||||
| 
 | ||||
|                 callback(null, (releasedCallback) => { | ||||
|                     if (lock.released) { | ||||
|                         return releasedCallback && | ||||
|                             releasedCallback(Object.assign(new Error('Lock is already released'), { code: 'ERELEASED' })); | ||||
|                     } | ||||
| 
 | ||||
|                     // Not necessary to use realpath twice when unlocking
 | ||||
|                     unlock(file, { ...options, realpath: false }, releasedCallback); | ||||
|                 }); | ||||
|             }); | ||||
|         }); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| function unlock(file, options, callback) { | ||||
|     options = { | ||||
|         fs, | ||||
|         realpath: true, | ||||
|         ...options, | ||||
|     }; | ||||
| 
 | ||||
|     // Resolve to a canonical file path
 | ||||
|     resolveCanonicalPath(file, options, (err, file) => { | ||||
|         if (err) { | ||||
|             return callback(err); | ||||
|         } | ||||
| 
 | ||||
|         // Skip if the lock is not acquired
 | ||||
|         const lock = locks[file]; | ||||
| 
 | ||||
|         if (!lock) { | ||||
|             return callback(Object.assign(new Error('Lock is not acquired/owned by you'), { code: 'ENOTACQUIRED' })); | ||||
|         } | ||||
| 
 | ||||
|         lock.updateTimeout && clearTimeout(lock.updateTimeout); // Cancel lock mtime update
 | ||||
|         lock.released = true; // Signal the lock has been released
 | ||||
|         delete locks[file]; // Delete from locks
 | ||||
| 
 | ||||
|         removeLock(file, options, callback); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| function check(file, options, callback) { | ||||
|     options = { | ||||
|         stale: 10000, | ||||
|         realpath: true, | ||||
|         fs, | ||||
|         ...options, | ||||
|     }; | ||||
| 
 | ||||
|     options.stale = Math.max(options.stale || 0, 2000); | ||||
| 
 | ||||
|     // Resolve to a canonical file path
 | ||||
|     resolveCanonicalPath(file, options, (err, file) => { | ||||
|         if (err) { | ||||
|             return callback(err); | ||||
|         } | ||||
| 
 | ||||
|         // Check if lockfile exists
 | ||||
|         options.fs.stat(getLockFile(file, options), (err, stat) => { | ||||
|             if (err) { | ||||
|                 // If does not exist, file is not locked. Otherwise, callback with error
 | ||||
|                 return err.code === 'ENOENT' ? callback(null, false) : callback(err); | ||||
|             } | ||||
| 
 | ||||
|             // Otherwise, check if lock is stale by analyzing the file mtime
 | ||||
|             return callback(null, !isLockStale(stat, options)); | ||||
|         }); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| function getLocks() { | ||||
|     return locks; | ||||
| } | ||||
| 
 | ||||
| // Remove acquired locks on exit
 | ||||
| /* istanbul ignore next */ | ||||
| onExit(() => { | ||||
|     for (const file in locks) { | ||||
|         const options = locks[file].options; | ||||
| 
 | ||||
|         try { options.fs.rmdirSync(getLockFile(file, options)); } catch (e) { /* Empty */ } | ||||
|     } | ||||
| }); | ||||
| 
 | ||||
| module.exports.lock = lock; | ||||
| module.exports.unlock = unlock; | ||||
| module.exports.check = check; | ||||
| module.exports.getLocks = getLocks; | ||||
							
								
								
									
										55
									
								
								server/libs/properLockfile/lib/mtime-precision.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								server/libs/properLockfile/lib/mtime-precision.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,55 @@ | ||||
| 'use strict'; | ||||
| 
 | ||||
| const cacheSymbol = Symbol(); | ||||
| 
 | ||||
| function probe(file, fs, callback) { | ||||
|     const cachedPrecision = fs[cacheSymbol]; | ||||
| 
 | ||||
|     if (cachedPrecision) { | ||||
|         return fs.stat(file, (err, stat) => { | ||||
|             /* istanbul ignore if */ | ||||
|             if (err) { | ||||
|                 return callback(err); | ||||
|             } | ||||
| 
 | ||||
|             callback(null, stat.mtime, cachedPrecision); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     // Set mtime by ceiling Date.now() to seconds + 5ms so that it's "not on the second"
 | ||||
|     const mtime = new Date((Math.ceil(Date.now() / 1000) * 1000) + 5); | ||||
| 
 | ||||
|     fs.utimes(file, mtime, mtime, (err) => { | ||||
|         /* istanbul ignore if */ | ||||
|         if (err) { | ||||
|             return callback(err); | ||||
|         } | ||||
| 
 | ||||
|         fs.stat(file, (err, stat) => { | ||||
|             /* istanbul ignore if */ | ||||
|             if (err) { | ||||
|                 return callback(err); | ||||
|             } | ||||
| 
 | ||||
|             const precision = stat.mtime.getTime() % 1000 === 0 ? 's' : 'ms'; | ||||
| 
 | ||||
|             // Cache the precision in a non-enumerable way
 | ||||
|             Object.defineProperty(fs, cacheSymbol, { value: precision }); | ||||
| 
 | ||||
|             callback(null, stat.mtime, precision); | ||||
|         }); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| function getMtime(precision) { | ||||
|     let now = Date.now(); | ||||
| 
 | ||||
|     if (precision === 's') { | ||||
|         now = Math.ceil(now / 1000) * 1000; | ||||
|     } | ||||
| 
 | ||||
|     return new Date(now); | ||||
| } | ||||
| 
 | ||||
| module.exports.probe = probe; | ||||
| module.exports.getMtime = getMtime; | ||||
							
								
								
									
										100
									
								
								server/libs/retry/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								server/libs/retry/index.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,100 @@ | ||||
| var RetryOperation = require('./retry_operation'); | ||||
| 
 | ||||
| exports.operation = function(options) { | ||||
|   var timeouts = exports.timeouts(options); | ||||
|   return new RetryOperation(timeouts, { | ||||
|       forever: options && options.forever, | ||||
|       unref: options && options.unref, | ||||
|       maxRetryTime: options && options.maxRetryTime | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| exports.timeouts = function(options) { | ||||
|   if (options instanceof Array) { | ||||
|     return [].concat(options); | ||||
|   } | ||||
| 
 | ||||
|   var opts = { | ||||
|     retries: 10, | ||||
|     factor: 2, | ||||
|     minTimeout: 1 * 1000, | ||||
|     maxTimeout: Infinity, | ||||
|     randomize: false | ||||
|   }; | ||||
|   for (var key in options) { | ||||
|     opts[key] = options[key]; | ||||
|   } | ||||
| 
 | ||||
|   if (opts.minTimeout > opts.maxTimeout) { | ||||
|     throw new Error('minTimeout is greater than maxTimeout'); | ||||
|   } | ||||
| 
 | ||||
|   var timeouts = []; | ||||
|   for (var i = 0; i < opts.retries; i++) { | ||||
|     timeouts.push(this.createTimeout(i, opts)); | ||||
|   } | ||||
| 
 | ||||
|   if (options && options.forever && !timeouts.length) { | ||||
|     timeouts.push(this.createTimeout(i, opts)); | ||||
|   } | ||||
| 
 | ||||
|   // sort the array numerically ascending
 | ||||
|   timeouts.sort(function(a,b) { | ||||
|     return a - b; | ||||
|   }); | ||||
| 
 | ||||
|   return timeouts; | ||||
| }; | ||||
| 
 | ||||
| exports.createTimeout = function(attempt, opts) { | ||||
|   var random = (opts.randomize) | ||||
|     ? (Math.random() + 1) | ||||
|     : 1; | ||||
| 
 | ||||
|   var timeout = Math.round(random * opts.minTimeout * Math.pow(opts.factor, attempt)); | ||||
|   timeout = Math.min(timeout, opts.maxTimeout); | ||||
| 
 | ||||
|   return timeout; | ||||
| }; | ||||
| 
 | ||||
| exports.wrap = function(obj, options, methods) { | ||||
|   if (options instanceof Array) { | ||||
|     methods = options; | ||||
|     options = null; | ||||
|   } | ||||
| 
 | ||||
|   if (!methods) { | ||||
|     methods = []; | ||||
|     for (var key in obj) { | ||||
|       if (typeof obj[key] === 'function') { | ||||
|         methods.push(key); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   for (var i = 0; i < methods.length; i++) { | ||||
|     var method   = methods[i]; | ||||
|     var original = obj[method]; | ||||
| 
 | ||||
|     obj[method] = function retryWrapper(original) { | ||||
|       var op       = exports.operation(options); | ||||
|       var args     = Array.prototype.slice.call(arguments, 1); | ||||
|       var callback = args.pop(); | ||||
| 
 | ||||
|       args.push(function(err) { | ||||
|         if (op.retry(err)) { | ||||
|           return; | ||||
|         } | ||||
|         if (err) { | ||||
|           arguments[0] = op.mainError(); | ||||
|         } | ||||
|         callback.apply(this, arguments); | ||||
|       }); | ||||
| 
 | ||||
|       op.attempt(function() { | ||||
|         original.apply(obj, args); | ||||
|       }); | ||||
|     }.bind(obj, original); | ||||
|     obj[method].options = options; | ||||
|   } | ||||
| }; | ||||
							
								
								
									
										158
									
								
								server/libs/retry/retry_operation.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								server/libs/retry/retry_operation.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,158 @@ | ||||
| function RetryOperation(timeouts, options) { | ||||
|   // Compatibility for the old (timeouts, retryForever) signature
 | ||||
|   if (typeof options === 'boolean') { | ||||
|     options = { forever: options }; | ||||
|   } | ||||
| 
 | ||||
|   this._originalTimeouts = JSON.parse(JSON.stringify(timeouts)); | ||||
|   this._timeouts = timeouts; | ||||
|   this._options = options || {}; | ||||
|   this._maxRetryTime = options && options.maxRetryTime || Infinity; | ||||
|   this._fn = null; | ||||
|   this._errors = []; | ||||
|   this._attempts = 1; | ||||
|   this._operationTimeout = null; | ||||
|   this._operationTimeoutCb = null; | ||||
|   this._timeout = null; | ||||
|   this._operationStart = null; | ||||
| 
 | ||||
|   if (this._options.forever) { | ||||
|     this._cachedTimeouts = this._timeouts.slice(0); | ||||
|   } | ||||
| } | ||||
| module.exports = RetryOperation; | ||||
| 
 | ||||
| RetryOperation.prototype.reset = function() { | ||||
|   this._attempts = 1; | ||||
|   this._timeouts = this._originalTimeouts; | ||||
| } | ||||
| 
 | ||||
| RetryOperation.prototype.stop = function() { | ||||
|   if (this._timeout) { | ||||
|     clearTimeout(this._timeout); | ||||
|   } | ||||
| 
 | ||||
|   this._timeouts       = []; | ||||
|   this._cachedTimeouts = null; | ||||
| }; | ||||
| 
 | ||||
| RetryOperation.prototype.retry = function(err) { | ||||
|   if (this._timeout) { | ||||
|     clearTimeout(this._timeout); | ||||
|   } | ||||
| 
 | ||||
|   if (!err) { | ||||
|     return false; | ||||
|   } | ||||
|   var currentTime = new Date().getTime(); | ||||
|   if (err && currentTime - this._operationStart >= this._maxRetryTime) { | ||||
|     this._errors.unshift(new Error('RetryOperation timeout occurred')); | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   this._errors.push(err); | ||||
| 
 | ||||
|   var timeout = this._timeouts.shift(); | ||||
|   if (timeout === undefined) { | ||||
|     if (this._cachedTimeouts) { | ||||
|       // retry forever, only keep last error
 | ||||
|       this._errors.splice(this._errors.length - 1, this._errors.length); | ||||
|       this._timeouts = this._cachedTimeouts.slice(0); | ||||
|       timeout = this._timeouts.shift(); | ||||
|     } else { | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   var self = this; | ||||
|   var timer = setTimeout(function() { | ||||
|     self._attempts++; | ||||
| 
 | ||||
|     if (self._operationTimeoutCb) { | ||||
|       self._timeout = setTimeout(function() { | ||||
|         self._operationTimeoutCb(self._attempts); | ||||
|       }, self._operationTimeout); | ||||
| 
 | ||||
|       if (self._options.unref) { | ||||
|           self._timeout.unref(); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     self._fn(self._attempts); | ||||
|   }, timeout); | ||||
| 
 | ||||
|   if (this._options.unref) { | ||||
|       timer.unref(); | ||||
|   } | ||||
| 
 | ||||
|   return true; | ||||
| }; | ||||
| 
 | ||||
| RetryOperation.prototype.attempt = function(fn, timeoutOps) { | ||||
|   this._fn = fn; | ||||
| 
 | ||||
|   if (timeoutOps) { | ||||
|     if (timeoutOps.timeout) { | ||||
|       this._operationTimeout = timeoutOps.timeout; | ||||
|     } | ||||
|     if (timeoutOps.cb) { | ||||
|       this._operationTimeoutCb = timeoutOps.cb; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   var self = this; | ||||
|   if (this._operationTimeoutCb) { | ||||
|     this._timeout = setTimeout(function() { | ||||
|       self._operationTimeoutCb(); | ||||
|     }, self._operationTimeout); | ||||
|   } | ||||
| 
 | ||||
|   this._operationStart = new Date().getTime(); | ||||
| 
 | ||||
|   this._fn(this._attempts); | ||||
| }; | ||||
| 
 | ||||
| RetryOperation.prototype.try = function(fn) { | ||||
|   console.log('Using RetryOperation.try() is deprecated'); | ||||
|   this.attempt(fn); | ||||
| }; | ||||
| 
 | ||||
| RetryOperation.prototype.start = function(fn) { | ||||
|   console.log('Using RetryOperation.start() is deprecated'); | ||||
|   this.attempt(fn); | ||||
| }; | ||||
| 
 | ||||
| RetryOperation.prototype.start = RetryOperation.prototype.try; | ||||
| 
 | ||||
| RetryOperation.prototype.errors = function() { | ||||
|   return this._errors; | ||||
| }; | ||||
| 
 | ||||
| RetryOperation.prototype.attempts = function() { | ||||
|   return this._attempts; | ||||
| }; | ||||
| 
 | ||||
| RetryOperation.prototype.mainError = function() { | ||||
|   if (this._errors.length === 0) { | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   var counts = {}; | ||||
|   var mainError = null; | ||||
|   var mainErrorCount = 0; | ||||
| 
 | ||||
|   for (var i = 0; i < this._errors.length; i++) { | ||||
|     var error = this._errors[i]; | ||||
|     var message = error.message; | ||||
|     var count = (counts[message] || 0) + 1; | ||||
| 
 | ||||
|     counts[message] = count; | ||||
| 
 | ||||
|     if (count >= mainErrorCount) { | ||||
|       mainError = error; | ||||
|       mainErrorCount = count; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return mainError; | ||||
| }; | ||||
							
								
								
									
										202
									
								
								server/libs/signalExit/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								server/libs/signalExit/index.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,202 @@ | ||||
| // Note: since nyc uses this module to output coverage, any lines
 | ||||
| // that are in the direct sync flow of nyc's outputCoverage are
 | ||||
| // ignored, since we can never get coverage for them.
 | ||||
| // grab a reference to node's real process object right away
 | ||||
| var process = global.process | ||||
| 
 | ||||
| const processOk = function (process) { | ||||
|   return process && | ||||
|     typeof process === 'object' && | ||||
|     typeof process.removeListener === 'function' && | ||||
|     typeof process.emit === 'function' && | ||||
|     typeof process.reallyExit === 'function' && | ||||
|     typeof process.listeners === 'function' && | ||||
|     typeof process.kill === 'function' && | ||||
|     typeof process.pid === 'number' && | ||||
|     typeof process.on === 'function' | ||||
| } | ||||
| 
 | ||||
| // some kind of non-node environment, just no-op
 | ||||
| /* istanbul ignore if */ | ||||
| if (!processOk(process)) { | ||||
|   module.exports = function () { | ||||
|     return function () {} | ||||
|   } | ||||
| } else { | ||||
|   var assert = require('assert') | ||||
|   var signals = require('./signals.js') | ||||
|   var isWin = /^win/i.test(process.platform) | ||||
| 
 | ||||
|   var EE = require('events') | ||||
|   /* istanbul ignore if */ | ||||
|   if (typeof EE !== 'function') { | ||||
|     EE = EE.EventEmitter | ||||
|   } | ||||
| 
 | ||||
|   var emitter | ||||
|   if (process.__signal_exit_emitter__) { | ||||
|     emitter = process.__signal_exit_emitter__ | ||||
|   } else { | ||||
|     emitter = process.__signal_exit_emitter__ = new EE() | ||||
|     emitter.count = 0 | ||||
|     emitter.emitted = {} | ||||
|   } | ||||
| 
 | ||||
|   // Because this emitter is a global, we have to check to see if a
 | ||||
|   // previous version of this library failed to enable infinite listeners.
 | ||||
|   // I know what you're about to say.  But literally everything about
 | ||||
|   // signal-exit is a compromise with evil.  Get used to it.
 | ||||
|   if (!emitter.infinite) { | ||||
|     emitter.setMaxListeners(Infinity) | ||||
|     emitter.infinite = true | ||||
|   } | ||||
| 
 | ||||
|   module.exports = function (cb, opts) { | ||||
|     /* istanbul ignore if */ | ||||
|     if (!processOk(global.process)) { | ||||
|       return function () {} | ||||
|     } | ||||
|     assert.equal(typeof cb, 'function', 'a callback must be provided for exit handler') | ||||
| 
 | ||||
|     if (loaded === false) { | ||||
|       load() | ||||
|     } | ||||
| 
 | ||||
|     var ev = 'exit' | ||||
|     if (opts && opts.alwaysLast) { | ||||
|       ev = 'afterexit' | ||||
|     } | ||||
| 
 | ||||
|     var remove = function () { | ||||
|       emitter.removeListener(ev, cb) | ||||
|       if (emitter.listeners('exit').length === 0 && | ||||
|           emitter.listeners('afterexit').length === 0) { | ||||
|         unload() | ||||
|       } | ||||
|     } | ||||
|     emitter.on(ev, cb) | ||||
| 
 | ||||
|     return remove | ||||
|   } | ||||
| 
 | ||||
|   var unload = function unload () { | ||||
|     if (!loaded || !processOk(global.process)) { | ||||
|       return | ||||
|     } | ||||
|     loaded = false | ||||
| 
 | ||||
|     signals.forEach(function (sig) { | ||||
|       try { | ||||
|         process.removeListener(sig, sigListeners[sig]) | ||||
|       } catch (er) {} | ||||
|     }) | ||||
|     process.emit = originalProcessEmit | ||||
|     process.reallyExit = originalProcessReallyExit | ||||
|     emitter.count -= 1 | ||||
|   } | ||||
|   module.exports.unload = unload | ||||
| 
 | ||||
|   var emit = function emit (event, code, signal) { | ||||
|     /* istanbul ignore if */ | ||||
|     if (emitter.emitted[event]) { | ||||
|       return | ||||
|     } | ||||
|     emitter.emitted[event] = true | ||||
|     emitter.emit(event, code, signal) | ||||
|   } | ||||
| 
 | ||||
|   // { <signal>: <listener fn>, ... }
 | ||||
|   var sigListeners = {} | ||||
|   signals.forEach(function (sig) { | ||||
|     sigListeners[sig] = function listener () { | ||||
|       /* istanbul ignore if */ | ||||
|       if (!processOk(global.process)) { | ||||
|         return | ||||
|       } | ||||
|       // If there are no other listeners, an exit is coming!
 | ||||
|       // Simplest way: remove us and then re-send the signal.
 | ||||
|       // We know that this will kill the process, so we can
 | ||||
|       // safely emit now.
 | ||||
|       var listeners = process.listeners(sig) | ||||
|       if (listeners.length === emitter.count) { | ||||
|         unload() | ||||
|         emit('exit', null, sig) | ||||
|         /* istanbul ignore next */ | ||||
|         emit('afterexit', null, sig) | ||||
|         /* istanbul ignore next */ | ||||
|         if (isWin && sig === 'SIGHUP') { | ||||
|           // "SIGHUP" throws an `ENOSYS` error on Windows,
 | ||||
|           // so use a supported signal instead
 | ||||
|           sig = 'SIGINT' | ||||
|         } | ||||
|         /* istanbul ignore next */ | ||||
|         process.kill(process.pid, sig) | ||||
|       } | ||||
|     } | ||||
|   }) | ||||
| 
 | ||||
|   module.exports.signals = function () { | ||||
|     return signals | ||||
|   } | ||||
| 
 | ||||
|   var loaded = false | ||||
| 
 | ||||
|   var load = function load () { | ||||
|     if (loaded || !processOk(global.process)) { | ||||
|       return | ||||
|     } | ||||
|     loaded = true | ||||
| 
 | ||||
|     // This is the number of onSignalExit's that are in play.
 | ||||
|     // It's important so that we can count the correct number of
 | ||||
|     // listeners on signals, and don't wait for the other one to
 | ||||
|     // handle it instead of us.
 | ||||
|     emitter.count += 1 | ||||
| 
 | ||||
|     signals = signals.filter(function (sig) { | ||||
|       try { | ||||
|         process.on(sig, sigListeners[sig]) | ||||
|         return true | ||||
|       } catch (er) { | ||||
|         return false | ||||
|       } | ||||
|     }) | ||||
| 
 | ||||
|     process.emit = processEmit | ||||
|     process.reallyExit = processReallyExit | ||||
|   } | ||||
|   module.exports.load = load | ||||
| 
 | ||||
|   var originalProcessReallyExit = process.reallyExit | ||||
|   var processReallyExit = function processReallyExit (code) { | ||||
|     /* istanbul ignore if */ | ||||
|     if (!processOk(global.process)) { | ||||
|       return | ||||
|     } | ||||
|     process.exitCode = code || /* istanbul ignore next */ 0 | ||||
|     emit('exit', process.exitCode, null) | ||||
|     /* istanbul ignore next */ | ||||
|     emit('afterexit', process.exitCode, null) | ||||
|     /* istanbul ignore next */ | ||||
|     originalProcessReallyExit.call(process, process.exitCode) | ||||
|   } | ||||
| 
 | ||||
|   var originalProcessEmit = process.emit | ||||
|   var processEmit = function processEmit (ev, arg) { | ||||
|     if (ev === 'exit' && processOk(global.process)) { | ||||
|       /* istanbul ignore else */ | ||||
|       if (arg !== undefined) { | ||||
|         process.exitCode = arg | ||||
|       } | ||||
|       var ret = originalProcessEmit.apply(this, arguments) | ||||
|       /* istanbul ignore next */ | ||||
|       emit('exit', process.exitCode, null) | ||||
|       /* istanbul ignore next */ | ||||
|       emit('afterexit', process.exitCode, null) | ||||
|       /* istanbul ignore next */ | ||||
|       return ret | ||||
|     } else { | ||||
|       return originalProcessEmit.apply(this, arguments) | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										53
									
								
								server/libs/signalExit/signals.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								server/libs/signalExit/signals.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | ||||
| // This is not the set of all possible signals.
 | ||||
| //
 | ||||
| // It IS, however, the set of all signals that trigger
 | ||||
| // an exit on either Linux or BSD systems.  Linux is a
 | ||||
| // superset of the signal names supported on BSD, and
 | ||||
| // the unknown signals just fail to register, so we can
 | ||||
| // catch that easily enough.
 | ||||
| //
 | ||||
| // Don't bother with SIGKILL.  It's uncatchable, which
 | ||||
| // means that we can't fire any callbacks anyway.
 | ||||
| //
 | ||||
| // If a user does happen to register a handler on a non-
 | ||||
| // fatal signal like SIGWINCH or something, and then
 | ||||
| // exit, it'll end up firing `process.emit('exit')`, so
 | ||||
| // the handler will be fired anyway.
 | ||||
| //
 | ||||
| // SIGBUS, SIGFPE, SIGSEGV and SIGILL, when not raised
 | ||||
| // artificially, inherently leave the process in a
 | ||||
| // state from which it is not safe to try and enter JS
 | ||||
| // listeners.
 | ||||
| module.exports = [ | ||||
|   'SIGABRT', | ||||
|   'SIGALRM', | ||||
|   'SIGHUP', | ||||
|   'SIGINT', | ||||
|   'SIGTERM' | ||||
| ] | ||||
| 
 | ||||
| if (process.platform !== 'win32') { | ||||
|   module.exports.push( | ||||
|     'SIGVTALRM', | ||||
|     'SIGXCPU', | ||||
|     'SIGXFSZ', | ||||
|     'SIGUSR2', | ||||
|     'SIGTRAP', | ||||
|     'SIGSYS', | ||||
|     'SIGQUIT', | ||||
|     'SIGIOT' | ||||
|     // should detect profiler and enable/disable accordingly.
 | ||||
|     // see #21
 | ||||
|     // 'SIGPROF'
 | ||||
|   ) | ||||
| } | ||||
| 
 | ||||
| if (process.platform === 'linux') { | ||||
|   module.exports.push( | ||||
|     'SIGIO', | ||||
|     'SIGPOLL', | ||||
|     'SIGPWR', | ||||
|     'SIGSTKFLT', | ||||
|     'SIGUNUSED' | ||||
|   ) | ||||
| } | ||||
| @ -1,6 +1,6 @@ | ||||
| const Path = require('path') | ||||
| const fs = require('fs-extra') | ||||
| const njodb = require('../njodb') | ||||
| const njodb = require('../libs/njodb') | ||||
| 
 | ||||
| const { SupportedEbookTypes } = require('./globals') | ||||
| const { PlayMethod } = require('./constants') | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user