Streamerbot / client

Streamer.bot WebSocket client
https://streamerbot.github.io/client/
MIT License
23 stars 4 forks source link

WebSocket was closed before the connection was established #2

Closed zephsinx closed 1 year ago

zephsinx commented 1 year ago

It's me again! Thank you so much for your quick reply and addressing of my last issue #1. I am now running into another issue when trying to get WebSockets running on a Node app.

The Error(s)

The issue seems to come down to the WebSocket connection closing too quickly before it can be used. Note the _readyState of 2 (i.e. Closing) in the error below when using connect().

Using getActions()

      throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
            ^

Error: WebSocket is not open: readyState 0 (CONNECTING)
    at WebSocket.send (E:\Projects\Software\streamerbot-tools\sb-client\node_modules\ws\lib\websocket.js:442:13)
    at StreamerbotClient.send (file:///sb-client/node_modules/@streamerbot/client/dist/index.js:339:46)
    at file:///sb-client/node_modules/@streamerbot/client/dist/index.js:388:16
    at new Promise (<anonymous>)
    at StreamerbotClient.<anonymous> (file:///sb-client/node_modules/@streamerbot/client/dist/index.js:358:9)
    at Generator.next (<anonymous>)
    at file:///sb-client/node_modules/@streamerbot/client/dist/index.js:37:61
    at new Promise (<anonymous>)
    at __async (file:///sb-client/node_modules/@streamerbot/client/dist/index.js:21:10)
    at StreamerbotClient.request (file:///sb-client/node_modules/@streamerbot/client/dist/index.js:342:12)

Using connect()

WebSocket Error ErrorEvent {
  [Symbol(kTarget)]: WebSocket {
    _events: [Object: null prototype] {
      open: [Function],
      close: [Function],
      error: [Function],
      message: [Function]
    },
    _eventsCount: 4,
    _maxListeners: undefined,
    _binaryType: 'nodebuffer',
    _closeCode: 1006,
    _closeFrameReceived: false,
    _closeFrameSent: false,
    _closeMessage: <Buffer >,
    _closeTimer: null,
    _extensions: {},
    _paused: false,
    _protocol: '',
    _readyState: 2,
    _receiver: null,
    _sender: null,
    _socket: null,
    _bufferedAmount: 0,
    _isServer: false,
    _redirects: 0,
    _url: 'ws://127.0.0.1:8080/',
    _req: ClientRequest {
      _events: [Object: null prototype],
      _eventsCount: 3,
      _maxListeners: undefined,
      outputData: [Array],
      outputSize: 223,
      writable: true,
      destroyed: true,
      _last: true,
      chunkedEncoding: false,
      shouldKeepAlive: true,
      maxRequestsOnConnectionReached: false,
      _defaultKeepAlive: true,
      useChunkedEncodingByDefault: false,
      sendDate: false,
      _removedConnection: false,
      _removedContLen: false,
      _removedTE: false,
      _contentLength: 0,
      _hasBody: true,
      _trailer: '',
      finished: true,
      _headerSent: true,
      _closed: false,
      socket: null,
      _header: 'GET / HTTP/1.1\r\n' +
        'Sec-WebSocket-Version: 13\r\n' +
        'Sec-WebSocket-Key: GBuyJi1SQiZOQQq7y9ofmw==\r\n' +
        'Connection: Upgrade\r\n' +
        'Upgrade: websocket\r\n' +
        'Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits\r\n' +
        'Host: 127.0.0.1:8080\r\n' +
        '\r\n',
      _keepAliveTimeout: 0,
      _onPendingData: [Function: nop],
      agent: undefined,
      socketPath: undefined,
      method: 'GET',
      maxHeaderSize: undefined,
      insecureHTTPParser: undefined,
      path: '/',
      _ended: false,
      res: null,
      aborted: true,
      timeoutCb: null,
      upgradeOrConnect: false,
      parser: null,
      maxHeadersCount: null,
      reusedSocket: false,
      host: '127.0.0.1',
      protocol: 'http:',
      [Symbol(kCapture)]: false,
      [Symbol(kNeedDrain)]: false,
      [Symbol(corked)]: 0,
      [Symbol(kOutHeaders)]: [Object: null prototype],
      [Symbol(kAborted)]: true,
      [Symbol(kError)]: undefined
    },
    [Symbol(kCapture)]: false
  },
  [Symbol(kType)]: 'error',
  [Symbol(kError)]: Error: WebSocket was closed before the connection was established
      at WebSocket.close (E:\Projects\Software\streamerbot-tools\sb-client\node_modules\ws\lib\websocket.js:285:7)
      at StreamerbotClient.disconnect (file:///sb-client/node_modules/@streamerbot/client/dist/index.js:237:17)
      at StreamerbotClient.<anonymous> (file:///sb-client/node_modules/@streamerbot/client/dist/index.js:211:12)
      at Generator.next (<anonymous>)
      at file:///sb-client/node_modules/@streamerbot/client/dist/index.js:37:61
      at new Promise (<anonymous>)
      at __async (file:///sb-client/node_modules/@streamerbot/client/dist/index.js:21:10)
      at StreamerbotClient.connect (file:///sb-client/node_modules/@streamerbot/client/dist/index.js:209:12)
      at file:///sb-client/index.js:4:16
      at ModuleJob.run (node:internal/modules/esm/module_job:185:25),
  [Symbol(kMessage)]: 'WebSocket was closed before the connection was established'
}
Reconnecting... (attempt 0)
Reconnecting... (attempt 0)

The Code

As before, the code is pretty simple.

import * as streamerbotClient from '@streamerbot/client';
const sbClient = new streamerbotClient.StreamerbotClient();
await sbClient.connect();
// await sbClient.getActions();

Other Info

I've validated my connection settings and that my Streamer.bot client websocket server is started. In fact if I stop it, or change the host or port on the StreamerbotClient(), I get connection refused messages, or messages telling me the server is not started/does not exist.

Thank you again in advance!

Whipstickgostop commented 1 year ago

I've actually got my own note written already for handling this better :D

Keep in mind, the client attempts to connect automatically by default, unless you pass in { immediate: false }

When you call connect() in your code, you are essentially calling it a second time. This is trying to close/kill any existing connections, hence the error. This is what I intend to clean up some.

Examples:

import { StreamerbotClient } from '@streamerbot/client';

// Client will automatically try to connect() and attempt reconnection until Streamer.bot is online
const client = new StreamerbotClient();

// Client waits for you to call `connect()`
const client = new StreamerbotClient({ immediate: false });
await client.connect();

Thanks for a great report again - will try and get another update out today :)

zephsinx commented 1 year ago

Thanks for a great report again

Of course! I've had my fair share of struggles due to having issues reported to me with no details 😅

And interesting. That makes sense. Oddly enough, when I specify the { immediate: false } option, and then call connect(), I get the same issue when calling getActions() (or any method that uses the websocket).

It doesn't seem like the connection ever actually completes/resolves.

Code

import * as streamerbotClient from '@streamerbot/client';

const sbClient = new streamerbotClient.StreamerbotClient({ immediate: false });
await sbClient.connect();
await sbClient.getActions();

If I don't call await sbClient.connect() in this case, I get the following error when calling getActions(), which is probably obvious as the connection was not started.

node:internal/process/esm_loader:94
    internalBinding('errors').triggerUncaughtException(
                              ^
{
  message: 'WebSocket request timeout exceeded',
  request: { request: 'GetActions' }
}

Error

      throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
            ^

Error: WebSocket is not open: readyState 0 (CONNECTING)
    at WebSocket.send (E:\Projects\Software\streamerbot-tools\sb-client\node_modules\ws\lib\websocket.js:442:13)
    at StreamerbotClient.send (file:///sb-client/node_modules/@streamerbot/client/dist/index.js:339:46)
    at file:///sb-client/node_modules/@streamerbot/client/dist/index.js:388:16
    at new Promise (<anonymous>)
    at StreamerbotClient.<anonymous> (file:///sb-client/node_modules/@streamerbot/client/dist/index.js:358:9)
    at Generator.next (<anonymous>)
    at file:///sb-client/node_modules/@streamerbot/client/dist/index.js:37:61
    at new Promise (<anonymous>)
    at __async (file:///sb-client/node_modules/@streamerbot/client/dist/index.js:21:10)
    at StreamerbotClient.request (file:///sb-client/node_modules/@streamerbot/client/dist/index.js:342:12)

Thanks again for the quick replies!

Whipstickgostop commented 1 year ago

As of v1.0.2, await connect() should properly await open state, and await disconnect() should properly await closed state.

Working for me in node v19.4.0:

import { StreamerbotClient } from '@streamerbot/client';

const client = new StreamerbotClient({ host: 'aphex', immediate: false });
await client.connect();

const info = await client.getInfo();
console.log(`Connected to Streamer.bot`, info);

const actions = await client.getActions();
console.log('Actions received:', actions);
zephsinx commented 1 year ago

It works!! Thank you so much for pushing out the change! You're very quick and I appreciate it.