@@ -158,7 +158,9 @@ public async Task AddMessageCallback(string channel, Action<OnMessageReceivedArg
158
158
await JoinChannel ( channel ) ;
159
159
var channelSan = channel . ToLowerInvariant ( ) ;
160
160
lock ( _onMessageReceived ) {
161
- _onMessageReceived [ channelSan ] = callback ;
161
+ if ( ! _onMessageReceived . TryAdd ( channelSan , callback ) ) {
162
+ _onMessageReceived [ channelSan ] += callback ;
163
+ }
162
164
}
163
165
}
164
166
@@ -167,7 +169,16 @@ public void RemoveMessageCallback(string channel, Action<OnMessageReceivedArgs>
167
169
bool shouldRemove = false ;
168
170
var channelSan = channel . ToLowerInvariant ( ) ;
169
171
lock ( _onMessageReceived ) {
170
- _onMessageReceived . Remove ( channel ) ;
172
+ if ( _onMessageReceived . ContainsKey ( channelSan ) ) {
173
+ var item = _onMessageReceived [ channelSan ] ;
174
+ item -= callback ;
175
+ if ( null == item ) {
176
+ _onMessageReceived . Remove ( channelSan ) ;
177
+ }
178
+ else {
179
+ _onMessageReceived [ channelSan ] = item ;
180
+ }
181
+ }
171
182
}
172
183
173
184
if ( shouldRemove ) {
@@ -233,33 +244,31 @@ private async Task<bool> JoinChannel(string channel) {
233
244
if ( ! await Connect ( ) ) {
234
245
return false ;
235
246
}
247
+
248
+ try {
249
+ // If we don't have a client, give up.
250
+ if ( null == client ) {
251
+ return false ;
252
+ }
236
253
237
- return await Task . Run ( ( ) => {
238
- try {
239
- // If we don't have a client, give up.
240
- if ( null == client ) {
241
- return false ;
242
- }
243
-
244
- lock ( twitchClientLock ) {
245
- // If we are already in the channel, we are done.
246
- if ( null != client . JoinedChannels . FirstOrDefault ( c =>
247
- channel . Equals ( c . Channel , StringComparison . InvariantCultureIgnoreCase ) ) ) {
248
- return true ;
249
- }
250
-
251
- // Otherwise, join the channel. At one point we waited here on the "OnJoinedChannel" to ensure the
252
- // connection before moving onto the next channel. However, it was causing a massive slowdown in
253
- // the application, and we've been working fine without it...so for now...we try this...
254
- client . JoinChannel ( channel ) ;
254
+ lock ( twitchClientLock ) {
255
+ // If we are already in the channel, we are done.
256
+ if ( null != client . JoinedChannels . FirstOrDefault ( c =>
257
+ channel . Equals ( c . Channel , StringComparison . InvariantCultureIgnoreCase ) ) ) {
258
+ return true ;
255
259
}
256
260
257
- return true ;
258
- }
259
- catch {
260
- return false ;
261
+ // Otherwise, join the channel. At one point we waited here on the "OnJoinedChannel" to ensure the
262
+ // connection before moving onto the next channel. However, it was causing a massive slowdown in
263
+ // the application, and we've been working fine without it...so for now...we try this...
264
+ client . JoinChannel ( channel ) ;
261
265
}
262
- } ) ;
266
+
267
+ return true ;
268
+ }
269
+ catch {
270
+ return false ;
271
+ }
263
272
}
264
273
265
274
/// <summary>
@@ -290,93 +299,92 @@ private async void TwitchChatClientReconnectOnElapsed(object? sender, ElapsedEve
290
299
/// Connects to twitch chat.
291
300
/// </summary>
292
301
/// <returns>True if successful, false otherwise.</returns>
293
- private async Task < bool > Connect ( ) {
302
+ private Task < bool > Connect ( ) {
294
303
// If we're already connected, we are good to go.
295
304
lock ( twitchClientLock ) {
296
305
if ( client ? . IsConnected ?? false ) {
297
- return true ;
306
+ return Task . FromResult ( true ) ;
298
307
}
299
308
}
300
309
301
310
// If we don't have the ability to connect, we can leave early.
302
311
if ( string . IsNullOrWhiteSpace ( TwitchUsername ) || string . IsNullOrWhiteSpace ( TwitchOAuthToken ) ) {
303
- return false ;
312
+ return Task . FromResult ( false ) ;
304
313
}
305
314
306
- return await Task . Run ( ( ) => {
307
- try {
308
- bool isConnected = false ;
309
- lock ( twitchClientLock ) {
310
- if ( client ? . IsConnected ?? false ) {
311
- return true ;
312
- }
313
-
314
- // If this is a first time initialization, create a brand-new client.
315
- bool haveNoClient = null == client ;
316
- if ( haveNoClient ) {
317
- var clientOptions = new ClientOptions
318
- { MessagesAllowedInPeriod = 750 , ThrottlingPeriod = TimeSpan . FromSeconds ( 30 ) } ;
319
-
320
- socket = new WebSocketClient ( clientOptions ) ;
321
- client = new TwitchClient ( socket ) ;
322
- var credentials = new ConnectionCredentials ( TwitchUsername , TwitchOAuthToken ) ;
323
- client . Initialize ( credentials ) ;
324
- client . AutoReListenOnException = true ;
325
- client . OnMessageReceived += TwitchChatClient_OnMessageReceived ;
326
- client . OnUserBanned += TwitchChatClient_OnUserBanned ;
327
- client . OnRaidNotification += TwitchChatClient_OnRaidNotification ;
328
- client . OnDisconnected += ( sender , args ) => {
329
- LOG . Error ( "Twitch Client Disconnected" ) ;
330
- } ;
331
- client . OnConnectionError += ( sender , args ) => {
332
- LOG . Error ( $ "Twitch Client Connection Error: { args . Error . Message } ") ;
333
- } ;
334
- client . OnError += ( sender , args ) => {
335
- LOG . Error ( $ "Twitch Client Error: { args . Exception . Message } ") ;
336
- } ;
337
- client . OnIncorrectLogin += ( sender , args ) => {
338
- LOG . Error ( $ "Twitch Client Incorrect Login: { args . Exception . Message } ") ;
339
- } ;
340
- client . OnNoPermissionError += ( sender , args ) => {
341
- LOG . Error ( "Twitch Client No Permission Error" ) ;
342
- } ;
343
- }
315
+ try {
316
+ bool isConnected = false ;
317
+ lock ( twitchClientLock ) {
318
+ if ( client ? . IsConnected ?? false ) {
319
+ return Task . FromResult ( true ) ;
320
+ }
344
321
345
- try {
346
- // If we are not connect, connect.
347
- if ( null != client && ! client . IsConnected ) {
348
- // If this is a new chat client, connect for the first time, otherwise reconnect.
349
- Action connect = haveNoClient ? ( ) => client . Connect ( ) : ( ) => client . Reconnect ( ) ;
350
- using var connectedEvent = new ManualResetEventSlim ( false ) ;
351
- EventHandler < OnConnectedArgs > onConnected = ( _ , _ ) => connectedEvent . Set ( ) ;
352
- EventHandler < OnReconnectedEventArgs > onReconnect = ( _ , _ ) => connectedEvent . Set ( ) ;
353
- try {
354
- client ! . OnConnected += onConnected ;
355
- client ! . OnReconnected += onReconnect ;
356
- connect ( ) ;
357
- if ( ! connectedEvent . Wait ( 30 * 1000 ) ) {
358
- return false ;
359
- }
360
- }
361
- finally {
362
- client . OnConnected -= onConnected ;
363
- client . OnReconnected -= onReconnect ;
322
+ // If this is a first time initialization, create a brand-new client.
323
+ bool haveNoClient = null == client ;
324
+ if ( haveNoClient ) {
325
+ var clientOptions = new ClientOptions
326
+ { MessagesAllowedInPeriod = 750 , ThrottlingPeriod = TimeSpan . FromSeconds ( 30 ) } ;
327
+
328
+ socket = new WebSocketClient ( clientOptions ) ;
329
+ client = new TwitchClient ( socket ) ;
330
+ var credentials = new ConnectionCredentials ( TwitchUsername , TwitchOAuthToken ) ;
331
+ client . Initialize ( credentials ) ;
332
+ client . AutoReListenOnException = true ;
333
+ client . OnMessageReceived += TwitchChatClient_OnMessageReceived ;
334
+ client . OnUserBanned += TwitchChatClient_OnUserBanned ;
335
+ client . OnRaidNotification += TwitchChatClient_OnRaidNotification ;
336
+ client . OnDisconnected += ( sender , args ) => {
337
+ LOG . Error ( "Twitch Client Disconnected" ) ;
338
+ } ;
339
+ client . OnConnectionError += ( sender , args ) => {
340
+ LOG . Error ( $ "Twitch Client Connection Error: { args . Error . Message } ") ;
341
+ } ;
342
+ client . OnError += ( sender , args ) => {
343
+ LOG . Error ( $ "Twitch Client Error: { args . Exception . Message } ") ;
344
+ } ;
345
+ client . OnIncorrectLogin += ( sender , args ) => {
346
+ LOG . Error ( $ "Twitch Client Incorrect Login: { args . Exception . Message } ") ;
347
+ } ;
348
+ client . OnNoPermissionError += ( sender , args ) => {
349
+ LOG . Error ( "Twitch Client No Permission Error" ) ;
350
+ } ;
351
+ }
352
+
353
+ try {
354
+ // If we are not connect, connect.
355
+ if ( null != client && ! client . IsConnected ) {
356
+ // If this is a new chat client, connect for the first time, otherwise reconnect.
357
+ Action connect = haveNoClient ? ( ) => client . Connect ( ) : ( ) => client . Reconnect ( ) ;
358
+ using var connectedEvent = new ManualResetEventSlim ( false ) ;
359
+ EventHandler < OnConnectedArgs > onConnected = ( _ , _ ) => connectedEvent . Set ( ) ;
360
+ EventHandler < OnReconnectedEventArgs > onReconnect = ( _ , _ ) => connectedEvent . Set ( ) ;
361
+ try {
362
+ client ! . OnConnected += onConnected ;
363
+ client ! . OnReconnected += onReconnect ;
364
+ connect ( ) ;
365
+ if ( ! connectedEvent . Wait ( 30 * 1000 ) ) {
366
+ return Task . FromResult ( false ) ;
364
367
}
365
368
}
369
+ finally {
370
+ client . OnConnected -= onConnected ;
371
+ client . OnReconnected -= onReconnect ;
372
+ }
366
373
}
367
- catch {
368
- }
369
-
370
- // Determine if we successfully connected.
371
- isConnected = client ? . IsConnected ?? false ;
374
+ }
375
+ catch {
376
+ // Do nothing, just try.
372
377
}
373
378
374
- return isConnected ;
375
- }
376
- catch {
377
- return false ;
379
+ // Determine if we successfully connected.
380
+ isConnected = client ? . IsConnected ?? false ;
378
381
}
379
- } ) ;
382
+
383
+ return Task . FromResult ( isConnected ) ;
384
+ }
385
+ catch {
386
+ return Task . FromResult ( false ) ;
387
+ }
380
388
}
381
389
382
390
/// <summary>
0 commit comments