tmi.js icon indicating copy to clipboard operation
tmi.js copied to clipboard

`disconnected` callback's "reason" parameter is blank

Open Vindexus opened this issue 6 years ago • 6 comments
trafficstars

Actual behaviour: The disconnected event's reason parameter for its callback is blank.

Expected behaviour: The callback for the disconnected event would receive a string saying why it was disconnect.

Code sample

this.client = new tmi.client({
      identity: {
        username: opts.username.toLowerCase(),
        password: opts.token
      },
      channels: [opts.username]
    })

    this.client.on('disconnected', (reason) => {
      log.error(`Twitchchat disconnected ${reason}`)
      this.connected = false
      this.client.connect()
    })

this.client.connect()

Error log:

Jan 10 23:46:34:   error: Twitchchat disconnected
Jan 10 20:48:43:   error: Twitchchat disconnected

Server configuration

  • Operating system: Ubuntu 18
  • Node version (if applicable): 10.12.0
  • NPM version (if applicable): 6.4.1
  • tmi.js version: 1.2.1

Vindexus avatar Jan 11 '19 00:01 Vindexus

Tried replicating this with the code currently on Git.


Test details: Operating Systems:

  • Ubuntu 18.04.3 LTS
  • Windows 10 Home (build 18362.356)

Node version:

  • v10.16.3
  • v10.16.1

NPM version:

  • 6.11.3
  • 6.11.3

With both tests I tried:

  • Disconnecting manually (calling client.disconnect())
  • Supplying invalid login data (incorrect oauth code to new tmi.Client())

In both tests, both cases have reason defined. This would lead me to believe this issue has been resolved, either by an update to tmi.js, or by an update to Ubuntu/Node/NPM.

This issue can be closed and marked as resolved.

InzeNL avatar Sep 15 '19 23:09 InzeNL

I have the same issue and i cant find the problem why my bot is disconnecting randomly from twitch.

Test details: Operating Systems: Debian 9.0

Node version: v11.15.0

NPM version: 6.12.0

EightyNine avatar Oct 18 '19 18:10 EightyNine

@EightyNine What does your options object like? (You can leave out the oauth (identity.password) token) This would allow us to test more accurately

InzeNL avatar Oct 18 '19 21:10 InzeNL

Bot = new tmi.client({
			options: {
				clientId: process.env.BOT_CLIENTID,
				debug: false
			},
			
			identity: {
				username: process.env.BOT_NAME,
				password: process.env.BOT_PASS
			},
			
			connection: { 
				cluster: "aws",
				reconnect: true,
				reconnectInterval: 2000,
				//secure: true,
				timeout: 180000
			},
			channels: ["channel1", "channel2", ..... ] 
		});

My bot is joining the most channel with the join command. Here a chart to see the is broke up the connection without a reason.

https://gyazo.com/b414a06523863471520481abea367f06

EightyNine avatar Oct 18 '19 21:10 EightyNine

Was there ever any resolution to this? I have the same issue. I get:

[11:50] info: Connecting to irc-ws.chat.twitch.tv on port 443..
[11:50] info: Sending authentication to server..
[11:50] error: Could not connect to server. Reconnecting in 2 seconds..
[11:50] info: Connecting to irc-ws.chat.twitch.tv on port 443..
[11:50] info: Sending authentication to server..
[11:50] error: Could not connect to server. Reconnecting in 2 seconds..
[11:50] info: Connecting to irc-ws.chat.twitch.tv on port 443..
[11:50] info: Sending authentication to server..
[11:50] error: Could not connect to server. Reconnecting in 3 seconds..
[11:50] info: Connecting to irc-ws.chat.twitch.tv on port 443..
[11:50] info: Sending authentication to server..
[11:50] error: Could not connect to server. Reconnecting in 5 seconds..
[11:50] info: Connecting to irc-ws.chat.twitch.tv on port 443..
[11:50] info: Sending authentication to server..
[11:50] error: Could not connect to server. Reconnecting in 8 seconds..
[11:50] info: Connecting to irc-ws.chat.twitch.tv on port 443..
[11:50] info: Sending authentication to server..
[11:50] error: Maximum reconnection attempts reached.

Then in the disconnect logs all I get is

[11:50:11.702] DEBUG (10724): Twitch Client Disconnected
    reason: ""

It seems like there is some kind of issue with my setup, but I don't get any other errors or descriptors as to what I might be doing incorrectly.

