33using System . Text ;
44using System . Threading ;
55using System . Net . Sockets ;
6-
7- using Random = System . Random ;
6+ using System . IO ;
87
98namespace Lexone . UnityTwitchChat
109{
1110 internal partial class TwitchConnection
1211 {
13- private string currentRawLine ;
14- private byte [ ] inputBuffer ;
15- private char [ ] chars ;
16- private Decoder decoder = Encoding . UTF8 . GetDecoder ( ) ;
17-
1812 // Used to generate session based random colors for undefined users
19- private int sessionRandom = DateTime . Now . Second ;
13+ private int sessionRandom = DateTime . Now . Second ;
2014
2115 private void ReadThreadLoop ( )
2216 {
2317 if ( showThreadDebug )
2418 Debug . Log ( $ "{ Tags . thread } Read thread started") ;
2519
26- Socket socket = tcpClient . Client ;
27- currentRawLine = string . Empty ;
28- inputBuffer = new byte [ readBufferSize ] ;
29- chars = new char [ readBufferSize ] ;
30-
31- while ( ThreadsRunning )
20+ using ( NetworkStream stream = tcpClient . GetStream ( ) )
3221 {
33- if ( ! CheckConnection ( socket ) )
34- {
35- // Sometimes, right after a new TcpClient is created, the socket says
36- // it has been shutdown. This catches that case and attempts reconnecting.
37- alertQueue . Enqueue ( IRCReply . CONNECTION_INTERRUPTED ) ;
38- break ;
39- }
22+ byte [ ] readBuffer = new byte [ readBufferSize ] ;
23+ StringBuilder currentLine = new StringBuilder ( ) ;
24+ Decoder decoder = Encoding . UTF8 . GetDecoder ( ) ;
4025
41- while ( socket . Available > 0 )
42- {
43- // Receive data from the socket
44- int bytesReceived = socket . Receive ( inputBuffer ) ;
26+ // Temporary solution(?):
27+ // Certain multi-byte UTF-8 characters can result in overflowing (special characters)
28+ // So we add a little extra space to the chars array just to be safe
29+ char [ ] chars = new char [ readBufferSize + Mathf . Clamp ( readBufferSize / 4 , 1 , 32 ) ] ;
4530
46- // Decode data into text
47- int charCount = decoder . GetChars ( inputBuffer , 0 , bytesReceived , chars , 0 ) ;
31+ while ( ThreadsRunning )
32+ {
33+ // Check if the connection is still alive
34+ if ( ! CheckConnection ( tcpClient . Client ) )
35+ {
36+ alertQueue . Enqueue ( IRCReply . CONNECTION_INTERRUPTED ) ;
37+ return ;
38+ }
4839
49- for ( int i = 0 ; i < charCount ; ++ i )
40+ while ( stream . DataAvailable )
5041 {
51- // If the character is a linebreak, we have a complete line
52- if ( chars [ i ] == '\n ' || chars [ i ] == '\r ' )
42+ // Read the bytes from the stream
43+ int bytesReceived = stream . Read ( readBuffer , 0 , readBufferSize ) ;
44+
45+ // Decode the bytes to chars
46+ int charsDecoded = decoder . GetChars ( readBuffer , 0 , bytesReceived , chars , 0 ) ;
47+
48+ for ( int i = 0 ; i < charsDecoded ; ++ i )
5349 {
54- // Process the line if it's not empty
55- if ( currentRawLine . Length > 0 )
50+ // Character is a linebreak -> We have a complete line
51+ if ( chars [ i ] == ' \n ' || chars [ i ] == ' \r ' )
5652 {
57- HandleRawLine ( currentRawLine ) ;
58- currentRawLine = string . Empty ;
53+ // If the line is not empty, handle it
54+ if ( currentLine . Length > 0 )
55+ {
56+ HandleRawLine ( currentLine . ToString ( ) ) ;
57+ currentLine . Clear ( ) ;
58+ }
59+ }
60+ else
61+ {
62+ // Append the character to the current line
63+ currentLine . Append ( chars [ i ] ) ;
5964 }
60- continue ;
61- }
62-
63- // Otherwise, append the character to the current line
64- else
65- {
66- currentRawLine += chars [ i ] ;
6765 }
6866 }
69- }
7067
71- // Sleep to prevent high CPU usage
72- Thread . Sleep ( readInterval ) ;
68+ // Sleep to prevent high CPU usage
69+ Thread . Sleep ( readInterval ) ;
70+ }
7371 }
7472
7573 if ( showThreadDebug )
@@ -87,6 +85,7 @@ private bool CheckConnection(Socket socket)
8785 return true ;
8886 }
8987
88+
9089 private void HandleRawLine ( string raw )
9190 {
9291 if ( showIRCDebug )
@@ -147,10 +146,10 @@ private void HandlePRIVMSG(string ircString, string tagString)
147146 var channel = ParseHelper . ParseChannel ( ircString ) ;
148147 var message = ParseHelper . ParseMessage ( ircString ) ;
149148 var tags = ParseHelper . ParseTags ( tagString ) ;
150-
149+
151150 // Not all users have set their Twitch name color, so we need to check for that
152151 if ( tags . colorHex . Length <= 0 )
153- tags . colorHex = useRandomColorForUndefined
152+ tags . colorHex = useRandomColorForUndefined
154153 ? ChatColors . GetRandomNameColor ( sessionRandom , login )
155154 : "#FFFFFF" ;
156155
0 commit comments