testsse.lpr 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. program testsse;
  2. {$ifdef mswindows}
  3. {$apptype console}
  4. {$endif}
  5. uses sysutils, custApp, httpdefs, fphttpclient, httproute, fphttpserver;
  6. Type
  7. { TEventSourceApp }
  8. TEventSourceApp = class(TCustomApplication)
  9. private
  10. FPort : Integer;
  11. FSource: TCustomHTTPEventSource;
  12. procedure DoHTTPRequest(Sender: TObject; var ARequest: TFPHTTPConnectionRequest; var AResponse: TFPHTTPConnectionResponse);
  13. procedure DoServerEvents(ARequest: TRequest; AResponse: TResponse);
  14. procedure ReadEvents(aSender: TObject; aSource: TCustomHTTPEventSource);
  15. procedure RunEventLoop;
  16. Protected
  17. Procedure StartServer;
  18. procedure StartClient;
  19. Procedure Usage(const aMsg : string);
  20. procedure DoRun; override;
  21. end;
  22. procedure TEventSourceApp.DoServerEvents(ARequest: TRequest; AResponse: TResponse);
  23. var
  24. lEvent : THTTPServerEvent;
  25. i,lStartID : Integer;
  26. lAccept : String;
  27. begin
  28. lAccept:=aRequest.Accept;
  29. if Pos('text/event-stream',lAccept)<>0 then
  30. begin
  31. aResponse.StartServerEvents;
  32. LStartID:=StrToIntDef(aRequest.CustomHeaders.Values['Last-Event-ID'],0);
  33. for I:=lStartID+1 to lStartID+10 do
  34. begin
  35. lEvent:=Default(THTTPServerEvent);
  36. lEvent.Data:=['Ping event '+IntToStr(I)];
  37. lEvent.Event:='ping';
  38. lEvent.ID:=IntToStr(i);
  39. aResponse.SendServerEvent(lEvent);
  40. sleep(500);
  41. end;
  42. end;
  43. end;
  44. procedure TEventSourceApp.DoHTTPRequest(Sender: TObject; var ARequest: TFPHTTPConnectionRequest;
  45. var AResponse: TFPHTTPConnectionResponse);
  46. begin
  47. HTTPRouter.RouteRequest(aRequest,aResponse);
  48. end;
  49. procedure TEventSourceApp.ReadEvents(aSender: TObject; aSource: TCustomHTTPEventSource);
  50. begin
  51. FSource:=aSource;
  52. end;
  53. Procedure TEventSourceApp.RunEventLoop;
  54. var
  55. lEvent : THTTPServerEvent;
  56. begin
  57. while not FSource.EOF do
  58. begin
  59. if FSource.ReadEvent(lEvent) then
  60. begin
  61. Write('Got event');
  62. if lEvent.Event<>'' then
  63. Write(' of type: ',lEvent.Event);
  64. if lEvent.Event<>'' then
  65. Write(' with id: ',lEvent.Id);
  66. Writeln('');
  67. Writeln(lEvent.Data[0]);
  68. Writeln('');
  69. end;
  70. end;
  71. FSource.Free;
  72. Terminate;
  73. end;
  74. procedure TEventSourceApp.StartServer;
  75. var
  76. lServer : TFPHttpServer;
  77. begin
  78. Writeln('Starting server, listening for requests on port ',FPort);
  79. Writeln('Send requests to http://localhost:',FPort,'/events');
  80. HTTPRouter.RegisterRoute('/events',rmAll,@DoServerEvents);
  81. lServer:=TFPHttpServer.Create(Self);
  82. try
  83. lServer.OnRequest:=@DoHTTPRequest;
  84. lServer.Port:=FPort;
  85. lServer.Active:=True;
  86. finally
  87. lServer.Free;
  88. end;
  89. end;
  90. Procedure TEventSourceApp.StartClient;
  91. var
  92. lHTTP : TFPHTTPClient;
  93. lLast : Integer;
  94. lUrl,lResult : string;
  95. begin
  96. lHTTP:=TFPHTTPClient.Create(Self);
  97. lUrl:=GetOptionValue('u','url');
  98. if lUrl='' then
  99. lUrl:=Format('http://localhost:%d/events',[FPort]);
  100. // lHTTP.OnEventStream:=@ReadEvents;
  101. lHTTP.AddHeader('Accept','text/event-stream');
  102. lLast:=StrToIntDef(GetOptionValue('l','last-id'),0);
  103. if lLast<>0 then
  104. lHTTP.AddHeader('Last-Event-Id',IntToStr(lLast));
  105. FSource:=lHTTP.GetEventSource('GET',lURL);
  106. // lResult:=lHTTP.Get(lUrl);
  107. if FSource=nil then
  108. Writeln('Get returned (Result=',lResult,')')
  109. else
  110. begin
  111. Writeln('Have event source. Listening for events...');
  112. RunEventLoop;
  113. end;
  114. end;
  115. Procedure TEventSourceApp.Usage(const aMsg : String);
  116. begin
  117. if aMsg<>'' then
  118. Writeln('Error: ',aMsg);
  119. Writeln('Usage : ',ExtractFileName(ParamStr(0)),' [options]');
  120. Writeln('Where options is one of :');
  121. Writeln('-h --help This help');
  122. Writeln('-c --client Run in client mode');
  123. Writeln('-p --port=PORT Set server HTTP port number (both client and server)');
  124. Writeln('-l --last-id=ID Set last event ID (client)');
  125. Writeln('-s --server Run in server mode');
  126. Writeln('-u --url:URL Connect to this URL.');
  127. Writeln(' If not set, the default URL for testsse -r is used, taking -p in account');
  128. ExitCode:=Ord(aMsg<>'');
  129. end;
  130. Procedure TEventSourceApp.DoRun;
  131. var
  132. Err : string;
  133. begin
  134. Terminate;
  135. Err:=CheckOptions('chsp:l:u:',['client','help','server','port:','last-id:','url:']);
  136. if (Err<>'') or HasOption('h','help') then
  137. begin
  138. Usage(Err);
  139. exit;
  140. end;
  141. FPort:=StrToIntDef(GetOptionValue('p','port'),8080);
  142. if HasOption('s','server') then
  143. StartServer
  144. else if HasOption('c','client') then
  145. StartClient
  146. else
  147. Usage('Need run mode');
  148. end;
  149. begin
  150. CustomApplication:=TEventSourceApp.Create(Nil);
  151. CustomApplication.Initialize;
  152. CustomApplication.Run;
  153. CustomApplication.Free;
  154. end.