1717#endregion
1818
1919using System . CommandLine ;
20+ using System . CommandLine . Binding ;
2021using System . CommandLine . Invocation ;
2122using System . Diagnostics ;
2223using System . Globalization ;
@@ -58,29 +59,33 @@ class Program
5859
5960 public static async Task < int > Main ( string [ ] args )
6061 {
62+ var options = new List < Option > ( ) ;
63+ options . Add ( new Option < Uri > ( new string [ ] { "-u" , "--url" } , "The server url to request" ) { IsRequired = true } ) ;
64+ options . Add ( new Option < string > ( new string [ ] { "--udsFileName" } , "The Unix Domain Socket file name" ) ) ;
65+ options . Add ( new Option < int > ( new string [ ] { "-c" , "--connections" } , ( ) => 1 , "Total number of connections to keep open" ) ) ;
66+ options . Add ( new Option < int > ( new string [ ] { "-w" , "--warmup" } , ( ) => 5 , "Duration of the warmup in seconds" ) ) ;
67+ options . Add ( new Option < int > ( new string [ ] { "-d" , "--duration" } , ( ) => 10 , "Duration of the test in seconds" ) ) ;
68+ options . Add ( new Option < int > ( new string [ ] { "--callCount" } , "Call count of test" ) ) ;
69+ options . Add ( new Option < string > ( new string [ ] { "-s" , "--scenario" } , "Scenario to run" ) { IsRequired = true } ) ;
70+ options . Add ( new Option < bool > ( new string [ ] { "-l" , "--latency" } , ( ) => false , "Whether to collect detailed latency" ) ) ;
71+ options . Add ( new Option < string > ( new string [ ] { "-p" , "--protocol" } , "HTTP protocol" ) { IsRequired = true } ) ;
72+ options . Add ( new Option < LogLevel > ( new string [ ] { "-log" , "--logLevel" } , ( ) => LogLevel . None , "The log level to use for Console logging" ) ) ;
73+ options . Add ( new Option < int > ( new string [ ] { "--requestSize" } , "Request payload size" ) ) ;
74+ options . Add ( new Option < int > ( new string [ ] { "--responseSize" } , "Response payload size" ) ) ;
75+ options . Add ( new Option < GrpcClientType > ( new string [ ] { "--grpcClientType" } , ( ) => GrpcClientType . GrpcNetClient , "Whether to use Grpc.NetClient or Grpc.Core client" ) ) ;
76+ options . Add ( new Option < int > ( new string [ ] { "--streams" } , ( ) => 1 , "Maximum concurrent streams per connection" ) ) ;
77+ options . Add ( new Option < bool > ( new string [ ] { "--enableCertAuth" } , ( ) => false , "Flag indicating whether client sends a client certificate" ) ) ;
78+ options . Add ( new Option < int > ( new string [ ] { "--deadline" } , "Duration of deadline in seconds" ) ) ;
79+
6180 var rootCommand = new RootCommand ( ) ;
62- rootCommand . AddOption ( new Option < string > ( new string [ ] { "-u" , "--url" } , "The server url to request" ) { Required = true } ) ;
63- rootCommand . AddOption ( new Option < string > ( new string [ ] { "--udsFileName" } , "The Unix Domain Socket file name" ) ) ;
64- rootCommand . AddOption ( new Option < int > ( new string [ ] { "-c" , "--connections" } , ( ) => 1 , "Total number of connections to keep open" ) ) ;
65- rootCommand . AddOption ( new Option < int > ( new string [ ] { "-w" , "--warmup" } , ( ) => 5 , "Duration of the warmup in seconds" ) ) ;
66- rootCommand . AddOption ( new Option < int > ( new string [ ] { "-d" , "--duration" } , ( ) => 10 , "Duration of the test in seconds" ) ) ;
67- rootCommand . AddOption ( new Option < int > ( new string [ ] { "--callCount" } , "Call count of test" ) ) ;
68- rootCommand . AddOption ( new Option < string > ( new string [ ] { "-s" , "--scenario" } , "Scenario to run" ) { Required = true } ) ;
69- rootCommand . AddOption ( new Option < bool > ( new string [ ] { "-l" , "--latency" } , ( ) => false , "Whether to collect detailed latency" ) ) ;
70- rootCommand . AddOption ( new Option < string > ( new string [ ] { "-p" , "--protocol" } , "HTTP protocol" ) { Required = true } ) ;
71- rootCommand . AddOption ( new Option < LogLevel > ( new string [ ] { "-log" , "--logLevel" } , ( ) => LogLevel . None , "The log level to use for Console logging" ) ) ;
72- rootCommand . AddOption ( new Option < int > ( new string [ ] { "--requestSize" } , "Request payload size" ) ) ;
73- rootCommand . AddOption ( new Option < int > ( new string [ ] { "--responseSize" } , "Response payload size" ) ) ;
74- rootCommand . AddOption ( new Option < GrpcClientType > ( new string [ ] { "--grpcClientType" } , ( ) => GrpcClientType . GrpcNetClient , "Whether to use Grpc.NetClient or Grpc.Core client" ) ) ;
75- rootCommand . AddOption ( new Option < int > ( new string [ ] { "--streams" } , ( ) => 1 , "Maximum concurrent streams per connection" ) ) ;
76- rootCommand . AddOption ( new Option < bool > ( new string [ ] { "--enableCertAuth" } , ( ) => false , "Flag indicating whether client sends a client certificate" ) ) ;
77- rootCommand . AddOption ( new Option < int > ( new string [ ] { "--deadline" } , "Duration of deadline in seconds" ) ) ;
78-
79- rootCommand . Handler = CommandHandler . Create < ClientOptions > ( async ( options ) =>
81+ foreach ( var option in options )
8082 {
81- _options = options ;
83+ rootCommand . AddOption ( option ) ;
84+ }
8285
83- Log ( "gRPC Client" ) ;
86+ rootCommand . SetHandler < ClientOptions > ( async ( options ) =>
87+ {
88+ _options = options ;
8489
8590 var runtimeVersion = typeof ( object ) . GetTypeInfo ( ) . Assembly . GetCustomAttribute < AssemblyInformationalVersionAttribute > ( ) ? . InformationalVersion ?? "Unknown" ;
8691 var isServerGC = GCSettings . IsServerGC ;
@@ -103,11 +108,45 @@ public static async Task<int> Main(string[] args)
103108 await StartScenario ( ) ;
104109
105110 await StopJobAsync ( ) ;
106- } ) ;
111+ } , new ReflectionBinder < ClientOptions > ( options ) ) ;
112+
113+ Log ( "gRPC Client" ) ;
107114
108115 return await rootCommand . InvokeAsync ( args ) ;
109116 }
110117
118+ private class ReflectionBinder < T > : BinderBase < T > where T : new ( )
119+ {
120+ private readonly List < Option > _options ;
121+
122+ public ReflectionBinder ( List < Option > options )
123+ {
124+ _options = options ;
125+ }
126+
127+ protected override T GetBoundValue ( BindingContext bindingContext )
128+ {
129+ var boundValue = new T ( ) ;
130+
131+ Log ( $ "Binding { typeof ( T ) } ") ;
132+
133+ foreach ( var option in _options )
134+ {
135+ var value = bindingContext . ParseResult . GetValueForOption ( option ) ;
136+
137+ var propertyInfo = typeof ( T ) . GetProperty ( option . Name , BindingFlags . IgnoreCase | BindingFlags . Public | BindingFlags . Instance ) ;
138+ if ( propertyInfo != null )
139+ {
140+ propertyInfo . SetValue ( boundValue , value ) ;
141+
142+ Log ( $ "-{ propertyInfo . Name } = { value } ") ;
143+ }
144+ }
145+
146+ return boundValue ;
147+ }
148+ }
149+
111150 private static async Task StartScenario ( )
112151 {
113152 if ( _options . CallCount == null )
@@ -354,7 +393,7 @@ private static void CreateChannels()
354393 }
355394
356395 // Channel does not care about scheme
357- var initialUri = new Uri ( _options . Url ! ) ;
396+ var initialUri = _options . Url ! ;
358397 var resolvedUri = initialUri . Authority ;
359398
360399 Log ( $ "gRPC client type: { _options . GrpcClientType } ") ;
0 commit comments