1
1
using System ;
2
- using System . Collections . Concurrent ;
3
- using System . Collections . Generic ;
4
2
using System . IO ;
5
3
using System . Linq ;
6
- using System . Text ;
7
4
using System . Threading ;
8
5
using System . Threading . Tasks ;
9
- using JsonRpc . Server ;
10
6
using JsonRpc . Server . Messages ;
11
7
using Newtonsoft . Json . Linq ;
12
8
13
9
namespace JsonRpc
14
10
{
15
11
public class InputHandler : IInputHandler
16
12
{
17
- private readonly TimeSpan _sleepTime = TimeSpan . FromMilliseconds ( 50 ) ;
18
13
public const char CR = '\r ' ;
19
14
public const char LF = '\n ' ;
20
15
public static char [ ] CRLF = { CR , LF } ;
@@ -28,8 +23,7 @@ public class InputHandler : IInputHandler
28
23
private Thread _inputThread ;
29
24
private readonly IRequestRouter _requestRouter ;
30
25
private readonly IResponseRouter _responseRouter ;
31
- private readonly ConcurrentQueue < ( RequestProcessType type , Func < Task > request ) > _queue ;
32
- private Thread _queueThread ;
26
+ private readonly IScheduler _scheduler ;
33
27
34
28
public InputHandler (
35
29
TextReader input ,
@@ -46,31 +40,16 @@ IResponseRouter responseRouter
46
40
_requestProcessIdentifier = requestProcessIdentifier ;
47
41
_requestRouter = requestRouter ;
48
42
_responseRouter = responseRouter ;
49
- _queue = new ConcurrentQueue < ( RequestProcessType type , Func < Task > request ) > ( ) ;
50
43
51
- _inputThread = new Thread ( ProcessInputStream ) { IsBackground = true } ;
52
-
53
- _queueThread = new Thread ( ProcessRequestQueue ) { IsBackground = true } ;
54
- }
55
-
56
- internal InputHandler (
57
- TextReader input ,
58
- IOutputHandler outputHandler ,
59
- IReciever reciever ,
60
- IRequestProcessIdentifier requestProcessIdentifier ,
61
- IRequestRouter requestRouter ,
62
- IResponseRouter responseRouter ,
63
- TimeSpan sleepTime
64
- ) : this ( input , outputHandler , reciever , requestProcessIdentifier , requestRouter , responseRouter )
65
- {
66
- _sleepTime = sleepTime ;
67
- }
44
+ _scheduler = new ProcessScheduler ( ) ;
45
+ _inputThread = new Thread ( ProcessInputStream ) { IsBackground = true , Name = "ProcessInputStream" } ;
46
+ }
68
47
69
48
public void Start ( )
70
49
{
71
50
_outputHandler . Start ( ) ;
72
51
_inputThread . Start ( ) ;
73
- _queueThread . Start ( ) ;
52
+ _scheduler . Start ( ) ;
74
53
}
75
54
76
55
private async void ProcessInputStream ( )
@@ -81,10 +60,14 @@ private async void ProcessInputStream()
81
60
82
61
var buffer = new char [ 300 ] ;
83
62
var current = await _input . ReadBlockAsync ( buffer , 0 , MinBuffer ) ;
63
+ if ( current == 0 ) return ; // no more _input
64
+
84
65
while ( current < MinBuffer || buffer [ current - 4 ] != CR || buffer [ current - 3 ] != LF ||
85
66
buffer [ current - 2 ] != CR || buffer [ current - 1 ] != LF )
86
67
{
87
- current += await _input . ReadBlockAsync ( buffer , current , 1 ) ;
68
+ var n = await _input . ReadBlockAsync ( buffer , current , 1 ) ;
69
+ if ( n == 0 ) return ; // no more _input, mitigates endless loop here.
70
+ current += n ;
88
71
}
89
72
90
73
var headersContent = new string ( buffer , 0 , current ) ;
@@ -97,17 +80,28 @@ private async void ProcessInputStream()
97
80
var value = headers [ i ] . Trim ( ) ;
98
81
if ( header . Equals ( "Content-Length" , StringComparison . OrdinalIgnoreCase ) )
99
82
{
100
- length = long . Parse ( value ) ;
83
+ length = 0 ;
84
+ long . TryParse ( value , out length ) ;
101
85
}
102
86
}
103
87
104
- var requestBuffer = new char [ length ] ;
105
-
106
- await _input . ReadBlockAsync ( requestBuffer , 0 , requestBuffer . Length ) ;
107
-
108
- var payload = new string ( requestBuffer ) ;
109
-
110
- HandleRequest ( payload ) ;
88
+ if ( length == 0 || length >= int . MaxValue )
89
+ {
90
+ HandleRequest ( string . Empty ) ;
91
+ }
92
+ else
93
+ {
94
+ var requestBuffer = new char [ length ] ;
95
+ var received = 0 ;
96
+ while ( received < length )
97
+ {
98
+ var n = await _input . ReadBlockAsync ( requestBuffer , received , requestBuffer . Length - received ) ;
99
+ if ( n == 0 ) return ; // no more _input
100
+ received += n ;
101
+ }
102
+ var payload = new string ( requestBuffer ) ;
103
+ HandleRequest ( payload ) ;
104
+ }
111
105
}
112
106
}
113
107
@@ -158,24 +152,23 @@ private void HandleRequest(string request)
158
152
{
159
153
if ( item . IsRequest )
160
154
{
161
- _queue . Enqueue ( (
155
+ _scheduler . Add (
162
156
type ,
163
157
async ( ) => {
164
158
var result = await _requestRouter . RouteRequest ( item . Request ) ;
165
-
166
159
_outputHandler . Send ( result . Value ) ;
167
160
}
168
- ) ) ;
161
+ ) ;
169
162
}
170
163
else if ( item . IsNotification )
171
164
{
172
- _queue . Enqueue ( (
165
+ _scheduler . Add (
173
166
type ,
174
167
( ) => {
175
168
_requestRouter . RouteNotification ( item . Notification ) ;
176
169
return Task . CompletedTask ;
177
170
}
178
- ) ) ;
171
+ ) ;
179
172
}
180
173
else if ( item . IsError )
181
174
{
@@ -185,42 +178,12 @@ private void HandleRequest(string request)
185
178
}
186
179
}
187
180
188
- private bool IsNextSerial ( )
189
- {
190
- return _queue . TryPeek ( out var queueResult ) && queueResult . type == RequestProcessType . Serial ;
191
- }
192
-
193
- private async void ProcessRequestQueue ( )
194
- {
195
- while ( true )
196
- {
197
- if ( _queueThread == null ) return ;
198
- var items = new List < Func < Task > > ( ) ;
199
- while ( ! _queue . IsEmpty )
200
- {
201
- if ( IsNextSerial ( ) && items . Count > 0 )
202
- {
203
- break ;
204
- }
205
-
206
- if ( _queue . TryDequeue ( out var queueResult ) )
207
- items . Add ( queueResult . request ) ;
208
- }
209
-
210
- await Task . WhenAll ( items . Select ( x => x ( ) ) ) ;
211
-
212
- if ( _queue . IsEmpty )
213
- {
214
- await Task . Delay ( _sleepTime ) ;
215
- }
216
- }
217
- }
218
181
219
182
public void Dispose ( )
220
183
{
221
184
_outputHandler . Dispose ( ) ;
222
185
_inputThread = null ;
223
- _queueThread = null ;
186
+ _scheduler . Dispose ( ) ;
224
187
}
225
188
}
226
189
}
0 commit comments