mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-11-04 03:17:00 -05: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",
 | 
					        "libgen": "^2.1.0",
 | 
				
			||||||
        "node-ffprobe": "^3.0.0",
 | 
					        "node-ffprobe": "^3.0.0",
 | 
				
			||||||
        "node-stream-zip": "^1.15.0",
 | 
					        "node-stream-zip": "^1.15.0",
 | 
				
			||||||
        "proper-lockfile": "^4.1.2",
 | 
					 | 
				
			||||||
        "recursive-readdir-async": "^1.1.8",
 | 
					        "recursive-readdir-async": "^1.1.8",
 | 
				
			||||||
        "socket.io": "^4.4.1",
 | 
					        "socket.io": "^4.4.1",
 | 
				
			||||||
        "xml2js": "^0.4.23"
 | 
					        "xml2js": "^0.4.23"
 | 
				
			||||||
@ -1488,16 +1487,6 @@
 | 
				
			|||||||
      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
 | 
				
			||||||
      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
 | 
					      "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": {
 | 
					    "node_modules/proxy-addr": {
 | 
				
			||||||
      "version": "2.0.7",
 | 
					      "version": "2.0.7",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
 | 
				
			||||||
@ -1608,14 +1597,6 @@
 | 
				
			|||||||
        "lowercase-keys": "^2.0.0"
 | 
					        "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": {
 | 
					    "node_modules/safe-buffer": {
 | 
				
			||||||
      "version": "5.2.1",
 | 
					      "version": "5.2.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
 | 
				
			||||||
@ -1713,11 +1694,6 @@
 | 
				
			|||||||
        "url": "https://github.com/sponsors/ljharb"
 | 
					        "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": {
 | 
					    "node_modules/socket.io": {
 | 
				
			||||||
      "version": "4.5.1",
 | 
					      "version": "4.5.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.1.tgz",
 | 
					      "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",
 | 
					      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
 | 
				
			||||||
      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
 | 
					      "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": {
 | 
					    "proxy-addr": {
 | 
				
			||||||
      "version": "2.0.7",
 | 
					      "version": "2.0.7",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
 | 
				
			||||||
@ -3177,11 +3143,6 @@
 | 
				
			|||||||
        "lowercase-keys": "^2.0.0"
 | 
					        "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": {
 | 
					    "safe-buffer": {
 | 
				
			||||||
      "version": "5.2.1",
 | 
					      "version": "5.2.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
 | 
				
			||||||
@ -3255,11 +3216,6 @@
 | 
				
			|||||||
        "object-inspect": "^1.9.0"
 | 
					        "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": {
 | 
					    "socket.io": {
 | 
				
			||||||
      "version": "4.5.1",
 | 
					      "version": "4.5.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.1.tgz",
 | 
				
			||||||
 | 
				
			|||||||
@ -43,7 +43,6 @@
 | 
				
			|||||||
    "libgen": "^2.1.0",
 | 
					    "libgen": "^2.1.0",
 | 
				
			||||||
    "node-ffprobe": "^3.0.0",
 | 
					    "node-ffprobe": "^3.0.0",
 | 
				
			||||||
    "node-stream-zip": "^1.15.0",
 | 
					    "node-stream-zip": "^1.15.0",
 | 
				
			||||||
    "proper-lockfile": "^4.1.2",
 | 
					 | 
				
			||||||
    "recursive-readdir-async": "^1.1.8",
 | 
					    "recursive-readdir-async": "^1.1.8",
 | 
				
			||||||
    "socket.io": "^4.4.1",
 | 
					    "socket.io": "^4.4.1",
 | 
				
			||||||
    "xml2js": "^0.4.23"
 | 
					    "xml2js": "^0.4.23"
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,5 @@
 | 
				
			|||||||
const Path = require('path')
 | 
					const Path = require('path')
 | 
				
			||||||
const njodb = require('./njodb')
 | 
					const njodb = require('./libs/njodb')
 | 
				
			||||||
const jwt = require('jsonwebtoken')
 | 
					 | 
				
			||||||
const Logger = require('./Logger')
 | 
					const Logger = require('./Logger')
 | 
				
			||||||
const { version } = require('../package.json')
 | 
					const { version } = require('../package.json')
 | 
				
			||||||
const LibraryItem = require('./objects/LibraryItem')
 | 
					const LibraryItem = require('./objects/LibraryItem')
 | 
				
			||||||
 | 
				
			|||||||
@ -27,7 +27,7 @@ const {
 | 
				
			|||||||
    checkSync,
 | 
					    checkSync,
 | 
				
			||||||
    lock,
 | 
					    lock,
 | 
				
			||||||
    lockSync
 | 
					    lockSync
 | 
				
			||||||
} = require("proper-lockfile");
 | 
					} = require("../properLockfile");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const {
 | 
					const {
 | 
				
			||||||
    deleteFile,
 | 
					    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 Path = require('path')
 | 
				
			||||||
const fs = require('fs-extra')
 | 
					const fs = require('fs-extra')
 | 
				
			||||||
const njodb = require('../njodb')
 | 
					const njodb = require('../libs/njodb')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const { SupportedEbookTypes } = require('./globals')
 | 
					const { SupportedEbookTypes } = require('./globals')
 | 
				
			||||||
const { PlayMethod } = require('./constants')
 | 
					const { PlayMethod } = require('./constants')
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user