11using System ;
2- using System . Collections . Concurrent ;
3- using System . Collections . Generic ;
42using System . IO ;
53using System . Linq ;
64using System . Threading ;
@@ -20,20 +18,95 @@ internal class LogicalConnection : ILogicalConnection
2018 {
2119 private readonly MsgPackContext _msgPackContext ;
2220
21+ private readonly ClientOptions _clientOptions ;
22+
23+ private readonly RequestIdCounter _requestIdCounter ;
24+
2325 private readonly INetworkStreamPhysicalConnection _physicalConnection ;
2426
25- private long _currentRequestId ;
27+ private readonly ReaderWriterLockSlim _physicalConnectionLock = new ReaderWriterLockSlim ( ) ;
2628
27- private readonly ConcurrentDictionary < RequestId , TaskCompletionSource < MemoryStream > > _pendingRequests =
28- new ConcurrentDictionary < RequestId , TaskCompletionSource < MemoryStream > > ( ) ;
29+ private readonly IResponseReader _responseReader ;
2930
3031 private readonly ILog _logWriter ;
3132
32- public LogicalConnection ( ClientOptions options , INetworkStreamPhysicalConnection physicalConnection )
33+ private bool _disposed ;
34+
35+ public LogicalConnection ( ClientOptions options , RequestIdCounter requestIdCounter )
3336 {
37+ _clientOptions = options ;
38+ _requestIdCounter = requestIdCounter ;
3439 _msgPackContext = options . MsgPackContext ;
3540 _logWriter = options . LogWriter ;
36- _physicalConnection = physicalConnection ;
41+
42+ _physicalConnection = new NetworkStreamPhysicalConnection ( ) ;
43+ _responseReader = new ResponseReader ( _clientOptions , _physicalConnection ) ;
44+ }
45+
46+ public void Dispose ( )
47+ {
48+ if ( _disposed )
49+ {
50+ return ;
51+ }
52+
53+ _disposed = true ;
54+
55+ _responseReader . Dispose ( ) ;
56+ _physicalConnection . Dispose ( ) ;
57+ }
58+
59+ public async Task Connect ( )
60+ {
61+ await _physicalConnection . Connect ( _clientOptions ) ;
62+
63+ var greetingsResponseBytes = new byte [ 128 ] ;
64+ var readCount = await _physicalConnection . ReadAsync ( greetingsResponseBytes , 0 , greetingsResponseBytes . Length ) ;
65+ if ( readCount != greetingsResponseBytes . Length )
66+ {
67+ throw ExceptionHelper . UnexpectedGreetingBytesCount ( readCount ) ;
68+ }
69+
70+ var greetings = new GreetingsResponse ( greetingsResponseBytes ) ;
71+
72+ _clientOptions . LogWriter ? . WriteLine ( $ "Greetings received, salt is { Convert . ToBase64String ( greetings . Salt ) } .") ;
73+
74+ _responseReader . BeginReading ( ) ;
75+
76+ _clientOptions . LogWriter ? . WriteLine ( "Server responses reading started." ) ;
77+
78+ await LoginIfNotGuest ( greetings ) ;
79+ }
80+
81+ public bool IsConnected ( )
82+ {
83+ if ( _disposed )
84+ {
85+ return false ;
86+ }
87+
88+ if ( ! _responseReader . IsConnected ( ) || ! _physicalConnection . IsConnected ( ) )
89+ {
90+ return false ;
91+ }
92+
93+ return true ;
94+ }
95+
96+ private async Task LoginIfNotGuest ( GreetingsResponse greetings )
97+ {
98+ var singleNode = _clientOptions . ConnectionOptions . Nodes . Single ( ) ;
99+
100+ if ( string . IsNullOrEmpty ( singleNode . Uri . UserName ) )
101+ {
102+ _clientOptions . LogWriter ? . WriteLine ( "Guest mode, no authentication attempt." ) ;
103+ return ;
104+ }
105+
106+ var authenticateRequest = AuthenticationRequest . Create ( greetings , singleNode . Uri ) ;
107+
108+ await SendRequestWithEmptyResponse ( authenticateRequest ) ;
109+ _clientOptions . LogWriter ? . WriteLine ( $ "Authentication request send: { authenticateRequest } ") ;
37110 }
38111
39112 public async Task SendRequestWithEmptyResponse < TRequest > ( TRequest request )
@@ -48,15 +121,6 @@ public async Task<DataResponse<TResponse[]>> SendRequest<TRequest, TResponse>(TR
48121 return await SendRequestImpl < TRequest , DataResponse < TResponse [ ] > > ( request ) ;
49122 }
50123
51- public TaskCompletionSource < MemoryStream > PopResponseCompletionSource ( RequestId requestId , MemoryStream resultStream )
52- {
53- TaskCompletionSource < MemoryStream > request ;
54-
55- return _pendingRequests . TryRemove ( requestId , out request )
56- ? request
57- : null ;
58- }
59-
60124 public static byte [ ] ReadFully ( Stream input )
61125 {
62126 input . Position = 0 ;
@@ -72,32 +136,43 @@ public static byte[] ReadFully(Stream input)
72136 }
73137 }
74138
75- public IEnumerable < TaskCompletionSource < MemoryStream > > PopAllResponseCompletionSources ( )
76- {
77- var result = _pendingRequests . Values . ToArray ( ) ;
78- _pendingRequests . Clear ( ) ;
79- return result ;
80- }
81-
82139 private async Task < TResponse > SendRequestImpl < TRequest , TResponse > ( TRequest request )
83140 where TRequest : IRequest
84141 {
142+ if ( _disposed )
143+ {
144+ throw new ObjectDisposedException ( nameof ( LogicalConnection ) ) ;
145+ }
146+
85147 var bodyBuffer = MsgPackSerializer . Serialize ( request , _msgPackContext ) ;
86148
87- var requestId = GetRequestId ( ) ;
88- var responseTask = GetResponseTask ( requestId ) ;
149+ var requestId = _requestIdCounter . GetRequestId ( ) ;
150+ var responseTask = _responseReader . GetResponseTask ( requestId ) ;
89151
90152 long headerLength ;
91153 var headerBuffer = CreateAndSerializeBuffer ( request , requestId , bodyBuffer , out headerLength ) ;
92154
93- lock ( _physicalConnection )
155+ try
94156 {
157+ _physicalConnectionLock . EnterWriteLock ( ) ;
158+
95159 _logWriter ? . WriteLine ( $ "Begin sending request header buffer, requestId: { requestId } , code: { request . Code } , length: { headerBuffer . Length } ") ;
96- _physicalConnection . Write ( headerBuffer , 0 , Constants . PacketSizeBufferSize + ( int ) headerLength ) ;
160+ _physicalConnection . Write ( headerBuffer , 0 , Constants . PacketSizeBufferSize + ( int ) headerLength ) ;
97161
98162 _logWriter ? . WriteLine ( $ "Begin sending request body buffer, length: { bodyBuffer . Length } ") ;
99163 _physicalConnection . Write ( bodyBuffer , 0 , bodyBuffer . Length ) ;
100164 }
165+ catch ( Exception ex )
166+ {
167+ _logWriter ? . WriteLine (
168+ $ "Request with requestId { requestId } failed, header:\n { ToReadableString ( headerBuffer ) } \n body: \n { ToReadableString ( bodyBuffer ) } ") ;
169+ Dispose ( ) ;
170+ throw ;
171+ }
172+ finally
173+ {
174+ _physicalConnectionLock . ExitWriteLock ( ) ;
175+ }
101176
102177 try
103178 {
@@ -137,22 +212,5 @@ private byte[] CreateAndSerializeBuffer<TRequest>(
137212 MsgPackSerializer . Serialize ( packetLength , stream , _msgPackContext ) ;
138213 return packetSizeBuffer ;
139214 }
140-
141- private RequestId GetRequestId ( )
142- {
143- var requestId = Interlocked . Increment ( ref _currentRequestId ) ;
144- return ( RequestId ) ( ulong ) requestId ;
145- }
146-
147- private Task < MemoryStream > GetResponseTask ( RequestId requestId )
148- {
149- var tcs = new TaskCompletionSource < MemoryStream > ( ) ;
150- if ( ! _pendingRequests . TryAdd ( requestId , tcs ) )
151- {
152- throw ExceptionHelper . RequestWithSuchIdAlreadySent ( requestId ) ;
153- }
154-
155- return tcs . Task ;
156- }
157215 }
158216}
0 commit comments