-
Notifications
You must be signed in to change notification settings - Fork 490
refactor(@embark/blockchain_process): remove http-proxy-middleware #1195
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
bdfb14f to
299c3fe
Compare
This PR replaces #1166. The "stuck sockets" bug is addressed in #1195 so there is no longer a need to use timeouts. However a few aspects of the original PR are still useful, and lessons learned from #1166, #1181, and #1195 can be put to good use. Use a websocket client from the `ws` package when pinging websocket endpoints instead of manually building a request header. The `'upgrade'` event being listened for was never actually firing; and though a response was received for those pings, the response messages indicated problems with those requests. It seems cleaner to use a proper websocket client and callback success upon the `ws` client's `'open'` event. Abstract error and success handling across websocket and http pings. Report network errors other than `ECONNREFUSED`. Only `ECONNREFUSED` is expected, as that genuinely indicates an endpoint isn't accepting connections at the specified host and port. If other kinds of network errors are occurring, it will be helpful to have a visual indicator to prompt investigation. After success or the first error, cleanup the ping's request/connection immediately since we're not awaiting `'data'` events on an http request and we don't want to leave a websocket connection open. Don't callback any additional `'error'` events that might fire after the first `'error'` event, but do report them.
This PR replaces #1166. The "stuck sockets" bug is addressed in #1195 so there is no longer a need to use timeouts. However a few aspects of the original PR are still useful, and lessons learned from #1166, #1181, and #1195 can be put to good use. Use a websocket client from the `ws` package when pinging websocket endpoints instead of manually building a request header. The `'upgrade'` event being listened for was never actually firing; and though a response was received for those pings, the response messages indicated problems with those requests. It seems cleaner to use a proper websocket client and callback success upon the `ws` client's `'open'` event. Abstract error and success handling across websocket and http pings. Report network errors other than `ECONNREFUSED`. Only `ECONNREFUSED` is expected, as that genuinely indicates an endpoint isn't accepting connections at the specified host and port. If other kinds of network errors are occurring, it will be helpful to have a visual indicator to prompt investigation. After success or the first error, cleanup the ping's request/connection immediately since we're not awaiting `'data'` events on an http request and we don't want to leave a websocket connection open. Don't callback any `'error'` events that might fire after the first `'error'` event or a success event, but do report them.
| }; | ||
|
|
||
| Blockchain.prototype.setupProxy = async function () { | ||
| const AccountParser = require('../../utils/accountParser'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we move this require statement out of the function? Ideally we refactor this straight to import * as AccountParser ..
Actually it'd be nicer if we could do import { AccountParser } from '... but we'll have to refactor the exports of AccountParser for that.
| case METHODS_TO_MODIFY.accounts: | ||
| body.result = body.result.concat(accounts); | ||
| break; | ||
| default: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think default should return something here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, it should not modify or change the behavior in case of default. I used a switch because it's easier that way to add more cases than an ìf`
| head.push(`${key}: ${value}`); | ||
| return head; | ||
| } | ||
| for (let i = 0; i < value.length; i++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we go with value.forEach here?
| server.emit('proxyReqWs', proxyReq, req, socket, options, head); | ||
| } | ||
|
|
||
| // Error Handler |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment is unnecessary
| const http = require('http'); | ||
| const https = require('https'); | ||
| const httpProxyWsIncoming = require('http-proxy/lib/http-proxy/passes/ws-incoming'); | ||
| const common = require('http-proxy/lib/http-proxy/common'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is a newly introduced file, it'd be great if we could go with import statements right away
| const CRLF = '\r\n'; | ||
|
|
||
| httpProxyWsIncoming.stream = (req, socket, options, head, server, cb) => { | ||
| const createHttpHeader = function(line, headers) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this function can be defined outside of stream no?
Also, if we go with function initialization instead of declaration, can we use arrow functions instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
httpProxyOverride.js was copied from an unmerged PR for the http-proxy package:
http-party/node-http-proxy#1301
We're using it to patch http-proxy with support for transform streams.
Some light cleanup was done to the formatting of the copied code, but it wasn't otherwise modified. We certainly can introduce additional changes, but more time will need to be spent studying the source to make sure we don't break it.
| // The pipe below will end proxySocket if socket closes cleanly, but not | ||
| // if it errors (eg, vanishes from the net and starts returning | ||
| // EHOSTUNREACH). We need to do that explicitly. | ||
| socket.on('error', function () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also here, for all the anonymous functions above, I think this would be nicer with arrow functions.
| const testLogger = new TestLogger({}); | ||
| }; | ||
| isHexStrictStub = sinon.stub(Web3.utils, 'isHexStrict').returns(true); | ||
| // Web3.utils.isHexStrict = sinon.stub().returns(true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's still a comment left here.
| }); | ||
|
|
||
| if (ws) { | ||
| server.on('upgrade', function (msg, socket, head) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we go with arrow function here too? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
|
|
||
| /*eslint complexity: ["error", 30]*/ | ||
| static getAccount(accountConfig, web3, logger = console, nodeAccounts) { | ||
| const {utils} = require('web3'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's move this require statement out of this function.
|
FYI, this PR now contains #1172 |
|
@PascalPrecht Like Michael mentioned, the file httpProxyOverride.js is a patch from a PR that was never merged in |
f867cc1 to
291146d
Compare
|
Rebased against master, mainly accounting for #1156. |
This PR replaces #1166. The "stuck sockets" bug is addressed in #1195 so there is no longer a need to use timeouts. However a few aspects of the original PR are still useful, and lessons learned from #1166, #1181, and #1195 can be put to good use. Use a websocket client from the `ws` package when pinging websocket endpoints instead of manually building a request header. The `'upgrade'` event being listened for was never actually firing; and though a response was received for those pings, the response messages indicated problems with those requests. It seems cleaner to use a proper websocket client and callback success upon the `ws` client's `'open'` event. Abstract error and success handling across websocket and http pings. Report network errors other than `ECONNREFUSED`. Only `ECONNREFUSED` is expected, as that genuinely indicates an endpoint isn't accepting connections at the specified host and port. If other kinds of network errors are occurring, it will be helpful to have a visual indicator to prompt investigation. After success or the first error, cleanup the ping's request/connection immediately since we're not awaiting `'data'` events on an http request and we don't want to leave a websocket connection open. Don't callback any `'error'` events that might fire after the first `'error'` event or a success event, but do report them.
The problems described in embark PR #1166 can be resolved by implementing the blockchain proxy with `http-proxy` directly instead of using `express` together with `http-proxy-middleware`. The ultimate cause of the buggy behavior (the "stuck sockets" problems described in #1166) is unknown. The need to swallow some errors as described in embark PR #1181 is also eliminated by dropping `http-proxy-middleware` and `express`.
291146d to
bd6e4a6
Compare
This PR replaces #1166. The "stuck sockets" bug is addressed in #1195 so there is no longer a need to use timeouts. However a few aspects of the original PR are still useful, and lessons learned from #1166, #1181, and #1195 can be put to good use. Use a websocket client from the `ws` package when pinging websocket endpoints instead of manually building a request header. The `'upgrade'` event being listened for was never actually firing; and though a response was received for those pings, the response messages indicated problems with those requests. It seems cleaner to use a proper websocket client and callback success upon the `ws` client's `'open'` event. Abstract error and success handling across websocket and http pings. Report network errors other than `ECONNREFUSED`. Only `ECONNREFUSED` is expected, as that genuinely indicates an endpoint isn't accepting connections at the specified host and port. If other kinds of network errors are occurring, it will be helpful to have a visual indicator to prompt investigation. After success or the first error, cleanup the ping's request/connection immediately since we're not awaiting `'data'` events on an http request and we don't want to leave a websocket connection open. Don't callback any `'error'` events that might fire after the first `'error'` event or a success event, but do report them.
The problems described in embark PR #1166 can be resolved by implementing the blockchain proxy with
http-proxydirectly instead of usingexpresstogether withhttp-proxy-middleware. The ultimate cause of the buggy behavior (the "stuck sockets" problems described in #1166) is unknown.The need to swallow some errors as described in embark PR #1181 is also eliminated by dropping
http-proxy-middlewareandexpress.