delphimvcframework/samples/serversentevents/SSEControllerU.pas
2017-07-05 00:19:38 +02:00

88 lines
2.4 KiB
ObjectPascal

unit SSEControllerU;
interface
uses
MVCFramework, MVCFramework.Commons;
type
[MVCPath('/')]
TSSEController = class(TMVCController)
public
[MVCPath('/stocks')]
[MVCHTTPMethod([httpGET])]
[MVCProduces('text/event-stream')]
procedure Index;
protected
procedure OnBeforeAction(Context: TWebContext; const AActionName: string;
var Handled: Boolean); override;
procedure OnAfterAction(Context: TWebContext;
const AActionName: string); override;
end;
implementation
uses
MVCFramework.Logger, System.SysUtils, StorageU;
procedure TSSEController.Index;
var
lLastEventID: Integer;
lCurrentEventID: Integer;
lMessage: string;
begin
// wait a little bit
Sleep(1000 + Random(2000));
// retrieve the last id received by the client reading the request header.
lLastEventID := StrToIntDef(Context.Request.Headers['Last-Event-ID'], 0);
// get the next message to send based on the last id already received by the client
lMessage := GetNextDataToSend(lLastEventID, lCurrentEventID);
// setting up the correct SSE headers
ContentType := 'text/event-stream';
Context.Response.SetCustomHeader('Cache-Control', 'no-cache');
// WARNING!! keep-alive heaer has been set directly on the server!
// Context.Response.SetCustomHeader('Connection', 'keep-alive');
// render the response using SSE compliant data format
// current event id (the client will resend this number at the next request)
ResponseStream.Append('id: ' + IntToStr(lCurrentEventID) + #13);
// The browser attempts to reconnect to the source roughly 3 seconds after
// each connection is closed. You can change that timeout by including a line
// beginning with "retry:", followed by the number of milliseconds to wait
// before trying to reconnect.
ResponseStream.Append('retry: 100'#13);
ResponseStream.Append('event: stockupdate'#13);
// actual message
ResponseStream.Append('data: ' + lMessage + #13#13);
// render all the stuff
RenderResponseStream;
end;
procedure TSSEController.OnAfterAction(Context: TWebContext;
const AActionName: string);
begin
{ Executed after each action }
inherited;
end;
procedure TSSEController.OnBeforeAction(Context: TWebContext;
const AActionName: string; var Handled: Boolean);
begin
{ Executed before each action
if handled is true (or an exception is raised) the actual
action will not be called }
inherited;
end;
end.