22
33using System . Runtime . InteropServices ;
44
5- using Valkey . Glide . Commands ;
65using Valkey . Glide . Internals ;
76using Valkey . Glide . Pipeline ;
87
98using static Valkey . Glide . ConnectionConfiguration ;
109using static Valkey . Glide . Errors ;
1110using static Valkey . Glide . Internals . FFI ;
11+ using static Valkey . Glide . Internals . ResponseConverters ;
1212using static Valkey . Glide . Internals . ResponseHandler ;
1313using static Valkey . Glide . Pipeline . Options ;
14- using static Valkey . Glide . Route ;
1514
1615namespace Valkey . Glide ;
1716
18- public abstract class BaseClient : IDisposable , IStringBaseCommands
17+ public abstract partial class BaseClient : IDisposable
1918{
2019 #region public methods
21- public async Task < string > Set ( GlideString key , GlideString value )
22- => await Command ( RequestType . Set , [ key , value ] , HandleOk ) ;
23-
24- public async Task < GlideString ? > Get ( GlideString key )
25- => await Command ( RequestType . Get , [ key ] , response => HandleServerResponse < GlideString > ( response , true ) ) ;
26-
2720 public void Dispose ( )
2821 {
2922 GC . SuppressFinalize ( this ) ;
@@ -71,10 +64,17 @@ protected BaseClient()
7164
7265 protected internal delegate T ResponseHandler < T > ( IntPtr response ) ;
7366
74- internal async Task < T > Command < T > ( RequestType requestType , GlideString [ ] arguments , ResponseHandler < T > responseHandler , Route ? route = null ) where T : class ?
67+ /// <summary>
68+ /// </summary>
69+ /// <typeparam name="R">Type received from server.</typeparam>
70+ /// <typeparam name="T">Type we return to the user.</typeparam>
71+ /// <param name="command"></param>
72+ /// <param name="route"></param>
73+ /// <returns></returns>
74+ internal async Task < T > Command < R , T > ( Request . Cmd < R , T > command , Route ? route = null )
7575 {
7676 // 1. Create Cmd which wraps CmdInfo and manages all memory allocations
77- using Cmd cmd = new ( requestType , arguments ) ;
77+ using Cmd cmd = command . ToFfi ( ) ;
7878
7979 // 2. Allocate memory for route
8080 using FFI . Route ? ffiRoute = route ? . ToFfi ( ) ;
@@ -84,7 +84,15 @@ internal async Task<T> Command<T>(RequestType requestType, GlideString[] argumen
8484 CommandFfi ( _clientPointer , ( ulong ) message . Index , cmd . ToPtr ( ) , ffiRoute ? . ToPtr ( ) ?? IntPtr . Zero ) ;
8585
8686 // 4. Get a response and Handle it
87- return responseHandler ( await message ) ;
87+ IntPtr response = await message ;
88+ try
89+ {
90+ return HandleServerValue ( HandleResponse ( response ) , command . IsNullable , command . Converter ) ;
91+ }
92+ finally
93+ {
94+ FreeResponse ( response ) ;
95+ }
8896
8997 // All memory allocated is auto-freed by `using` operator
9098 }
@@ -102,79 +110,17 @@ internal async Task<T> Command<T>(RequestType requestType, GlideString[] argumen
102110 BatchFfi ( _clientPointer , ( ulong ) message . Index , ffiBatch . ToPtr ( ) , raiseOnError , ffiOptions ? . ToPtr ( ) ?? IntPtr . Zero ) ;
103111
104112 // 4. Get a response and Handle it
105- return HandleServerResponse < object ? [ ] ? > ( await message , true ) ;
106-
107- // All memory allocated is auto-freed by `using` operator
108- }
109-
110- protected internal static string HandleOk ( IntPtr response )
111- => HandleServerResponse < string > ( response , false ) ;
112-
113- protected internal static T HandleServerResponse < T > ( IntPtr response , bool isNullable ) where T : class ?
114- => HandleServerResponse < T , T > ( response , isNullable , o => o ) ;
115-
116- protected static ClusterValue < object ? > HandleCustomCommandClusterResponse ( IntPtr response , Route ? route = null )
117- => HandleServerResponse < object , ClusterValue < object ? > > ( response , true , data
118- => ( data is string str && str == "OK" ) || route is SingleNodeRoute || data is not Dictionary < GlideString , object ? >
119- ? ClusterValue < object ? > . OfSingleValue ( data )
120- : ClusterValue < object ? > . OfMultiValue ( ( Dictionary < GlideString , object ? > ) data ) ) ;
121-
122- /// <summary>
123- /// Process and convert a server response that may be a multi-node response.
124- /// </summary>
125- /// <typeparam name="R">GLIDE's return type per node.</typeparam>
126- /// <typeparam name="T">Command's return type.</typeparam>
127- /// <param name="response"></param>
128- /// <param name="isNullable"></param>
129- /// <param name="converter">Function to convert <typeparamref name="R"/> to <typeparamref name="T"/>.</param>
130- protected static ClusterValue < T > HandleClusterValueResponse < R , T > ( IntPtr response , bool isNullable , Route route , Func < R , T > converter ) where T : class ?
131- => HandleServerResponse < object , ClusterValue < T > > ( response , isNullable , data => route is SingleNodeRoute
132- ? ClusterValue < T > . OfSingleValue ( converter ( ( R ) data ) )
133- : ClusterValue < T > . OfMultiValue ( ( ( Dictionary < GlideString , object > ) data ) . ConvertValues ( converter ) ) ) ;
134-
135- /// <summary>
136- /// Process and convert a cluster multi-node response.
137- /// </summary>
138- /// <typeparam name="R">GLIDE's return type per node.</typeparam>
139- /// <typeparam name="T">Command's return type.</typeparam>
140- /// <param name="response"></param>
141- /// <param name="converter">Function to convert <typeparamref name="R"/> to <typeparamref name="T"/>.</param>
142- protected static Dictionary < string , T > HandleMultiNodeResponse < R , T > ( IntPtr response , Func < R , T > converter ) where T : class ?
143- => HandleServerResponse < Dictionary < GlideString , object > , Dictionary < string , T > > ( response , false , dict => dict . DownCastKeys ( ) . ConvertValues ( converter ) ) ;
144-
145- /// <summary>
146- /// Process and convert a server response.
147- /// </summary>
148- /// <typeparam name="R">GLIDE's return type.</typeparam>
149- /// <typeparam name="T">Command's return type.</typeparam>
150- /// <param name="response"></param>
151- /// <param name="isNullable"></param>
152- /// <param name="converter">Optional function to convert <typeparamref name="R" /> to <typeparamref name="T" />.</param>
153- /// <returns></returns>
154- /// <exception cref="Exception"></exception>
155- protected internal static T HandleServerResponse < R , T > ( IntPtr response , bool isNullable , Func < R , T > converter ) where T : class ? where R : class ?
156- {
113+ IntPtr response = await message ;
157114 try
158115 {
159- object ? value = HandleResponse ( response ) ;
160- if ( value is null )
161- {
162- if ( isNullable )
163- {
164- #pragma warning disable CS8603 // Possible null reference return.
165- return null ;
166- #pragma warning restore CS8603 // Possible null reference return.
167- }
168- throw new Exception ( $ "Unexpected return type from Glide: got null expected { typeof ( T ) . GetRealTypeName ( ) } ") ;
169- }
170- return value is R
171- ? converter ( ( value as R ) ! )
172- : throw new RequestException ( $ "Unexpected return type from Glide: got { value ? . GetType ( ) . GetRealTypeName ( ) } expected { typeof ( T ) . GetRealTypeName ( ) } ") ;
116+ return batch . ConvertResponse ( HandleServerValue ( HandleResponse ( response ) , true , ( object ? [ ] ? o ) => o ) ) ;
173117 }
174118 finally
175119 {
176120 FreeResponse ( response ) ;
177121 }
122+
123+ // All memory allocated is auto-freed by `using` operator
178124 }
179125 #endregion protected methods
180126
0 commit comments