Here's the snip for creating the client:

      const tokenPass = `${this.botAccount.token.token_type} ${this.botAccount.token.access_token}`;
      this.twitchClient = new Client({
        connection: {
          maxReconnectAttempts: 5,
          timeout: 18000,
        },
        channels: [this.botAccount.channel],
        options: { debug: process.env.NODE_ENV === "development" },
        identity: {
          username: this.botAccount.username,
          password: tokenPass,
        },
      });

      this.twitchClient.on("disconnected", (reason) => {
        logger.debug(
          { reason, twitchClient: this.twitchClient },
          "Twitch Client Disconnected"
        );
      });

      try {
        await this.twitchClient.connect();
        this.STATUS = "READY";
        resolve();
        logger.debug("Created and connected new authenticated twitch client");
      } catch (err) {
        reject(err);
        this.STATUS = "ERROR";
        logger.error(
          { err },
          "Failed to connect new twitch authenticated client"
        );
      }
    });

Connecting anonymously works 100% fine. It's only when authenticating that I have an issue. It seems like the authentication IS working, though. If I provide an incorrect bearer token I get a 400 invalid client.

ScriptPup avatar Dec 18 '22 16:12 ScriptPup

I got it working for myself, but holy heck was it a pain to figure out... Essentially after hours and hours of troubleshooting and trying different things it boiled down to not having a wide enough scope. Despite the documentation stating

image

That doesn't appear to be the case. After I changed the authorization flow to use

const twitchAuthURI = `https://id.twitch.tv/oauth2/authorize?response_type=code&client_id=${botAccount.client_id}&redirect_uri=http://localhost:9000%2Fsetup&scope=chat%3Aread+chat%3Aedit+channel%3Amoderate+whispers%3Aread+whispers%3Aedit+channel_editor&token_type=bearer&state=${state}`;

As the OAuth token request, instead of

const twitchAuthURI = `https://id.twitch.tv/oauth2/authorize?response_type=code&client_id=${botAccount.client_id}&redirect_uri=http://localhost:9000%2Fsetup&scope=chat%3Aedit%20whispers%3Aedit&state=${state}`;

everything magically started working!

There are TWO major differences...

  1. token_type=bearer : I never saw anything mentioning this token_type parameter anywhere in any documentation (either twitch side or tmi.js side), the only way I knew to add it is through working backwards from an app that provides a token that works
  2. The scopes are WAY wider. I only opted to request the scopes that I really need for my bot at this time, but apparently that was a mistake.

Once I fixed the authorization request to use the above URI, sending the results to the server and using my previous workflow works 100%. I did change my code back to use the documented oauth:{token} instead of using the {token_type} {token} which I posted above (as that's where I was in my trial and error banging head against the wall strat).

Here's what my working server-side code looks like:

const tokenPass = `oauth:${this.botAccount.token.access_token}`;
      this.twitchClient = new Client({
        connection: {
          maxReconnectAttempts: 5,
          timeout: 18000,
          secure: true,
        },
        channels: [this.botAccount.channel],
        options: {
          debug: process.env.NODE_ENV === "development",
        },
        identity: {
          username: this.botAccount.username,
          password: tokenPass,
        },
      });

      this.twitchClient.on("disconnected", (reason) => {
        logger.debug(
          { reason, status: this.twitchClient?.readyState },
          "Twitch Client Disconnected"
        );
      });
      this.twitchClient.on("connected", (reason) => {
        logger.debug("Twitch client connected");
      });

      try {
        await this.twitchClient.connect();
        this.STATUS = "READY";
        resolve();
        logger.debug("Created and connected new authenticated twitch client");
      } catch (err) {
        reject(err);
        this.STATUS = "ERROR";
        logger.error(
          { err },
          "Failed to connect new twitch authenticated client"
        );
      }

My current project is kind of becoming a bit cumbersome to use as reference, so I wouldn't necessarily recommend it... But it IS currently working as-is at this point (though currently vastly under documented as it's just in the beginning phase of playing with stuff and figuring out what does and doesn't work).

If anyone does want an example though, you can find my project here. https://github.com/ScriptPup/TwitchHelpers In particular, the server logic is mostly here While the client logic is here (check for the showBotTemplate function if it's changed since I posted this).

Lastly, the resources I used to work backwards and figure this out:

  • A working project: https://github.com/FrozenTear7/twitch-spambot (awesome documentation and super easy to spin this up following them which helped me vastly in verifying the problem was with the auth flow and not some kind of edge-case network issue, a problem with my account or application registration, etc.)
  • Again, this little token generator was also extremely helpful: https://twitchapps.com/tmi/

If the maintainers were able to put together a simple minimal-viable working project example or something and link it in the docs, that would help tremendously. It'd also be a good idea to review the claims about needing only scopes chat:read and/or chat:edit.

Hope this helps someone who stumbles upon the topic like I did in the future. Good luck!

ScriptPup avatar Dec 18 '22 21:12 ScriptPup