xprezzo-on-finished
Advanced tools
Comparing version
@@ -5,6 +5,16 @@ 1.0.0 / 2020-10-05 | ||
* depds updated | ||
* depds eslint updated to 8.15.0 | ||
* depds eslint-config-standard to 17.0.0 | ||
* depds eslint-plugin-import to 2.26.0 | ||
* depds mocha to 10.0.0 | ||
1.0.0 / 2020-10-05 | ||
================== | ||
* depds updated | ||
1.0.0 / 2020-10-05 | ||
================== | ||
* Initial release |
219
index.js
/*! | ||
* xprezzo-on-finished | ||
* Copyright(c) 2020 Ben Ajenoui <info@seohero.io> | ||
* Copyright(c) 2022 Cloudgen Wong <cloudgen.wong@gmail.com> | ||
* MIT Licensed | ||
@@ -33,18 +33,17 @@ */ | ||
*/ | ||
let isFinished = (msg) => { | ||
const socket = msg.socket | ||
function isFinished (msg) { | ||
const socket = msg.socket | ||
if (typeof msg.finished === 'boolean') { | ||
// OutgoingMessage | ||
return Boolean(msg.finished || (socket && !socket.writable)) | ||
} | ||
if (typeof msg.finished === 'boolean') { | ||
// OutgoingMessage | ||
return Boolean(msg.finished || (socket && !socket.writable)) | ||
} | ||
if (typeof msg.complete === 'boolean') { | ||
// IncomingMessage | ||
return Boolean(msg.upgrade || !socket || !socket.readable || (msg.complete && !msg.readable)) | ||
} | ||
if (typeof msg.complete === 'boolean') { | ||
// IncomingMessage | ||
return Boolean(msg.upgrade || !socket || !socket.readable || (msg.complete && !msg.readable)) | ||
} | ||
// don't know | ||
return undefined | ||
// don't know | ||
return undefined | ||
} | ||
@@ -60,110 +59,63 @@ | ||
function attachFinishedListener (msg, callback) { | ||
let eeSocket | ||
let finished = false | ||
let attachFinishedListener =(msg, callback) => { | ||
let eeSocket | ||
let finished = false | ||
let onFinish = (error) => { | ||
eeMsg.cancel() | ||
eeSocket.cancel() | ||
function onFinish (error) { | ||
eeMsg.cancel() | ||
eeSocket.cancel() | ||
finished = true | ||
callback(error) | ||
} | ||
finished = true | ||
callback(error) | ||
} | ||
// finished on first message event | ||
const eeMsg = eeSocket = first([[msg, 'end', 'finish']], onFinish) | ||
// finished on first message event | ||
const eeMsg = eeSocket = first([[msg, 'end', 'finish']], onFinish) | ||
let onSocket = (socket) => { | ||
// remove listener | ||
msg.removeListener('socket', onSocket) | ||
function onSocket (socket) { | ||
// remove listener | ||
msg.removeListener('socket', onSocket) | ||
if (finished) return | ||
if (eeMsg !== eeSocket) return | ||
if (finished) return | ||
if (eeMsg !== eeSocket) return | ||
// finished on first socket event | ||
eeSocket = first([[socket, 'error', 'close']], onFinish) | ||
} | ||
// finished on first socket event | ||
eeSocket = first([[socket, 'error', 'close']], onFinish) | ||
} | ||
if (msg.socket) { | ||
// socket already assigned | ||
onSocket(msg.socket) | ||
return | ||
} | ||
if (msg.socket) { | ||
// socket already assigned | ||
onSocket(msg.socket) | ||
return | ||
} | ||
// wait for socket to be assigned | ||
msg.on('socket', onSocket) | ||
// wait for socket to be assigned | ||
msg.on('socket', onSocket) | ||
if (msg.socket === undefined) { | ||
// istanbul ignore next: node.js 0.8 patch | ||
patchAssignSocket(msg, onSocket) | ||
} | ||
if (msg.socket === undefined) { | ||
// to be remove soon: | ||
// Patch ServerResponse.prototype.assignSocket for node.js 0.8. | ||
// istanbul ignore next: node.js 0.8 patch | ||
((res, callback) => { | ||
const assignSocket = res.assignSocket | ||
if (typeof assignSocket !== 'function') return | ||
// res.on('socket', callback) is broken in 0.8 | ||
res.assignSocket = (socket) => { | ||
assignSocket.call(this, socket) | ||
callback(socket) | ||
} | ||
})(msg, onSocket) | ||
} | ||
} | ||
/** | ||
* Attach the listener to the message. | ||
* | ||
* @param {object} msg | ||
* @return {function} | ||
* @private | ||
*/ | ||
function attachListener (msg, listener) { | ||
let attached = msg.__onFinished | ||
// create a private single listener with queue | ||
if (!attached || !attached.queue) { | ||
attached = msg.__onFinished = createListener(msg) | ||
attachFinishedListener(msg, attached) | ||
} | ||
const queue = __queue__.get(attached) | ||
queue.push(listener) | ||
__queue__.set(attached, queue) | ||
} | ||
/** | ||
* Create listener on message. | ||
* | ||
* @param {object} msg | ||
* @return {function} | ||
* @private | ||
*/ | ||
function createListener (msg) { | ||
function listener (err) { | ||
const queue = __queue__.get(listener) | ||
if (msg.__onFinished === listener) msg.__onFinished = null | ||
if (!queue) return | ||
__queue__.set(listener, null) | ||
for (let i = 0; i < queue.length; i++) { | ||
queue[i](err, msg) | ||
let asyncHooks = (() => { | ||
try { | ||
return require('async_hooks') | ||
} catch (e) { | ||
return {} | ||
} | ||
} | ||
__queue__.set(listener, []) | ||
})() | ||
return listener | ||
} | ||
/** | ||
* Patch ServerResponse.prototype.assignSocket for node.js 0.8. | ||
* | ||
* @param {ServerResponse} res | ||
* @param {function} callback | ||
* @private | ||
*/ | ||
// istanbul ignore next: node.js 0.8 patch | ||
function patchAssignSocket (res, callback) { | ||
const assignSocket = res.assignSocket | ||
if (typeof assignSocket !== 'function') return | ||
// res.on('socket', callback) is broken in 0.8 | ||
res.assignSocket = function _assignSocket (socket) { | ||
assignSocket.call(this, socket) | ||
callback(socket) | ||
} | ||
} | ||
/** | ||
* Module exports. | ||
@@ -183,13 +135,48 @@ * @public | ||
module.exports = (msg, listener) => { | ||
if (isFinished(msg) !== false) { | ||
defer(listener, null, msg) | ||
return msg | ||
} | ||
if (isFinished(msg) !== false) { | ||
defer(listener, null, msg) | ||
return msg | ||
} | ||
// attach the listener to the message | ||
attachListener(msg, listener) | ||
// attach the listener to the message | ||
((msg, listener) => { | ||
let attached = msg.__onFinishe | ||
let res | ||
return msg | ||
// create anonymous resource | ||
if (asyncHooks.AsyncResource) { | ||
res = new asyncHooks.AsyncResource(listener.name || 'bound-anonymous-fn') | ||
} | ||
// apply to compatible node.js on | ||
if (res && res.runInAsyncScope) { | ||
listener = res.runInAsyncScope.bind(res, listener, null) | ||
} | ||
// create a private single listener with queue | ||
if (!attached || !attached.queue) { | ||
// Create listener on message | ||
attached = msg.__onFinished = ((msg) =>{ | ||
let listener = (err) => { | ||
const queue = __queue__.get(listener) | ||
if (msg.__onFinished === listener) msg.__onFinished = null | ||
if (!queue) return | ||
__queue__.set(listener, null) | ||
for (let i = 0; i < queue.length; i++) { | ||
queue[i](err, msg) | ||
} | ||
} | ||
__queue__.set(listener, []) | ||
return listener | ||
})(msg) | ||
attachFinishedListener(msg, attached) | ||
} | ||
const queue = __queue__.get(attached) | ||
queue.push(listener) | ||
__queue__.set(attached, queue) | ||
})(msg, listener) | ||
return msg | ||
} | ||
module.exports.isFinished = isFinished |
{ | ||
"name": "xprezzo-on-finished", | ||
"description": "Execute a callback when a request closes, finishes, or errors", | ||
"version": "1.1.1", | ||
"author": "Ben Ajenoui <info@seohero.io>", | ||
"version": "1.1.2", | ||
"author": "Cloudgen Wong <cloudgen.wong@gmail.com>", | ||
"license": "MIT", | ||
@@ -10,10 +10,9 @@ "repository": "xprezzo/xprezzo-on-finished", | ||
"devDependencies": { | ||
"eslint": "7.11.0", | ||
"eslint-config-standard": "14.1.1", | ||
"eslint-plugin-import": "2.22.1", | ||
"eslint": "8.15.0", | ||
"eslint-config-standard": "17.0.0", | ||
"eslint-plugin-import": "2.26.0", | ||
"eslint-plugin-markdown": "1.0.2", | ||
"eslint-plugin-node": "11.1.0", | ||
"eslint-plugin-promise": "4.2.1", | ||
"eslint-plugin-standard": "4.0.1", | ||
"mocha": "8.2.0", | ||
"eslint-plugin-promise": "6.0.0", | ||
"mocha": "10.0.0", | ||
"nyc": "15.1.0" | ||
@@ -20,0 +19,0 @@ }, |
@@ -5,16 +5,3 @@ # xprezzo-on-finished | ||
## Philosophy of Xprezzo | ||
Problems faced: | ||
* Too many requires which creates problem when project grow | ||
* The dependencies update are slow | ||
* Test cases of difficult to design | ||
How Xprezzo try to tackle those problems: | ||
* Useful internal libraries/packages are exposed | ||
* Merge small libraries into a larger one. | ||
* Provide easy to use test framework | ||
## Install | ||
@@ -163,3 +150,3 @@ | ||
Xprezzo and related projects are maintained by [Ben Ajenoui](mailto:info@seohero.io) and sponsored by [SEO Hero](https://www.seohero.io). | ||
Xprezzo and related projects are maintained by [Cloudgen Wong](mailto:cloudgen.wong@gmail.com). | ||
@@ -166,0 +153,0 @@ ## License |
Sorry, the diff of this file is not supported yet
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Found 1 instance in 1 package
AI-detected possible typosquat
Supply chain riskAI has identified this package as a potential typosquat of a more popular package. This suggests that the package may be intentionally mimicking another package's name, description, or other metadata.
Found 1 instance in 1 package
13099
2.76%8
-11.11%0
-100%215
-2.71%154
-7.78%2
100%