17
17
#endregion
18
18
19
19
using System . CommandLine ;
20
+ using System . CommandLine . Binding ;
20
21
using System . CommandLine . Invocation ;
21
22
using System . Diagnostics ;
22
23
using System . Globalization ;
@@ -58,29 +59,33 @@ class Program
58
59
59
60
public static async Task < int > Main ( string [ ] args )
60
61
{
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
+
61
80
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 )
80
82
{
81
- _options = options ;
83
+ rootCommand . AddOption ( option ) ;
84
+ }
82
85
83
- Log ( "gRPC Client" ) ;
86
+ rootCommand . SetHandler < ClientOptions > ( async ( options ) =>
87
+ {
88
+ _options = options ;
84
89
85
90
var runtimeVersion = typeof ( object ) . GetTypeInfo ( ) . Assembly . GetCustomAttribute < AssemblyInformationalVersionAttribute > ( ) ? . InformationalVersion ?? "Unknown" ;
86
91
var isServerGC = GCSettings . IsServerGC ;
@@ -103,11 +108,45 @@ public static async Task<int> Main(string[] args)
103
108
await StartScenario ( ) ;
104
109
105
110
await StopJobAsync ( ) ;
106
- } ) ;
111
+ } , new ReflectionBinder < ClientOptions > ( options ) ) ;
112
+
113
+ Log ( "gRPC Client" ) ;
107
114
108
115
return await rootCommand . InvokeAsync ( args ) ;
109
116
}
110
117
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
+
111
150
private static async Task StartScenario ( )
112
151
{
113
152
if ( _options . CallCount == null )
@@ -354,7 +393,7 @@ private static void CreateChannels()
354
393
}
355
394
356
395
// Channel does not care about scheme
357
- var initialUri = new Uri ( _options . Url ! ) ;
396
+ var initialUri = _options . Url ! ;
358
397
var resolvedUri = initialUri . Authority ;
359
398
360
399
Log ( $ "gRPC client type: { _options . GrpcClientType } ") ;
0 commit comments