]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
1 | (* |
2 | * Licensed to the Apache Software Foundation (ASF) under one | |
3 | * or more contributor license agreements. See the NOTICE file | |
4 | * distributed with this work for additional information | |
5 | * regarding copyright ownership. The ASF licenses this file | |
6 | * to you under the Apache License, Version 2.0 (the | |
7 | * "License"); you may not use this file except in compliance | |
8 | * with the License. You may obtain a copy of the License at | |
9 | * | |
10 | * http://www.apache.org/licenses/LICENSE-2.0 | |
11 | * | |
12 | * Unless required by applicable law or agreed to in writing, | |
13 | * software distributed under the License is distributed on an | |
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
15 | * KIND, either express or implied. See the License for the | |
16 | * specific language governing permissions and limitations | |
17 | * under the License. | |
18 | *) | |
19 | ||
20 | unit TestServer; | |
21 | ||
22 | {$I ../src/Thrift.Defines.inc} | |
23 | {$WARN SYMBOL_PLATFORM OFF} | |
24 | ||
25 | {.$DEFINE RunEndless} // activate to interactively stress-test the server stop routines via Ctrl+C | |
26 | ||
27 | interface | |
28 | ||
29 | uses | |
30 | Windows, SysUtils, | |
31 | Generics.Collections, | |
32 | Thrift.Server, | |
33 | Thrift.Transport, | |
34 | Thrift.Transport.Pipes, | |
35 | Thrift.Protocol, | |
36 | Thrift.Protocol.JSON, | |
37 | Thrift.Protocol.Compact, | |
38 | Thrift.Collections, | |
39 | Thrift.Utils, | |
40 | Thrift.Test, | |
41 | Thrift, | |
42 | TestConstants, | |
43 | TestServerEvents, | |
44 | ConsoleHelper, | |
45 | Contnrs; | |
46 | ||
47 | type | |
48 | TTestServer = class | |
49 | public | |
50 | type | |
51 | ||
52 | ITestHandler = interface( TThriftTest.Iface ) | |
53 | procedure SetServer( const AServer : IServer ); | |
54 | procedure TestStop; | |
55 | end; | |
56 | ||
57 | TTestHandlerImpl = class( TInterfacedObject, ITestHandler ) | |
58 | private | |
59 | FServer : IServer; | |
60 | protected | |
61 | procedure testVoid(); | |
62 | function testBool(thing: Boolean): Boolean; | |
63 | function testString(const thing: string): string; | |
64 | function testByte(thing: ShortInt): ShortInt; | |
65 | function testI32(thing: Integer): Integer; | |
66 | function testI64(const thing: Int64): Int64; | |
67 | function testDouble(const thing: Double): Double; | |
68 | function testBinary(const thing: TBytes): TBytes; | |
69 | function testStruct(const thing: IXtruct): IXtruct; | |
70 | function testNest(const thing: IXtruct2): IXtruct2; | |
71 | function testMap(const thing: IThriftDictionary<Integer, Integer>): IThriftDictionary<Integer, Integer>; | |
72 | function testStringMap(const thing: IThriftDictionary<string, string>): IThriftDictionary<string, string>; | |
73 | function testSet(const thing: IHashSet<Integer>): IHashSet<Integer>; | |
74 | function testList(const thing: IThriftList<Integer>): IThriftList<Integer>; | |
75 | function testEnum(thing: TNumberz): TNumberz; | |
76 | function testTypedef(const thing: Int64): Int64; | |
77 | function testMapMap(hello: Integer): IThriftDictionary<Integer, IThriftDictionary<Integer, Integer>>; | |
78 | function testInsanity(const argument: IInsanity): IThriftDictionary<Int64, IThriftDictionary<TNumberz, IInsanity>>; | |
79 | function testMulti(arg0: ShortInt; arg1: Integer; const arg2: Int64; const arg3: IThriftDictionary<SmallInt, string>; arg4: TNumberz; const arg5: Int64): IXtruct; | |
80 | procedure testException(const arg: string); | |
81 | function testMultiException(const arg0: string; const arg1: string): IXtruct; | |
82 | procedure testOneway(secondsToSleep: Integer); | |
83 | ||
84 | procedure TestStop; | |
85 | procedure SetServer( const AServer : IServer ); | |
86 | end; | |
87 | ||
88 | class procedure PrintCmdLineHelp; | |
89 | class procedure InvalidArgs; | |
90 | ||
91 | class procedure LaunchAnonPipeChild( const app : string; const transport : IAnonymousPipeServerTransport); | |
92 | class procedure Execute( const args: array of string); | |
93 | end; | |
94 | ||
95 | implementation | |
96 | ||
97 | ||
98 | var g_Handler : TTestServer.ITestHandler = nil; | |
99 | ||
100 | ||
101 | function MyConsoleEventHandler( dwCtrlType : DWORD) : BOOL; stdcall; | |
102 | // Note that this Handler procedure is called from another thread | |
103 | var handler : TTestServer.ITestHandler; | |
104 | begin | |
105 | result := TRUE; | |
106 | try | |
107 | case dwCtrlType of | |
108 | CTRL_C_EVENT : Console.WriteLine( 'Ctrl+C pressed'); | |
109 | CTRL_BREAK_EVENT : Console.WriteLine( 'Ctrl+Break pressed'); | |
110 | CTRL_CLOSE_EVENT : Console.WriteLine( 'Received CloseTask signal'); | |
111 | CTRL_LOGOFF_EVENT : Console.WriteLine( 'Received LogOff signal'); | |
112 | CTRL_SHUTDOWN_EVENT : Console.WriteLine( 'Received Shutdown signal'); | |
113 | else | |
114 | Console.WriteLine( 'Received console event #'+IntToStr(Integer(dwCtrlType))); | |
115 | end; | |
116 | ||
117 | handler := g_Handler; | |
118 | if handler <> nil then handler.TestStop; | |
119 | ||
120 | except | |
121 | // catch all | |
122 | end; | |
123 | end; | |
124 | ||
125 | ||
126 | { TTestServer.TTestHandlerImpl } | |
127 | ||
128 | procedure TTestServer.TTestHandlerImpl.SetServer( const AServer: IServer); | |
129 | begin | |
130 | FServer := AServer; | |
131 | end; | |
132 | ||
133 | function TTestServer.TTestHandlerImpl.testByte(thing: ShortInt): ShortInt; | |
134 | begin | |
135 | Console.WriteLine('testByte("' + IntToStr( thing) + '")'); | |
136 | Result := thing; | |
137 | end; | |
138 | ||
139 | function TTestServer.TTestHandlerImpl.testDouble( const thing: Double): Double; | |
140 | begin | |
141 | Console.WriteLine('testDouble("' + FloatToStr( thing ) + '")'); | |
142 | Result := thing; | |
143 | end; | |
144 | ||
145 | function TTestServer.TTestHandlerImpl.testBinary(const thing: TBytes): TBytes; | |
146 | begin | |
147 | Console.WriteLine('testBinary('+IntToStr(Length(thing)) + ' bytes)'); | |
148 | Result := thing; | |
149 | end; | |
150 | ||
151 | function TTestServer.TTestHandlerImpl.testEnum(thing: TNumberz): TNumberz; | |
152 | begin | |
153 | Console.WriteLine('testEnum(' + EnumUtils<TNumberz>.ToString(Ord(thing)) + ')'); | |
154 | Result := thing; | |
155 | end; | |
156 | ||
157 | procedure TTestServer.TTestHandlerImpl.testException(const arg: string); | |
158 | begin | |
159 | Console.WriteLine('testException(' + arg + ')'); | |
160 | if ( arg = 'Xception') then | |
161 | begin | |
162 | raise TXception.Create( 1001, arg); | |
163 | end; | |
164 | ||
165 | if (arg = 'TException') then | |
166 | begin | |
167 | raise TException.Create('TException'); | |
168 | end; | |
169 | ||
170 | // else do not throw anything | |
171 | end; | |
172 | ||
173 | function TTestServer.TTestHandlerImpl.testI32(thing: Integer): Integer; | |
174 | begin | |
175 | Console.WriteLine('testI32("' + IntToStr( thing) + '")'); | |
176 | Result := thing; | |
177 | end; | |
178 | ||
179 | function TTestServer.TTestHandlerImpl.testI64( const thing: Int64): Int64; | |
180 | begin | |
181 | Console.WriteLine('testI64("' + IntToStr( thing) + '")'); | |
182 | Result := thing; | |
183 | end; | |
184 | ||
185 | function TTestServer.TTestHandlerImpl.testInsanity( | |
186 | const argument: IInsanity): IThriftDictionary<Int64, IThriftDictionary<TNumberz, IInsanity>>; | |
187 | var | |
188 | looney : IInsanity; | |
189 | first_map : IThriftDictionary<TNumberz, IInsanity>; | |
190 | second_map : IThriftDictionary<TNumberz, IInsanity>; | |
191 | insane : IThriftDictionary<Int64, IThriftDictionary<TNumberz, IInsanity>>; | |
192 | ||
193 | begin | |
194 | Console.Write('testInsanity('); | |
195 | if argument <> nil then Console.Write(argument.ToString); | |
196 | Console.WriteLine(')'); | |
197 | ||
198 | ||
199 | (** | |
200 | * So you think you've got this all worked, out eh? | |
201 | * | |
202 | * Creates a the returned map with these values and prints it out: | |
203 | * { 1 => { 2 => argument, | |
204 | * 3 => argument, | |
205 | * }, | |
206 | * 2 => { 6 => <empty Insanity struct>, }, | |
207 | * } | |
208 | * @return map<UserId, map<Numberz,Insanity>> - a map with the above values | |
209 | *) | |
210 | ||
211 | first_map := TThriftDictionaryImpl<TNumberz, IInsanity>.Create; | |
212 | second_map := TThriftDictionaryImpl<TNumberz, IInsanity>.Create; | |
213 | ||
214 | first_map.AddOrSetValue( TNumberz.TWO, argument); | |
215 | first_map.AddOrSetValue( TNumberz.THREE, argument); | |
216 | ||
217 | looney := TInsanityImpl.Create; | |
218 | second_map.AddOrSetValue( TNumberz.SIX, looney); | |
219 | ||
220 | insane := TThriftDictionaryImpl<Int64, IThriftDictionary<TNumberz, IInsanity>>.Create; | |
221 | ||
222 | insane.AddOrSetValue( 1, first_map); | |
223 | insane.AddOrSetValue( 2, second_map); | |
224 | ||
225 | Result := insane; | |
226 | end; | |
227 | ||
228 | function TTestServer.TTestHandlerImpl.testList( const thing: IThriftList<Integer>): IThriftList<Integer>; | |
229 | begin | |
230 | Console.Write('testList('); | |
231 | if thing <> nil then Console.Write(thing.ToString); | |
232 | Console.WriteLine(')'); | |
233 | Result := thing; | |
234 | end; | |
235 | ||
236 | function TTestServer.TTestHandlerImpl.testMap( | |
237 | const thing: IThriftDictionary<Integer, Integer>): IThriftDictionary<Integer, Integer>; | |
238 | begin | |
239 | Console.Write('testMap('); | |
240 | if thing <> nil then Console.Write(thing.ToString); | |
241 | Console.WriteLine(')'); | |
242 | Result := thing; | |
243 | end; | |
244 | ||
245 | function TTestServer.TTestHandlerImpl.TestMapMap( | |
246 | hello: Integer): IThriftDictionary<Integer, IThriftDictionary<Integer, Integer>>; | |
247 | var | |
248 | mapmap : IThriftDictionary<Integer, IThriftDictionary<Integer, Integer>>; | |
249 | pos : IThriftDictionary<Integer, Integer>; | |
250 | neg : IThriftDictionary<Integer, Integer>; | |
251 | i : Integer; | |
252 | begin | |
253 | Console.WriteLine('testMapMap(' + IntToStr( hello) + ')'); | |
254 | mapmap := TThriftDictionaryImpl<Integer, IThriftDictionary<Integer, Integer>>.Create; | |
255 | pos := TThriftDictionaryImpl<Integer, Integer>.Create; | |
256 | neg := TThriftDictionaryImpl<Integer, Integer>.Create; | |
257 | ||
258 | for i := 1 to 4 do | |
259 | begin | |
260 | pos.AddOrSetValue( i, i); | |
261 | neg.AddOrSetValue( -i, -i); | |
262 | end; | |
263 | ||
264 | mapmap.AddOrSetValue(4, pos); | |
265 | mapmap.AddOrSetValue( -4, neg); | |
266 | ||
267 | Result := mapmap; | |
268 | end; | |
269 | ||
270 | function TTestServer.TTestHandlerImpl.testMulti(arg0: ShortInt; arg1: Integer; | |
271 | const arg2: Int64; const arg3: IThriftDictionary<SmallInt, string>; | |
272 | arg4: TNumberz; const arg5: Int64): IXtruct; | |
273 | var | |
274 | hello : IXtruct; | |
275 | begin | |
276 | Console.WriteLine('testMulti()'); | |
277 | hello := TXtructImpl.Create; | |
278 | hello.String_thing := 'Hello2'; | |
279 | hello.Byte_thing := arg0; | |
280 | hello.I32_thing := arg1; | |
281 | hello.I64_thing := arg2; | |
282 | Result := hello; | |
283 | end; | |
284 | ||
285 | function TTestServer.TTestHandlerImpl.testMultiException( const arg0, arg1: string): IXtruct; | |
286 | var | |
287 | x2 : TXception2; | |
288 | begin | |
289 | Console.WriteLine('testMultiException(' + arg0 + ', ' + arg1 + ')'); | |
290 | if ( arg0 = 'Xception') then begin | |
291 | raise TXception.Create( 1001, 'This is an Xception'); // test the new rich CTOR | |
292 | end; | |
293 | ||
294 | if ( arg0 = 'Xception2') then begin | |
295 | x2 := TXception2.Create; // the old way still works too? | |
296 | x2.ErrorCode := 2002; | |
297 | x2.Struct_thing := TXtructImpl.Create; | |
298 | x2.Struct_thing.String_thing := 'This is an Xception2'; | |
299 | x2.UpdateMessageProperty; | |
300 | raise x2; | |
301 | end; | |
302 | ||
303 | Result := TXtructImpl.Create; | |
304 | Result.String_thing := arg1; | |
305 | end; | |
306 | ||
307 | function TTestServer.TTestHandlerImpl.testNest( const thing: IXtruct2): IXtruct2; | |
308 | begin | |
309 | Console.Write('testNest('); | |
310 | if thing <> nil then Console.Write(thing.ToString); | |
311 | Console.WriteLine(')'); | |
312 | ||
313 | Result := thing; | |
314 | end; | |
315 | ||
316 | procedure TTestServer.TTestHandlerImpl.testOneway(secondsToSleep: Integer); | |
317 | begin | |
318 | Console.WriteLine('testOneway(' + IntToStr( secondsToSleep )+ '), sleeping...'); | |
319 | Sleep(secondsToSleep * 1000); | |
320 | Console.WriteLine('testOneway finished'); | |
321 | end; | |
322 | ||
323 | function TTestServer.TTestHandlerImpl.testSet( const thing: IHashSet<Integer>):IHashSet<Integer>; | |
324 | begin | |
325 | Console.Write('testSet('); | |
326 | if thing <> nil then Console.Write(thing.ToString); | |
327 | Console.WriteLine(')');; | |
328 | ||
329 | Result := thing; | |
330 | end; | |
331 | ||
332 | procedure TTestServer.TTestHandlerImpl.testStop; | |
333 | begin | |
334 | if FServer <> nil then begin | |
335 | FServer.Stop; | |
336 | end; | |
337 | end; | |
338 | ||
339 | function TTestServer.TTestHandlerImpl.testBool(thing: Boolean): Boolean; | |
340 | begin | |
341 | Console.WriteLine('testBool(' + BoolToStr(thing,true) + ')'); | |
342 | Result := thing; | |
343 | end; | |
344 | ||
345 | function TTestServer.TTestHandlerImpl.testString( const thing: string): string; | |
346 | begin | |
347 | Console.WriteLine('teststring("' + thing + '")'); | |
348 | Result := thing; | |
349 | end; | |
350 | ||
351 | function TTestServer.TTestHandlerImpl.testStringMap( | |
352 | const thing: IThriftDictionary<string, string>): IThriftDictionary<string, string>; | |
353 | begin | |
354 | Console.Write('testStringMap('); | |
355 | if thing <> nil then Console.Write(thing.ToString); | |
356 | Console.WriteLine(')'); | |
357 | ||
358 | Result := thing; | |
359 | end; | |
360 | ||
361 | function TTestServer.TTestHandlerImpl.testTypedef( const thing: Int64): Int64; | |
362 | begin | |
363 | Console.WriteLine('testTypedef(' + IntToStr( thing) + ')'); | |
364 | Result := thing; | |
365 | end; | |
366 | ||
367 | procedure TTestServer.TTestHandlerImpl.TestVoid; | |
368 | begin | |
369 | Console.WriteLine('testVoid()'); | |
370 | end; | |
371 | ||
372 | function TTestServer.TTestHandlerImpl.testStruct( const thing: IXtruct): IXtruct; | |
373 | begin | |
374 | Console.Write('testStruct('); | |
375 | if thing <> nil then Console.Write(thing.ToString); | |
376 | Console.WriteLine(')'); | |
377 | ||
378 | Result := thing; | |
379 | end; | |
380 | ||
381 | ||
382 | { TTestServer } | |
383 | ||
384 | ||
385 | class procedure TTestServer.PrintCmdLineHelp; | |
386 | const HELPTEXT = ' [options]'#10 | |
387 | + #10 | |
388 | + 'Allowed options:'#10 | |
389 | + ' -h [ --help ] produce help message'#10 | |
390 | + ' --port arg (=9090) Port number to listen'#10 | |
391 | + ' --domain-socket arg Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)'#10 | |
392 | + ' --named-pipe arg Windows Named Pipe (e.g. MyThriftPipe)'#10 | |
393 | + ' --server-type arg (=simple) type of server, "simple", "thread-pool",'#10 | |
394 | + ' "threaded", or "nonblocking"'#10 | |
395 | + ' --transport arg (=socket) transport: buffered, framed, http, anonpipe'#10 | |
396 | + ' --protocol arg (=binary) protocol: binary, compact, json'#10 | |
397 | + ' --ssl Encrypted Transport using SSL'#10 | |
398 | + ' --processor-events processor-events'#10 | |
399 | + ' -n [ --workers ] arg (=4) Number of thread pools workers. Only valid for'#10 | |
400 | + ' thread-pool server type'#10 | |
401 | ; | |
402 | begin | |
403 | Console.WriteLine( ChangeFileExt(ExtractFileName(ParamStr(0)),'') + HELPTEXT); | |
404 | end; | |
405 | ||
406 | class procedure TTestServer.InvalidArgs; | |
407 | begin | |
408 | Console.WriteLine( 'Invalid args.'); | |
409 | Console.WriteLine( ChangeFileExt(ExtractFileName(ParamStr(0)),'') + ' -h for more information'); | |
410 | Abort; | |
411 | end; | |
412 | ||
413 | class procedure TTestServer.LaunchAnonPipeChild( const app : string; const transport : IAnonymousPipeServerTransport); | |
414 | //Launch child process and pass R/W anonymous pipe handles on cmd line. | |
415 | //This is a simple example and does not include elevation or other | |
416 | //advanced features. | |
417 | var pi : PROCESS_INFORMATION; | |
418 | si : STARTUPINFO; | |
419 | sArg, sHandles, sCmdLine : string; | |
420 | i : Integer; | |
421 | begin | |
422 | GetStartupInfo( si); //set startupinfo for the spawned process | |
423 | ||
424 | // preformat handles args | |
425 | sHandles := Format( '%d %d', | |
426 | [ Integer(transport.ClientAnonRead), | |
427 | Integer(transport.ClientAnonWrite)]); | |
428 | ||
429 | // pass all settings to client | |
430 | sCmdLine := app; | |
431 | for i := 1 to ParamCount do begin | |
432 | sArg := ParamStr(i); | |
433 | ||
434 | // add anonymous handles and quote strings where appropriate | |
435 | if sArg = '-anon' | |
436 | then sArg := sArg +' '+ sHandles | |
437 | else begin | |
438 | if Pos(' ',sArg) > 0 | |
439 | then sArg := '"'+sArg+'"'; | |
440 | end;; | |
441 | ||
442 | sCmdLine := sCmdLine +' '+ sArg; | |
443 | end; | |
444 | ||
445 | // spawn the child process | |
446 | Console.WriteLine('Starting client '+sCmdLine); | |
447 | Win32Check( CreateProcess( nil, PChar(sCmdLine), nil,nil,TRUE,0,nil,nil,si,pi)); | |
448 | ||
449 | CloseHandle( pi.hThread); | |
450 | CloseHandle( pi.hProcess); | |
451 | end; | |
452 | ||
453 | ||
454 | class procedure TTestServer.Execute( const args: array of string); | |
455 | var | |
456 | Port : Integer; | |
457 | ServerEvents : Boolean; | |
458 | sPipeName : string; | |
459 | testHandler : ITestHandler; | |
460 | testProcessor : IProcessor; | |
461 | ServerTrans : IServerTransport; | |
462 | ServerEngine : IServer; | |
463 | anonymouspipe : IAnonymousPipeServerTransport; | |
464 | namedpipe : INamedPipeServerTransport; | |
465 | TransportFactory : ITransportFactory; | |
466 | ProtocolFactory : IProtocolFactory; | |
467 | i, numWorker : Integer; | |
468 | s : string; | |
469 | protType : TKnownProtocol; | |
470 | servertype : TServerType; | |
471 | endpoint : TEndpointTransport; | |
472 | layered : TLayeredTransports; | |
473 | UseSSL : Boolean; // include where appropriate (TLayeredTransport?) | |
474 | begin | |
475 | try | |
476 | ServerEvents := FALSE; | |
477 | protType := prot_Binary; | |
478 | servertype := srv_Simple; | |
479 | endpoint := trns_Sockets; | |
480 | layered := []; | |
481 | UseSSL := FALSE; | |
482 | Port := 9090; | |
483 | sPipeName := ''; | |
484 | numWorker := 4; | |
485 | ||
486 | i := 0; | |
487 | while ( i < Length(args) ) do begin | |
488 | s := args[i]; | |
489 | Inc(i); | |
490 | ||
491 | // Allowed options: | |
492 | if (s = '-h') or (s = '--help') then begin | |
493 | // -h [ --help ] produce help message | |
494 | PrintCmdLineHelp; | |
495 | Exit; | |
496 | end | |
497 | else if (s = '--port') then begin | |
498 | // --port arg (=9090) Port number to listen | |
499 | s := args[i]; | |
500 | Inc(i); | |
501 | Port := StrToIntDef( s, Port); | |
502 | end | |
503 | else if (s = '--domain-socket') then begin | |
504 | // --domain-socket arg Unix Domain Socket (e.g. /tmp/ThriftTest.thrift) | |
505 | raise Exception.Create('domain-socket not supported'); | |
506 | end | |
507 | else if (s = '--named-pipe') then begin | |
508 | // --named-pipe arg Windows Named Pipe (e.g. MyThriftPipe) | |
509 | endpoint := trns_NamedPipes; | |
510 | sPipeName := args[i]; // -pipe <name> | |
511 | Inc( i ); | |
512 | end | |
513 | else if (s = '--server-type') then begin | |
514 | // --server-type arg (=simple) type of server, | |
515 | // arg = "simple", "thread-pool", "threaded", or "nonblocking" | |
516 | s := args[i]; | |
517 | Inc(i); | |
518 | ||
519 | if s = 'simple' then servertype := srv_Simple | |
520 | else if s = 'thread-pool' then servertype := srv_Threadpool | |
521 | else if s = 'threaded' then servertype := srv_Threaded | |
522 | else if s = 'nonblocking' then servertype := srv_Nonblocking | |
523 | else InvalidArgs; | |
524 | end | |
525 | else if (s = '--transport') then begin | |
526 | // --transport arg (=buffered) transport: buffered, framed, http | |
527 | s := args[i]; | |
528 | Inc(i); | |
529 | ||
530 | if s = 'buffered' then Include( layered, trns_Buffered) | |
531 | else if s = 'framed' then Include( layered, trns_Framed) | |
532 | else if s = 'http' then endpoint := trns_MsxmlHttp | |
533 | else if s = 'winhttp' then endpoint := trns_WinHttp | |
534 | else if s = 'anonpipe' then endpoint := trns_AnonPipes | |
535 | else InvalidArgs; | |
536 | end | |
537 | else if (s = '--protocol') then begin | |
538 | // --protocol arg (=binary) protocol: binary, compact, json | |
539 | s := args[i]; | |
540 | Inc(i); | |
541 | ||
542 | if s = 'binary' then protType := prot_Binary | |
543 | else if s = 'compact' then protType := prot_Compact | |
544 | else if s = 'json' then protType := prot_JSON | |
545 | else InvalidArgs; | |
546 | end | |
547 | else if (s = '--ssl') then begin | |
548 | // --ssl Encrypted Transport using SSL | |
549 | UseSSL := TRUE; | |
550 | end | |
551 | else if (s = '--processor-events') then begin | |
552 | // --processor-events processor-events | |
553 | ServerEvents := TRUE; | |
554 | end | |
555 | else if (s = '-n') or (s = '--workers') then begin | |
556 | // -n [ --workers ] arg (=4) Number of thread pools workers. | |
557 | // Only valid for thread-pool server type | |
558 | s := args[i]; | |
559 | numWorker := StrToIntDef(s,0); | |
560 | if numWorker > 0 | |
561 | then Inc(i) | |
562 | else numWorker := 4; | |
563 | end | |
564 | else begin | |
565 | InvalidArgs; | |
566 | end; | |
567 | end; | |
568 | ||
569 | ||
570 | Console.WriteLine('Server configuration: '); | |
571 | ||
572 | // create protocol factory, default to BinaryProtocol | |
573 | case protType of | |
574 | prot_Binary : ProtocolFactory := TBinaryProtocolImpl.TFactory.Create( BINARY_STRICT_READ, BINARY_STRICT_WRITE); | |
575 | prot_JSON : ProtocolFactory := TJSONProtocolImpl.TFactory.Create; | |
576 | prot_Compact : ProtocolFactory := TCompactProtocolImpl.TFactory.Create; | |
577 | else | |
578 | raise Exception.Create('Unhandled protocol'); | |
579 | end; | |
580 | ASSERT( ProtocolFactory <> nil); | |
581 | Console.WriteLine('- '+THRIFT_PROTOCOLS[protType]+' protocol'); | |
582 | ||
583 | case endpoint of | |
584 | ||
585 | trns_Sockets : begin | |
586 | Console.WriteLine('- sockets (port '+IntToStr(port)+')'); | |
587 | if (trns_Buffered in layered) then Console.WriteLine('- buffered'); | |
588 | servertrans := TServerSocketImpl.Create( Port, 0, (trns_Buffered in layered)); | |
589 | end; | |
590 | ||
591 | trns_MsxmlHttp, | |
592 | trns_WinHttp : begin | |
593 | raise Exception.Create('HTTP server transport not implemented'); | |
594 | end; | |
595 | ||
596 | trns_NamedPipes : begin | |
597 | Console.WriteLine('- named pipe ('+sPipeName+')'); | |
598 | namedpipe := TNamedPipeServerTransportImpl.Create( sPipeName, 4096, PIPE_UNLIMITED_INSTANCES); | |
599 | servertrans := namedpipe; | |
600 | end; | |
601 | ||
602 | trns_AnonPipes : begin | |
603 | Console.WriteLine('- anonymous pipes'); | |
604 | anonymouspipe := TAnonymousPipeServerTransportImpl.Create; | |
605 | servertrans := anonymouspipe; | |
606 | end | |
607 | ||
608 | else | |
609 | raise Exception.Create('Unhandled endpoint transport'); | |
610 | end; | |
611 | ASSERT( servertrans <> nil); | |
612 | ||
613 | if UseSSL then begin | |
614 | raise Exception.Create('SSL not implemented'); | |
615 | end; | |
616 | ||
617 | if (trns_Framed in layered) then begin | |
618 | Console.WriteLine('- framed transport'); | |
619 | TransportFactory := TFramedTransportImpl.TFactory.Create | |
620 | end | |
621 | else begin | |
622 | TransportFactory := TTransportFactoryImpl.Create; | |
623 | end; | |
624 | ASSERT( TransportFactory <> nil); | |
625 | ||
626 | testHandler := TTestHandlerImpl.Create; | |
627 | testProcessor := TThriftTest.TProcessorImpl.Create( testHandler ); | |
628 | ||
629 | case servertype of | |
630 | srv_Simple : begin | |
631 | ServerEngine := TSimpleServer.Create( testProcessor, ServerTrans, TransportFactory, ProtocolFactory); | |
632 | end; | |
633 | ||
634 | srv_Nonblocking : begin | |
635 | raise Exception.Create(SERVER_TYPES[servertype]+' server not implemented'); | |
636 | end; | |
637 | ||
638 | srv_Threadpool, | |
639 | srv_Threaded: begin | |
640 | if numWorker > 1 then {use here}; | |
641 | raise Exception.Create(SERVER_TYPES[servertype]+' server not implemented'); | |
642 | end; | |
643 | ||
644 | else | |
645 | raise Exception.Create('Unhandled server type'); | |
646 | end; | |
647 | ASSERT( ServerEngine <> nil); | |
648 | ||
649 | testHandler.SetServer( ServerEngine); | |
650 | ||
651 | // test events? | |
652 | if ServerEvents then begin | |
653 | Console.WriteLine('- server events test enabled'); | |
654 | ServerEngine.ServerEvents := TServerEventsImpl.Create; | |
655 | end; | |
656 | ||
657 | // start the client now when we have the anon handles, but before the server starts | |
658 | if endpoint = trns_AnonPipes | |
659 | then LaunchAnonPipeChild( ExtractFilePath(ParamStr(0))+'client.exe', anonymouspipe); | |
660 | ||
661 | // install Ctrl+C handler before the server starts | |
662 | g_Handler := testHandler; | |
663 | SetConsoleCtrlHandler( @MyConsoleEventHandler, TRUE); | |
664 | ||
665 | Console.WriteLine(''); | |
666 | repeat | |
667 | Console.WriteLine('Starting the server ...'); | |
668 | serverEngine.Serve; | |
669 | until {$IFDEF RunEndless} FALSE {$ELSE} TRUE {$ENDIF}; | |
670 | ||
671 | testHandler.SetServer( nil); | |
672 | g_Handler := nil; | |
673 | ||
674 | except | |
675 | on E: EAbort do raise; | |
676 | on E: Exception do begin | |
677 | Console.WriteLine( E.Message + #10 + E.StackTrace ); | |
678 | end; | |
679 | end; | |
680 | Console.WriteLine( 'done.'); | |
681 | end; | |
682 | ||
683 | ||
684 | end. |