@@ -158,7 +158,9 @@ public async Task AddMessageCallback(string channel, Action<OnMessageReceivedArg
158158 await JoinChannel ( channel ) ;
159159 var channelSan = channel . ToLowerInvariant ( ) ;
160160 lock ( _onMessageReceived ) {
161- _onMessageReceived [ channelSan ] = callback ;
161+ if ( ! _onMessageReceived . TryAdd ( channelSan , callback ) ) {
162+ _onMessageReceived [ channelSan ] += callback ;
163+ }
162164 }
163165 }
164166
@@ -167,7 +169,16 @@ public void RemoveMessageCallback(string channel, Action<OnMessageReceivedArgs>
167169 bool shouldRemove = false ;
168170 var channelSan = channel . ToLowerInvariant ( ) ;
169171 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+ }
171182 }
172183
173184 if ( shouldRemove ) {
@@ -233,33 +244,31 @@ private async Task<bool> JoinChannel(string channel) {
233244 if ( ! await Connect ( ) ) {
234245 return false ;
235246 }
247+
248+ try {
249+ // If we don't have a client, give up.
250+ if ( null == client ) {
251+ return false ;
252+ }
236253
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 ;
255259 }
256260
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 ) ;
261265 }
262- } ) ;
266+
267+ return true ;
268+ }
269+ catch {
270+ return false ;
271+ }
263272 }
264273
265274 /// <summary>
@@ -303,80 +312,79 @@ private async Task<bool> Connect() {
303312 return false ;
304313 }
305314
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 true ;
320+ }
344321
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 false ;
364367 }
365368 }
369+ finally {
370+ client . OnConnected -= onConnected ;
371+ client . OnReconnected -= onReconnect ;
372+ }
366373 }
367- catch {
368- }
369-
370- // Determine if we successfully connected.
371- isConnected = client ? . IsConnected ?? false ;
374+ }
375+ catch {
376+ // Do nothing, just try.
372377 }
373378
374- return isConnected ;
375- }
376- catch {
377- return false ;
379+ // Determine if we successfully connected.
380+ isConnected = client ? . IsConnected ?? false ;
378381 }
379- } ) ;
382+
383+ return isConnected ;
384+ }
385+ catch {
386+ return false ;
387+ }
380388 }
381389
382390 /// <summary>
0 commit comments