Remove promise-to-callback, reimplement createAsyncMiddleware (#46)

* remove promise-to-callback, reimplement createAsyncMiddleware

* fix middleware plural copy
This commit is contained in:
Erik Marks
2020-07-27 13:42:29 -07:00
committed by GitHub
parent 776a07db30
commit 042e17e413
4 changed files with 60 additions and 48 deletions

View File

@@ -17,7 +17,6 @@
},
"dependencies": {
"eth-rpc-errors": "^2.1.1",
"promise-to-callback": "^1.0.0",
"safe-event-emitter": "^1.0.1"
},
"devDependencies": {

View File

@@ -1,39 +1,60 @@
const promiseToCallback = require('promise-to-callback')
/**
* JsonRpcEngine only accepts callback-based middleware directly.
* createAsyncMiddleware exists to enable consumers to pass in async middleware
* functions.
*
* Async middleware have no "end" function. Instead, they "end" if they return
* without calling "next". Rather than passing in explicit return handlers,
* async middleware can simply await "next", and perform operations on the
* response object when execution resumes.
*
* To accomplish this, createAsyncMiddleware passes the async middleware a
* wrapped "next" function. That function calls the internal JsonRpcEngine
* "next" function with a return handler that resolves a promise when called.
*
* The return handler will always be called. Its resolution of the promise
* enables the control flow described above.
*/
module.exports = function createAsyncMiddleware (asyncMiddleware) {
return (req, res, next, end) => {
let nextDonePromise = null
const finishedPromise = asyncMiddleware(req, res, getNextPromise)
promiseToCallback(finishedPromise)((err) => {
// async middleware ended
if (nextDonePromise) {
// next handler was called - complete nextHandler
promiseToCallback(nextDonePromise)((nextErr, nextHandlerSignalDone) => {
// nextErr is only present if something went really wrong
// if an error is thrown after `await next()` it appears as `err` and not `nextErr`
if (nextErr) {
console.error(nextErr)
return end(nextErr)
}
nextHandlerSignalDone(err)
return undefined
})
} else {
// next handler was not called - complete middleware
end(err)
}
// nextPromise is the key to the implementation
// it is resolved by the return handler passed to the
// "next" function
let resolveNextPromise
const nextPromise = new Promise((resolve) => {
resolveNextPromise = resolve
})
async function getNextPromise () {
nextDonePromise = getNextDoneCallback()
await nextDonePromise
return undefined
let returnHandlerCallback, nextWasCalled
const asyncNext = async () => {
nextWasCalled = true
next((callback) => { // eslint-disable-line callback-return
returnHandlerCallback = callback
resolveNextPromise()
})
await nextPromise
}
function getNextDoneCallback () {
return new Promise((resolve) => {
next((cb) => resolve(cb))
asyncMiddleware(req, res, asyncNext)
.then(async () => {
if (nextWasCalled) {
await nextPromise // we must wait until the return handler is called
returnHandlerCallback(null)
} else {
end(null)
}
})
.catch((error) => {
if (returnHandlerCallback) {
returnHandlerCallback(error)
} else {
end(error)
}
})
}
}
}

View File

@@ -92,7 +92,7 @@ describe('createAsyncMiddleware tests', function () {
})
})
it('doesnt await next', function (done) {
it('doesn\'t await next', function (done) {
const engine = new RpcEngine()
engine.push(createAsyncMiddleware(async (_req, _res, next) => {

View File

@@ -1131,11 +1131,6 @@ is-extglob@^2.1.1:
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
is-fn@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-fn/-/is-fn-1.0.0.tgz#9543d5de7bcf5b08a22ec8a20bae6e286d510d8c"
integrity sha1-lUPV3nvPWwiiLsiiC65uKG1RDYw=
is-fullwidth-code-point@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
@@ -1778,14 +1773,6 @@ progress@^2.0.0:
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
promise-to-callback@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/promise-to-callback/-/promise-to-callback-1.0.0.tgz#5d2a749010bfb67d963598fcd3960746a68feef7"
integrity sha1-XSp0kBC/tn2WNZj805YHRqaP7vc=
dependencies:
is-fn "^1.0.0"
set-immediate-shim "^1.0.1"
punycode@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
@@ -1934,10 +1921,15 @@ set-blocking@^2.0.0:
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
set-immediate-shim@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
integrity sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=
set-value@^2.0.0, set-value@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==
dependencies:
extend-shallow "^2.0.1"
is-extendable "^0.1.1"
is-plain-object "^2.0.3"
split-string "^3.0.1"
shebang-command@^1.2.0:
version "1.2.0"