local sync
This commit is contained in:
parent
86dc2bfc35
commit
7a59f2b272
|
@ -246,7 +246,7 @@ begin
|
||||||
if ARaiseExceptionOnTimeout then
|
if ARaiseExceptionOnTimeout then
|
||||||
EIdReadTimeout.Toss(RSIdNoDataToRead) //exit, no data can be received
|
EIdReadTimeout.Toss(RSIdNoDataToRead) //exit, no data can be received
|
||||||
else
|
else
|
||||||
Exit;
|
Exit(0);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
SetLength(VBuffer, RecvBufferSize);
|
SetLength(VBuffer, RecvBufferSize);
|
||||||
|
|
|
@ -584,6 +584,8 @@ var
|
||||||
errorref: TSocketIOError;
|
errorref: TSocketIOError;
|
||||||
error: ISuperObject;
|
error: ISuperObject;
|
||||||
begin
|
begin
|
||||||
|
if ASocket = nil then Exit;
|
||||||
|
|
||||||
if not FConnections.ContainsValue(ASocket) and
|
if not FConnections.ContainsValue(ASocket) and
|
||||||
not FConnectionsGUID.ContainsValue(ASocket) then
|
not FConnectionsGUID.ContainsValue(ASocket) then
|
||||||
begin
|
begin
|
||||||
|
@ -1258,8 +1260,6 @@ begin
|
||||||
for context in FConnections.Values do
|
for context in FConnections.Values do
|
||||||
begin
|
begin
|
||||||
if context.IsDisconnected then Continue;
|
if context.IsDisconnected then Continue;
|
||||||
// if not context.IsSocketIO then
|
|
||||||
// raise EIdSocketIoUnhandledMessage.Create('Not a socket.io connection!');
|
|
||||||
|
|
||||||
if not Assigned(aCallback) then
|
if not Assigned(aCallback) then
|
||||||
WriteSocketIOMsg(context, ''{no room}, aMessage, nil)
|
WriteSocketIOMsg(context, ''{no room}, aMessage, nil)
|
||||||
|
@ -1274,8 +1274,6 @@ begin
|
||||||
for context in FConnectionsGUID.Values do
|
for context in FConnectionsGUID.Values do
|
||||||
begin
|
begin
|
||||||
if context.IsDisconnected then Continue;
|
if context.IsDisconnected then Continue;
|
||||||
// if not context.IsSocketIO then
|
|
||||||
// raise EIdSocketIoUnhandledMessage.Create('Not a socket.io connection!');
|
|
||||||
|
|
||||||
if not Assigned(aCallback) then
|
if not Assigned(aCallback) then
|
||||||
WriteSocketIOMsg(context, ''{no room}, aMessage, nil)
|
WriteSocketIOMsg(context, ''{no room}, aMessage, nil)
|
||||||
|
|
|
@ -1,314 +1,333 @@
|
||||||
unit uROHTTPWebsocketServer;
|
unit uROHTTPWebsocketServer;
|
||||||
|
|
||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, IdServerIOHandlerWebsocket, IdIOHandlerWebsocket,
|
Classes, IdServerIOHandlerWebsocket, IdIOHandlerWebsocket,
|
||||||
uROIndyHTTPServer, uROClientIntf, uROServer, uROHTTPDispatch,
|
uROIndyHTTPServer, uROClientIntf, uROServer, uROHTTPDispatch,
|
||||||
IdContext, IdCustomHTTPServer, IdCustomTCPServer, uROHash, uROServerIntf,
|
IdContext, IdCustomHTTPServer, IdCustomTCPServer, uROHash, uROServerIntf,
|
||||||
IdServerWebsocketContext, IdServerSocketIOHandling,
|
IdServerWebsocketContext, IdServerSocketIOHandling,
|
||||||
IdServerWebsocketHandling;
|
IdServerWebsocketHandling;
|
||||||
|
|
||||||
type
|
type
|
||||||
TROTransportContext = class;
|
TROTransportContext = class;
|
||||||
|
|
||||||
TROIndyHTTPWebsocketServer = class(TROIndyHTTPServer)
|
TROIndyHTTPWebsocketServer = class(TROIndyHTTPServer)
|
||||||
private
|
private
|
||||||
FOnCustomChannelExecute: TWebsocketChannelRequest;
|
FOnCustomChannelExecute: TWebsocketChannelRequest;
|
||||||
FSocketIO: TIdServerSocketIOHandling_Ext;
|
FSocketIO: TIdServerSocketIOHandling_Ext;
|
||||||
function GetSocketIO: TIdServerSocketIOHandling;
|
function GetSocketIO: TIdServerSocketIOHandling;
|
||||||
protected
|
protected
|
||||||
procedure InternalServerConnect(AThread: TIdContext); override;
|
FROTransportContexts: TInterfaceList;
|
||||||
procedure InternalServerCommandGet(AThread: TIdThreadClass;
|
procedure InternalServerConnect(AThread: TIdContext); override;
|
||||||
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo); override;
|
procedure InternalServerDisConnect(AThread: TIdContext); virtual;
|
||||||
procedure ProcessRemObjectsRequest(const AThread: TIdContext; const strmRequest: TMemoryStream; const strmResponse: TMemoryStream);
|
procedure InternalServerCommandGet(AThread: TIdThreadClass;
|
||||||
|
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo); override;
|
||||||
function GetDispatchersClass: TROMessageDispatchersClass; override;
|
procedure ProcessRemObjectsRequest(const AThread: TIdContext; const strmRequest: TMemoryStream; const strmResponse: TMemoryStream);
|
||||||
public
|
|
||||||
procedure AfterConstruction; override;
|
function GetDispatchersClass: TROMessageDispatchersClass; override;
|
||||||
destructor Destroy; override;
|
public
|
||||||
procedure Loaded; override;
|
procedure AfterConstruction; override;
|
||||||
|
destructor Destroy; override;
|
||||||
property SocketIO: TIdServerSocketIOHandling read GetSocketIO;
|
procedure Loaded; override;
|
||||||
property OnCustomChannelExecute: TWebsocketChannelRequest read FOnCustomChannelExecute write FOnCustomChannelExecute;
|
|
||||||
end;
|
property SocketIO: TIdServerSocketIOHandling read GetSocketIO;
|
||||||
|
property OnCustomChannelExecute: TWebsocketChannelRequest read FOnCustomChannelExecute write FOnCustomChannelExecute;
|
||||||
TROHTTPDispatcher_Websocket = class(TROHTTPDispatcher)
|
end;
|
||||||
public
|
|
||||||
function CanHandleMessage(const aTransport: IROTransport; aRequeststream : TStream): boolean; override;
|
TROHTTPDispatcher_Websocket = class(TROHTTPDispatcher)
|
||||||
end;
|
public
|
||||||
|
function CanHandleMessage(const aTransport: IROTransport; aRequeststream : TStream): boolean; override;
|
||||||
TROHTTPMessageDispatchers_WebSocket = class(TROHTTPMessageDispatchers)
|
end;
|
||||||
protected
|
|
||||||
function GetDispatcherClass : TROMessageDispatcherClass; override;
|
TROHTTPMessageDispatchers_WebSocket = class(TROHTTPMessageDispatchers)
|
||||||
end;
|
protected
|
||||||
|
function GetDispatcherClass : TROMessageDispatcherClass; override;
|
||||||
TROTransportContext = class(TInterfacedObject,
|
end;
|
||||||
IROTransport, IROTCPTransport,
|
|
||||||
IROActiveEventServer)
|
TROTransportContext = class(TInterfacedObject,
|
||||||
private
|
IROTransport, IROTCPTransport,
|
||||||
FROServer: TROIndyHTTPServer;
|
IROActiveEventServer)
|
||||||
FIdContext: TIdServerWSContext;
|
private
|
||||||
FEventCount: Integer;
|
FROServer: TROIndyHTTPServer;
|
||||||
FClientId: TGUID;
|
FIdContext: TIdServerWSContext;
|
||||||
private
|
FEventCount: Integer;
|
||||||
class var FGlobalEventCount: Integer;
|
FClientId: TGUID;
|
||||||
protected
|
private
|
||||||
{IROTransport}
|
class var FGlobalEventCount: Integer;
|
||||||
function GetTransportObject: TObject;
|
protected
|
||||||
{IROTCPTransport}
|
{IROTransport}
|
||||||
function GetClientAddress : string;
|
function GetTransportObject: TObject;
|
||||||
{IROActiveEventServer}
|
{IROTCPTransport}
|
||||||
procedure EventsRegistered(aSender : TObject; aClient: TGUID);
|
function GetClientAddress : string;
|
||||||
procedure DispatchEvent(anEventDataItem : TROEventData; aSessionReference : TGUID; aSender: TObject); // asender is TROEventRepository
|
{IROActiveEventServer}
|
||||||
public
|
procedure EventsRegistered(aSender : TObject; aClient: TGUID);
|
||||||
//constructor Create(aROServer: TROIndyHTTPServer; aIOHandler: TIdIOHandlerWebsocket);
|
procedure DispatchEvent(anEventDataItem : TROEventData; aSessionReference : TGUID; aSender: TObject); // asender is TROEventRepository
|
||||||
constructor Create(aROServer: TROIndyHTTPServer; aIdContext: TIdServerWSContext);
|
public
|
||||||
|
//constructor Create(aROServer: TROIndyHTTPServer; aIOHandler: TIdIOHandlerWebsocket);
|
||||||
property Context: TIdServerWSContext read FIdContext;
|
constructor Create(aROServer: TROIndyHTTPServer; aIdContext: TIdServerWSContext);
|
||||||
property ClientId: TGUID read FClientId write FClientId;
|
|
||||||
end;
|
property Context: TIdServerWSContext read FIdContext;
|
||||||
|
property ClientId: TGUID read FClientId write FClientId;
|
||||||
procedure Register;
|
end;
|
||||||
|
|
||||||
implementation
|
procedure Register;
|
||||||
|
|
||||||
uses
|
implementation
|
||||||
SysUtils, IdCoderMIME, Windows, uROEventRepository, uROSessions, uROClient,
|
|
||||||
uROClasses, StrUtils, uROIdServerWebsocketHandling;
|
uses
|
||||||
|
SysUtils, IdCoderMIME, Windows, uROEventRepository, uROSessions, uROClient,
|
||||||
procedure Register;
|
uROClasses, StrUtils, uROIdServerWebsocketHandling;
|
||||||
begin
|
|
||||||
RegisterComponents('RBK', [TROIndyHTTPWebsocketServer]);
|
procedure Register;
|
||||||
end;
|
begin
|
||||||
|
RegisterComponents('RBK', [TROIndyHTTPWebsocketServer]);
|
||||||
procedure TROIndyHTTPWebsocketServer.AfterConstruction;
|
|
||||||
begin
|
|
||||||
inherited;
|
|
||||||
|
|
||||||
FSocketIO := TIdServerSocketIOHandling_Ext.Create;
|
|
||||||
|
|
||||||
IndyServer.ContextClass := TROIdServerWSContext;
|
|
||||||
if Self.IndyServer.IOHandler = nil then
|
|
||||||
IndyServer.IOHandler := TIdServerIOHandlerWebsocket.Create(Self);
|
|
||||||
end;
|
|
||||||
|
|
||||||
destructor TROIndyHTTPWebsocketServer.Destroy;
|
|
||||||
begin
|
|
||||||
inherited;
|
|
||||||
FSocketIO.Free;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TROIndyHTTPWebsocketServer.GetDispatchersClass: TROMessageDispatchersClass;
|
|
||||||
begin
|
|
||||||
Result := TROHTTPMessageDispatchers_Websocket;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TROIndyHTTPWebsocketServer.GetSocketIO: TIdServerSocketIOHandling;
|
|
||||||
begin
|
|
||||||
Result := FSocketIO;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TROIndyHTTPWebsocketServer.InternalServerCommandGet(AThread: TIdThreadClass;
|
|
||||||
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
|
|
||||||
begin
|
|
||||||
(AThread as TIdServerWSContext).OnCustomChannelExecute := Self.OnCustomChannelExecute;
|
|
||||||
(AThread as TIdServerWSContext).SocketIO := Self.FSocketIO;
|
|
||||||
(AThread as TROIdServerWSContext).OnRemObjectsRequest := Self.ProcessRemObjectsRequest;
|
|
||||||
|
|
||||||
if not TROIdServerWebsocketHandling.ProcessServerCommandGet(AThread as TIdServerWSContext, ARequestInfo, AResponseInfo) then
|
|
||||||
inherited InternalServerCommandGet(AThread, ARequestInfo, AResponseInfo)
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TROIndyHTTPWebsocketServer.InternalServerConnect(AThread: TIdContext);
|
procedure TROIndyHTTPWebsocketServer.AfterConstruction;
|
||||||
begin
|
begin
|
||||||
inherited;
|
inherited;
|
||||||
(AThread as TIdServerWSContext).OnCustomChannelExecute := Self.OnCustomChannelExecute;
|
|
||||||
(AThread as TROIdServerWSContext).OnRemObjectsRequest := Self.ProcessRemObjectsRequest;
|
FSocketIO := TIdServerSocketIOHandling_Ext.Create;
|
||||||
end;
|
FROTransportContexts := TInterfaceList.Create;
|
||||||
|
|
||||||
procedure TROIndyHTTPWebsocketServer.Loaded;
|
IndyServer.ContextClass := TROIdServerWSContext;
|
||||||
begin
|
if Self.IndyServer.IOHandler = nil then
|
||||||
//do before inherited in case of designtime connection
|
IndyServer.IOHandler := TIdServerIOHandlerWebsocket.Create(Self);
|
||||||
if Self.IndyServer.IOHandler = nil then
|
IndyServer.OnDisconnect := InternalServerDisConnect;
|
||||||
IndyServer.IOHandler := TIdServerIOHandlerWebsocket.Create(Self);
|
end;
|
||||||
inherited;
|
|
||||||
end;
|
destructor TROIndyHTTPWebsocketServer.Destroy;
|
||||||
|
begin
|
||||||
procedure TROIndyHTTPWebsocketServer.ProcessRemObjectsRequest(
|
inherited;
|
||||||
const AThread: TIdContext; const strmRequest: TMemoryStream; const strmResponse: TMemoryStream);
|
FSocketIO.Free;
|
||||||
var
|
FROTransportContexts.Free;
|
||||||
cWSNR: array[0..High(C_ROWSNR)] of AnsiChar;
|
end;
|
||||||
msg: TROMessageDispatcher;
|
|
||||||
iMsgNr: Integer;
|
function TROIndyHTTPWebsocketServer.GetDispatchersClass: TROMessageDispatchersClass;
|
||||||
imsg: IROMessage;
|
begin
|
||||||
transport: TROTransportContext;
|
Result := TROHTTPMessageDispatchers_Websocket;
|
||||||
begin
|
end;
|
||||||
if strmRequest.Size < Length(C_ROWSNR) + SizeOf(iMsgNr) then Exit;
|
|
||||||
//read messagenr from the end
|
function TROIndyHTTPWebsocketServer.GetSocketIO: TIdServerSocketIOHandling;
|
||||||
strmRequest.Position := strmRequest.Size - Length(C_ROWSNR) - SizeOf(iMsgNr);
|
begin
|
||||||
strmRequest.Read(cWSNR[0], Length(C_ROWSNR));
|
Result := FSocketIO;
|
||||||
if (cWSNR <> C_ROWSNR) then Exit;
|
end;
|
||||||
strmRequest.Read(iMsgNr, SizeOf(iMsgNr));
|
|
||||||
strmRequest.Position := 0;
|
procedure TROIndyHTTPWebsocketServer.InternalServerCommandGet(AThread: TIdThreadClass;
|
||||||
//trunc extra data
|
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
|
||||||
strmRequest.Size := strmRequest.Size - Length(C_ROWSNR) - SizeOf(iMsgNr);
|
begin
|
||||||
transport := AThread.Data as TROTransportContext;
|
(AThread as TIdServerWSContext).OnCustomChannelExecute := Self.OnCustomChannelExecute;
|
||||||
//no RO transport object already made?
|
(AThread as TIdServerWSContext).SocketIO := Self.FSocketIO;
|
||||||
if transport = nil then
|
(AThread as TROIdServerWSContext).OnRemObjectsRequest := Self.ProcessRemObjectsRequest;
|
||||||
begin
|
|
||||||
//create IROTransport object
|
if not TROIdServerWebsocketHandling.ProcessServerCommandGet(AThread as TIdServerWSContext, ARequestInfo, AResponseInfo) then
|
||||||
transport := TROTransportContext.Create(Self, AThread as TIdServerWSContext);
|
inherited InternalServerCommandGet(AThread, ARequestInfo, AResponseInfo)
|
||||||
(transport as IROTransport)._AddRef;
|
end;
|
||||||
//attach RO transport to indy context
|
|
||||||
AThread.Data := transport;
|
|
||||||
//todo: enveloppes
|
procedure TROIndyHTTPWebsocketServer.InternalServerConnect(AThread: TIdContext);
|
||||||
//read client GUID the first time (needed to be able to send RO events)
|
begin
|
||||||
msg := Self.Dispatchers.FindDispatcher(transport, strmRequest);
|
inherited;
|
||||||
if msg = nil then
|
(AThread as TIdServerWSContext).OnCustomChannelExecute := Self.OnCustomChannelExecute;
|
||||||
raise EROException.Create('No suiteable message dispatcher found!');
|
(AThread as TROIdServerWSContext).OnRemObjectsRequest := Self.ProcessRemObjectsRequest;
|
||||||
imsg := (msg.MessageIntf as IROMessageCloneable).Clone;
|
end;
|
||||||
imsg.InitializeRead(transport);
|
|
||||||
imsg.ReadFromStream(strmRequest);
|
procedure TROIndyHTTPWebsocketServer.InternalServerDisConnect(
|
||||||
transport.ClientId := imsg.ClientID;
|
AThread: TIdContext);
|
||||||
imsg := nil;
|
var
|
||||||
Assert(not IsEqualGUID(transport.ClientID, EmptyGUID));
|
transport: TROTransportContext;
|
||||||
end;
|
begin
|
||||||
//EXECUTE FUNCTION
|
transport := AThread.Data as TROTransportContext;
|
||||||
Self.DispatchMessage(transport, strmRequest, strmResponse);
|
if transport <> nil then
|
||||||
//write number at end
|
FROTransportContexts.Remove(transport);
|
||||||
strmResponse.Position := strmResponse.Size;
|
//transport._Release;
|
||||||
strmResponse.Write(C_ROWSNR, Length(C_ROWSNR));
|
AThread.Data := nil;
|
||||||
strmResponse.Write(iMsgNr, SizeOf(iMsgNr));
|
end;
|
||||||
strmResponse.Position := 0;
|
|
||||||
end;
|
procedure TROIndyHTTPWebsocketServer.Loaded;
|
||||||
|
begin
|
||||||
{ TROTransport }
|
//do before inherited in case of designtime connection
|
||||||
|
if Self.IndyServer.IOHandler = nil then
|
||||||
constructor TROTransportContext.Create(aROServer: TROIndyHTTPServer;
|
IndyServer.IOHandler := TIdServerIOHandlerWebsocket.Create(Self);
|
||||||
aIdContext: TIdServerWSContext);
|
inherited;
|
||||||
begin
|
end;
|
||||||
FROServer := aROServer;
|
|
||||||
FIdContext := aIdContext;
|
procedure TROIndyHTTPWebsocketServer.ProcessRemObjectsRequest(
|
||||||
end;
|
const AThread: TIdContext; const strmRequest: TMemoryStream; const strmResponse: TMemoryStream);
|
||||||
|
var
|
||||||
procedure TROTransportContext.EventsRegistered(aSender: TObject; aClient: TGUID);
|
cWSNR: array[0..High(C_ROWSNR)] of AnsiChar;
|
||||||
begin
|
msg: TROMessageDispatcher;
|
||||||
//
|
iMsgNr: Integer;
|
||||||
end;
|
imsg: IROMessage;
|
||||||
|
transport: TROTransportContext;
|
||||||
procedure TROTransportContext.DispatchEvent(anEventDataItem: TROEventData;
|
begin
|
||||||
aSessionReference: TGUID; aSender: TObject);
|
if strmRequest.Size < Length(C_ROWSNR) + SizeOf(iMsgNr) then Exit;
|
||||||
var
|
//read messagenr from the end
|
||||||
i: Integer;
|
strmRequest.Position := strmRequest.Size - Length(C_ROWSNR) - SizeOf(iMsgNr);
|
||||||
LContext: TIdContext;
|
strmRequest.Read(cWSNR[0], Length(C_ROWSNR));
|
||||||
transport: TROTransportContext;
|
if (cWSNR <> C_ROWSNR) then Exit;
|
||||||
l: TList;
|
strmRequest.Read(iMsgNr, SizeOf(iMsgNr));
|
||||||
ws: TIdIOHandlerWebsocket;
|
strmRequest.Position := 0;
|
||||||
cWSNR: array[0..High(C_ROWSNR)] of AnsiChar;
|
//trunc extra data
|
||||||
begin
|
strmRequest.Size := strmRequest.Size - Length(C_ROWSNR) - SizeOf(iMsgNr);
|
||||||
l := FROServer.IndyServer.Contexts.LockList;
|
transport := AThread.Data as TROTransportContext;
|
||||||
try
|
//no RO transport object already made?
|
||||||
if l.Count <= 0 then Exit;
|
if transport = nil then
|
||||||
|
begin
|
||||||
anEventDataItem.Data.Position := anEventDataItem.Data.Size - Length(C_ROWSNR) - SizeOf(FEventCount);
|
//create IROTransport object
|
||||||
anEventDataItem.Data.Read(cWSNR[0], Length(cWSNR));
|
transport := TROTransportContext.Create(Self, AThread as TIdServerWSContext);
|
||||||
//event number not written already?
|
//(transport as IROTransport)._AddRef;
|
||||||
if cWSNR <> C_ROWSNR then
|
FROTransportContexts.Add(transport);
|
||||||
begin
|
//attach RO transport to indy context
|
||||||
//new event nr
|
AThread.Data := transport;
|
||||||
FEventCount := -1 * InterlockedIncrement(FGlobalEventCount); //negative = event, positive is normal RO message
|
//todo: enveloppes
|
||||||
//overflow? then start again from 0
|
//read client GUID the first time (needed to be able to send RO events)
|
||||||
if FEventCount > 0 then
|
msg := Self.Dispatchers.FindDispatcher(transport, strmRequest);
|
||||||
begin
|
if msg = nil then
|
||||||
InterlockedExchange(FGlobalEventCount, 0);
|
raise EROException.Create('No suiteable message dispatcher found!');
|
||||||
FEventCount := -1 * InterlockedIncrement(FGlobalEventCount); //negative = event, positive is normal RO message
|
imsg := (msg.MessageIntf as IROMessageCloneable).Clone;
|
||||||
end;
|
imsg.InitializeRead(transport);
|
||||||
Assert(FEventCount < 0);
|
imsg.ReadFromStream(strmRequest);
|
||||||
//write nr at end of message
|
transport.ClientId := imsg.ClientID;
|
||||||
anEventDataItem.Data.Position := anEventDataItem.Data.Size;
|
imsg := nil;
|
||||||
anEventDataItem.Data.Write(C_ROWSNR, Length(C_ROWSNR));
|
Assert(not IsEqualGUID(transport.ClientID, EmptyGUID));
|
||||||
anEventDataItem.Data.Write(FEventCount, SizeOf(FEventCount));
|
end;
|
||||||
anEventDataItem.Data.Position := 0;
|
//EXECUTE FUNCTION
|
||||||
end;
|
Self.DispatchMessage(transport, strmRequest, strmResponse);
|
||||||
|
//write number at end
|
||||||
//search specific client
|
strmResponse.Position := strmResponse.Size;
|
||||||
for i := 0 to l.Count - 1 do
|
strmResponse.Write(C_ROWSNR, Length(C_ROWSNR));
|
||||||
begin
|
strmResponse.Write(iMsgNr, SizeOf(iMsgNr));
|
||||||
LContext := TIdContext(l.Items[i]);
|
strmResponse.Position := 0;
|
||||||
transport := LContext.Data as TROTransportContext;
|
end;
|
||||||
if transport = nil then Continue;
|
|
||||||
if not IsEqualGUID(transport.ClientId, aSessionReference) then Continue;
|
{ TROTransport }
|
||||||
|
|
||||||
//direct write event data
|
constructor TROTransportContext.Create(aROServer: TROIndyHTTPServer;
|
||||||
ws := (LContext.Connection.IOHandler as TIdIOHandlerWebsocket);
|
aIdContext: TIdServerWSContext);
|
||||||
if not ws.IsWebsocket then Exit;
|
begin
|
||||||
ws.Lock;
|
FROServer := aROServer;
|
||||||
try
|
FIdContext := aIdContext;
|
||||||
try ws.Write(anEventDataItem.Data, wdtBinary) except {continue with other connections} end;
|
end;
|
||||||
finally
|
|
||||||
ws.Unlock;
|
procedure TROTransportContext.EventsRegistered(aSender: TObject; aClient: TGUID);
|
||||||
end;
|
begin
|
||||||
end;
|
//
|
||||||
finally
|
end;
|
||||||
anEventDataItem.RemoveRef;
|
|
||||||
FROServer.IndyServer.Contexts.UnlockList;
|
procedure TROTransportContext.DispatchEvent(anEventDataItem: TROEventData;
|
||||||
end;
|
aSessionReference: TGUID; aSender: TObject);
|
||||||
end;
|
var
|
||||||
|
i: Integer;
|
||||||
function TROTransportContext.GetClientAddress: string;
|
LContext: TIdContext;
|
||||||
begin
|
transport: TROTransportContext;
|
||||||
Result := FIdContext.Binding.PeerIP;
|
l: TList;
|
||||||
end;
|
ws: TIdIOHandlerWebsocket;
|
||||||
|
cWSNR: array[0..High(C_ROWSNR)] of AnsiChar;
|
||||||
function TROTransportContext.GetTransportObject: TObject;
|
begin
|
||||||
begin
|
l := FROServer.IndyServer.Contexts.LockList;
|
||||||
Result := FROServer;
|
try
|
||||||
end;
|
if l.Count <= 0 then Exit;
|
||||||
|
|
||||||
{ TROHTTPMessageDispatchers_WebSocket }
|
anEventDataItem.Data.Position := anEventDataItem.Data.Size - Length(C_ROWSNR) - SizeOf(FEventCount);
|
||||||
|
anEventDataItem.Data.Read(cWSNR[0], Length(cWSNR));
|
||||||
function TROHTTPMessageDispatchers_WebSocket.GetDispatcherClass: TROMessageDispatcherClass;
|
//event number not written already?
|
||||||
begin
|
if cWSNR <> C_ROWSNR then
|
||||||
result := TROHTTPDispatcher_Websocket;
|
begin
|
||||||
end;
|
//new event nr
|
||||||
|
FEventCount := -1 * InterlockedIncrement(FGlobalEventCount); //negative = event, positive is normal RO message
|
||||||
{ TROHTTPDispatcher_Websocket }
|
//overflow? then start again from 0
|
||||||
|
if FEventCount > 0 then
|
||||||
function TROHTTPDispatcher_Websocket.CanHandleMessage(
|
begin
|
||||||
const aTransport: IROTransport; aRequeststream: TStream): boolean;
|
InterlockedExchange(FGlobalEventCount, 0);
|
||||||
var
|
FEventCount := -1 * InterlockedIncrement(FGlobalEventCount); //negative = event, positive is normal RO message
|
||||||
tcp: IROTCPTransport;
|
end;
|
||||||
buf: array [0..5] of AnsiChar;
|
Assert(FEventCount < 0);
|
||||||
begin
|
//write nr at end of message
|
||||||
if aRequeststream = nil then result := FALSE else // for preventing warning in FPC
|
anEventDataItem.Data.Position := anEventDataItem.Data.Size;
|
||||||
result := FALSE;
|
anEventDataItem.Data.Write(C_ROWSNR, Length(C_ROWSNR));
|
||||||
|
anEventDataItem.Data.Write(FEventCount, SizeOf(FEventCount));
|
||||||
if not Enabled or
|
anEventDataItem.Data.Position := 0;
|
||||||
not Supports(aTransport, IROTCPTransport, tcp)
|
end;
|
||||||
then
|
|
||||||
Exit;
|
//search specific client
|
||||||
if (tcp as TROTransportContext).FIdContext.IOHandler.IsWebsocket then
|
for i := 0 to l.Count - 1 do
|
||||||
begin
|
begin
|
||||||
//we can handle all kind of messages, independent on the path, so check which kind of message we have
|
LContext := TIdContext(l.Items[i]);
|
||||||
Result := Self.Message.IsValidMessage((aRequeststream as TMemoryStream).Memory, aRequeststream.Size);
|
transport := LContext.Data as TROTransportContext;
|
||||||
|
if transport = nil then Continue;
|
||||||
//goes wrong with enveloppes!
|
if not IsEqualGUID(transport.ClientId, aSessionReference) then Continue;
|
||||||
//TROMessage.Envelopes_ProcessIncoming
|
|
||||||
if not Result and
|
//direct write event data
|
||||||
(aRequeststream.Size > 6) then
|
ws := (LContext.Connection.IOHandler as TIdIOHandlerWebsocket);
|
||||||
begin
|
if not ws.IsWebsocket then Exit;
|
||||||
aRequeststream.Read(buf,6);
|
ws.Lock;
|
||||||
Result := (buf[0] = EnvelopeSignature[0]) and
|
try
|
||||||
(buf[1] = EnvelopeSignature[1]) and
|
try ws.Write(anEventDataItem.Data, wdtBinary) except {continue with other connections} end;
|
||||||
(buf[2] = EnvelopeSignature[2]) and
|
finally
|
||||||
(buf[3] = EnvelopeSignature[3]) and
|
ws.Unlock;
|
||||||
(buf[4] = EnvelopeSignature[4]);
|
end;
|
||||||
aRequeststream.Position := 0;
|
end;
|
||||||
end;
|
finally
|
||||||
end
|
anEventDataItem.RemoveRef;
|
||||||
else
|
FROServer.IndyServer.Contexts.UnlockList;
|
||||||
Result := inherited CanHandleMessage(aTransport, aRequeststream);
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
end.
|
function TROTransportContext.GetClientAddress: string;
|
||||||
|
begin
|
||||||
|
Result := FIdContext.Binding.PeerIP;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TROTransportContext.GetTransportObject: TObject;
|
||||||
|
begin
|
||||||
|
Result := FROServer;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TROHTTPMessageDispatchers_WebSocket }
|
||||||
|
|
||||||
|
function TROHTTPMessageDispatchers_WebSocket.GetDispatcherClass: TROMessageDispatcherClass;
|
||||||
|
begin
|
||||||
|
result := TROHTTPDispatcher_Websocket;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TROHTTPDispatcher_Websocket }
|
||||||
|
|
||||||
|
function TROHTTPDispatcher_Websocket.CanHandleMessage(
|
||||||
|
const aTransport: IROTransport; aRequeststream: TStream): boolean;
|
||||||
|
var
|
||||||
|
tcp: IROTCPTransport;
|
||||||
|
buf: array [0..5] of AnsiChar;
|
||||||
|
begin
|
||||||
|
if aRequeststream = nil then result := FALSE else // for preventing warning in FPC
|
||||||
|
result := FALSE;
|
||||||
|
|
||||||
|
if not Enabled or
|
||||||
|
not Supports(aTransport, IROTCPTransport, tcp)
|
||||||
|
then
|
||||||
|
Exit;
|
||||||
|
if (tcp as TROTransportContext).FIdContext.IOHandler.IsWebsocket then
|
||||||
|
begin
|
||||||
|
//we can handle all kind of messages, independent on the path, so check which kind of message we have
|
||||||
|
Result := Self.Message.IsValidMessage((aRequeststream as TMemoryStream).Memory, aRequeststream.Size);
|
||||||
|
|
||||||
|
//goes wrong with enveloppes!
|
||||||
|
//TROMessage.Envelopes_ProcessIncoming
|
||||||
|
if not Result and
|
||||||
|
(aRequeststream.Size > 6) then
|
||||||
|
begin
|
||||||
|
aRequeststream.Read(buf,6);
|
||||||
|
Result := (buf[0] = EnvelopeSignature[0]) and
|
||||||
|
(buf[1] = EnvelopeSignature[1]) and
|
||||||
|
(buf[2] = EnvelopeSignature[2]) and
|
||||||
|
(buf[3] = EnvelopeSignature[3]) and
|
||||||
|
(buf[4] = EnvelopeSignature[4]);
|
||||||
|
aRequeststream.Position := 0;
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Result := inherited CanHandleMessage(aTransport, aRequeststream);
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
Loading…
Reference in a new issue