Skip to content
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

fix: streaming client should connect under Node.js #4413

Merged
merged 24 commits into from
Jan 25, 2023

Conversation

compulim
Copy link
Contributor

@compulim compulim commented Jan 20, 2023

Fixes #4412.

Description

NodeWebSocket.connect() is not implemented correctly and should never work. There are multiple problems in the original implementation:

  • It expects the first argument is hostname
    • Instead, it should be server URL (for example, ws://your-bot.azurewebsites.net/.bot/v3/directline?token=123)
  • It is using a server, fake handshake, to get the WebSocket object out, which is probably not working
  • It is waiting for close event for connection to established, which is wrong

We are not sure why the original implementation has done this way.

We are updating the implementation to use ws package to connect.

Designs

Removing second argument (port = 8082)

We are removing the second argument (port = 8082) because:

  1. The serverAddress will contain the port number (by default, ws: is 80, and wss: is 443)
  2. If we keep the current logic, we will always ignore the port number in serverAddress because port is default to 8082

This does not sound intuitive to developer because the port number in serverAddress will always get replaced.

If we don't default port number to 8082, we will need to change the API saying there is no default (i.e. undefined). At the end of the day, we are still modifying the API and will introduce breaking changes.

Regardless of whether we keep port or not, we are still introducing breaking changes. Thus, we are choosing to remove port to simplify our code.

If the developer need to change the port to 8082, they could use the following code snippet:

const url = new URL(serverAddress);

url.port = 8082;

await nodeWebSocket.connect(url.href);

Specific Changes

❗This PR will introduce breaking changes and modified the API. Please bump version appropriately.

  • Update NodeWebSocket.connect() to connect to a Web Socket server as a client
  • Add tests
    • We did not add unhappy path (connect() rejections) because it will print errors to console and there is no easy way to suppress
  • Cleaned up code related to watershed
    • watershed was one of the candidate packages for using Web Socket in Node.js
    • However, ultimately, we chose ws
    • There are no binary, data, and text event in the ws version of Web Socket
    • Thus, we are removing test code related to these events
  • Separating mocks
    • Instead of using an uber FauxSock which mocks Web Socket and TCP/IP Socket, we are opting for a more specific mock for TCP/IP Socket, namely FauxSocket

Testing

Added tests to ensure NodeWebSocket can connect to a real Web Socket server.

@compulim compulim requested a review from a team as a code owner January 20, 2023 16:53
@coveralls
Copy link

coveralls commented Jan 20, 2023

Pull Request Test Coverage Report for Build 4003071240

  • 9 of 9 (100.0%) changed or added relevant lines in 1 file are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.003%) to 84.653%

Totals Coverage Status
Change from base Build 3841042555: 0.003%
Covered Lines: 20002
Relevant Lines: 22391

💛 - Coveralls

@compulim compulim changed the title Fix NodeWebSocket.connect fix: NodeWebSocket.connect Jan 20, 2023
@compulim compulim changed the title fix: NodeWebSocket.connect fix: streaming client should connect under Node.js Jan 20, 2023
Copy link
Contributor

@ckkashyap ckkashyap left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked at NodeWebSocket.ts in detail and it looks fine.

@tracyboehrer
Copy link
Member

@ckkashyap @compulim What is the expected impact of this being a breaking change? What would be a shame is to correct one issue and break another set of customers.

@compulim
Copy link
Contributor Author

I am modifying the API to become connect(serverAddressOrHostName: string, port = 8082). So it is conceptually backward-compatible.

  1. If serverAddressOrHostName is a valid URL (via new URL), then use it as-is, without the second argument (ignore port)
  2. Otherwise, serverAddressOrHostName is a host name, then
    • Construct an URL object by using serverAddressOrHostName as hostname and second argument as port
    • The protocol used is ws: and not wss:
    • This is for backward compatibility as previous version suggests non-secure protocol

As we do not have any existing tests that proves the existing code is working, we are doing our best efforts to make it backward compatible.

@compulim
Copy link
Contributor Author

I tried to write a test to show how previous signature would work. However, there are obvious mistakes in the code that made it very unlikely to work:

  • options.headers.upgrade must set to 'websocket'
  • Second argument of WebSocket.server.completeUpgrade should be {}, instead of undefined

I am keeping the old code as-is, without any tests.

ws.once('open', () => resolve());
});
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A warning here may be useful?

@tracyboehrer tracyboehrer merged commit 736979c into microsoft:main Jan 25, 2023
tracyboehrer pushed a commit that referenced this pull request Jan 25, 2023
* Fix NodeWebSocket.connect

* Fix ESLint

* Update API

* Remove .only

* Clean up code related to watershed

* Fix ESLint

* Fix tests for Node.js 12

* Fix ESLint

* Add mocks

* Remove .only

* Use LF

* Detect older signature

* Fix ESLint

* serverAddress become serverAddressOrHostName

* Update API

* Clean up

* More clean up

* Clean up

* Leaving old code

* Switching branch

* Clean up

* Clean up

* Clean up

* Manual edit
tracyboehrer pushed a commit that referenced this pull request Feb 16, 2023
tracyboehrer pushed a commit that referenced this pull request Mar 21, 2023
* Fix NodeWebSocket.connect

* Fix ESLint

* Update API

* Remove .only

* Clean up code related to watershed

* Fix ESLint

* Fix tests for Node.js 12

* Fix ESLint

* Add mocks

* Remove .only

* Use LF

* Detect older signature

* Fix ESLint

* serverAddress become serverAddressOrHostName

* Update API

* Clean up

* More clean up

* Clean up

* Leaving old code

* Switching branch

* Clean up

* Clean up

* Clean up

* Manual edit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Using Node.js with ASE did not work
5 participants