Support 1.1 beta

This commit is contained in:
Daniele Teti 2016-10-14 15:19:06 +02:00
parent 76d2d38432
commit 5ce5edb341
20 changed files with 1044 additions and 432 deletions

View File

@ -1,6 +1,6 @@
// Stomp Client for Embarcadero Delphi & FreePascal
// Tested With ApacheMQ 5.2/5.3, Apache Apollo 1.2, RabbitMQ
// Copyright (c) 2009-2015 Daniele Teti
// Copyright (c) 2009-2016 Daniele Teti
//
// Contributors:
// Daniel Gaspary: dgaspary@gmail.com
@ -28,6 +28,7 @@ interface
uses
StompTypes,
SysUtils,
DateUtils,
{$IFNDEF USESYNAPSE}
IdTCPClient,
@ -46,6 +47,7 @@ type
{ TStompClient }
TSenderFrameEvent = procedure(AFrame: IStompFrame) of object;
THeartBeatThread = class;
TStompClient = class(TInterfacedObject, IStompClient)
private
@ -76,6 +78,13 @@ type
FClientID: string;
FAcceptVersion: TStompAcceptProtocol;
FConnectionTimeout: UInt32;
FOutgoingHeartBeats: Int64;
FIncomingHeartBeats: Int64;
FLock: TObject;
FHeartBeatThread: THeartBeatThread;
FServerIncomingHeartBeats: Int64;
FServerOutgoingHeartBeats: Int64;
procedure ParseHeartBeat(Headers: IStompHeaders);
procedure SetReceiptTimeout(const Value: Integer);
procedure SetConnectionTimeout(const Value: UInt32);
@ -91,7 +100,9 @@ type
procedure MergeHeaders(var AFrame: IStompFrame;
var AHeaders: IStompHeaders);
procedure SendFrame(AFrame: IStompFrame);
procedure SendHeartBeat;
function FormatErrorFrame(const AErrorFrame: IStompFrame): string;
function ServerSupportsHeartBeat: boolean;
public
function SetPassword(const Value: string): IStompClient;
function SetUserName(const Value: string): IStompClient;
@ -103,7 +114,7 @@ type
procedure Connect(Host: string = '127.0.0.1';
Port: Integer = DEFAULT_STOMP_PORT; ClientID: string = '';
AcceptVersion: TStompAcceptProtocol = TStompAcceptProtocol.
STOMP_Version_1_0);
Ver_1_0);
procedure Disconnect;
procedure Subscribe(QueueOrTopicName: string;
Ack: TAckMode = TAckMode.amAuto; Headers: IStompHeaders = nil);
@ -125,8 +136,9 @@ type
class function CreateAndConnect(Host: string = '127.0.0.1';
Port: Integer = DEFAULT_STOMP_PORT; ClientID: string = '';
AcceptVersion: TStompAcceptProtocol = TStompAcceptProtocol.
STOMP_Version_1_0): IStompClient; overload; virtual;
Ver_1_0): IStompClient; overload; virtual;
destructor Destroy; override;
procedure SetHeartBeat(const OutgoingHeartBeats, IncomingHeartBeats: Int64);
function Clone: IStompClient;
function Connected: boolean;
function SetReceiveTimeout(const AMilliSeconds: Cardinal): IStompClient;
@ -145,20 +157,34 @@ type
write FOnAfterSendFrame;
end;
THeartBeatThread = class(TThread)
private
FStompClient: TStompClient;
FLock: TObject;
FOutgoingHeatBeatTimeout: Int64;
protected
procedure Execute; override;
public
constructor Create(StompClient: TStompClient; Lock: TObject;
OutgoingHeatBeatTimeout: Int64); virtual;
end;
implementation
{$IFDEF FPC}
const
CHAR0 = #0;
{$ELSE}
uses
// Windows, // Remove windows unit for compiling on ios
IdGlobal,
IdGlobalProtocols,
Character;
Character, Winapi.Windows;
{$ENDIF}
{ TStompClient }
@ -170,8 +196,8 @@ begin
if FTransactions.IndexOf(TransactionIdentifier) > -1 then
begin
Frame := TStompFrame.Create;
Frame.SetCommand('ABORT');
Frame.GetHeaders.Add('transaction', TransactionIdentifier);
Frame.Command := 'ABORT';
Frame.Headers.Add('transaction', TransactionIdentifier);
SendFrame(Frame);
FInTransaction := False;
FTransactions.Delete(FTransactions.IndexOf(TransactionIdentifier));
@ -188,10 +214,10 @@ var
Frame: IStompFrame;
begin
Frame := TStompFrame.Create;
Frame.SetCommand('ACK');
Frame.GetHeaders.Add(TStompHeaders.MESSAGE_ID, MessageID);
Frame.Command := 'ACK';
Frame.Headers.Add(TStompHeaders.MESSAGE_ID, MessageID);
if TransactionIdentifier <> '' then
Frame.GetHeaders.Add('transaction', TransactionIdentifier);
Frame.Headers.Add('transaction', TransactionIdentifier);
SendFrame(Frame);
end;
@ -202,8 +228,8 @@ begin
if FTransactions.IndexOf(TransactionIdentifier) = -1 then
begin
Frame := TStompFrame.Create;
Frame.SetCommand('BEGIN');
Frame.GetHeaders.Add('transaction', TransactionIdentifier);
Frame.Command := 'BEGIN';
Frame.Headers.Add('transaction', TransactionIdentifier);
SendFrame(Frame);
// CheckReceipt(Frame);
FInTransaction := True;
@ -222,7 +248,7 @@ end;
// if FEnableReceipts then
// begin
// ReceiptID := inttostr(GetTickCount);
// Frame.GetHeaders.Add('receipt', ReceiptID);
// Frame.Headers.Add('receipt', ReceiptID);
// SendFrame(Frame);
// Receipt(ReceiptID);
// end
@ -246,8 +272,8 @@ begin
if FTransactions.IndexOf(TransactionIdentifier) > -1 then
begin
Frame := TStompFrame.Create;
Frame.SetCommand('COMMIT');
Frame.GetHeaders.Add('transaction', TransactionIdentifier);
Frame.Command := 'COMMIT';
Frame.Headers.Add('transaction', TransactionIdentifier);
SendFrame(Frame);
FInTransaction := False;
FTransactions.Delete(FTransactions.IndexOf(TransactionIdentifier));
@ -262,6 +288,7 @@ procedure TStompClient.Connect(Host: string; Port: Integer; ClientID: string;
AcceptVersion: TStompAcceptProtocol);
var
Frame: IStompFrame;
lHeartBeat: string;
begin
FHost := Host;
FPort := Port;
@ -283,34 +310,48 @@ begin
{$ENDIF}
Frame := TStompFrame.Create;
Frame.SetCommand('CONNECT');
Frame.Command := 'CONNECT';
FClientAcceptProtocolVersion := AcceptVersion;
if TStompAcceptProtocol.STOMP_Version_1_1 in [FClientAcceptProtocolVersion]
if TStompAcceptProtocol.Ver_1_1 in [FClientAcceptProtocolVersion]
then
begin
Frame.GetHeaders.Add('heart-beat', '0,1000'); // stomp 1.1
Frame.GetHeaders.Add('accept-version', '1.1'); // stomp 1.1
Frame.Headers.Add('accept-version', '1.1'); // stomp 1.1
lHeartBeat := Format('%d,%d', [FOutgoingHeartBeats, FIncomingHeartBeats]);
Frame.Headers.Add('heart-beat', lHeartBeat); // stomp 1.1
end
else
begin
Frame.Headers.Add('accept-version', '1.0'); // stomp 1.0
end;
Frame.GetHeaders.Add('login', FUserName).Add('passcode', FPassword);
Frame.Headers.Add('login', FUserName).Add('passcode', FPassword);
FClientID := ClientID;
if ClientID <> '' then
begin
Frame.GetHeaders.Add('client-id', ClientID);
Frame.Headers.Add('client-id', ClientID);
end;
SendFrame(Frame);
Frame := nil;
while Frame = nil do
Frame := Receive;
if Frame.GetCommand = 'ERROR' then
if Frame.Command = 'ERROR' then
raise EStomp.Create(FormatErrorFrame(Frame));
if Frame.GetCommand = 'CONNECTED' then
if Frame.Command = 'CONNECTED' then
begin
FSession := Frame.GetHeaders.Value('session');
FServerProtocolVersion := Frame.GetHeaders.Value('version'); // stomp 1.1
FServer := Frame.GetHeaders.Value('server'); // stomp 1.1
FSession := Frame.Headers.Value('session');
FServerProtocolVersion := Frame.Headers.Value('version'); // stomp 1.1
FServer := Frame.Headers.Value('server'); // stomp 1.1
ParseHeartBeat(Frame.Headers);
end;
// Let's start the hearbeat thread
if ServerSupportsHeartBeat then
begin
FHeartBeatThread := THeartBeatThread.Create(Self, FLock, FServerOutgoingHeartBeats);
FHeartBeatThread.Start;
end;
{ todo: 'Call event?' }
except
on E: Exception do
@ -342,6 +383,7 @@ end;
constructor TStompClient.Create;
begin
inherited;
FLock := TObject.Create;
FInTransaction := False;
FSession := '';
FUserName := 'guest';
@ -350,6 +392,8 @@ begin
FTimeout := 200;
FReceiptTimeout := FTimeout;
FConnectionTimeout := 1000 * 10; // 10secs
FIncomingHeartBeats := 10000; // 10secs
FOutgoingHeartBeats := 0; // disabled
end;
procedure TStompClient.DeInit;
@ -369,6 +413,7 @@ destructor TStompClient.Destroy;
begin
Disconnect;
DeInit;
FLock.Free;
inherited;
end;
@ -378,8 +423,16 @@ var
begin
if Connected then
begin
if ServerSupportsHeartBeat then
begin
Assert(Assigned(FHeartBeatThread), 'HeartBeat thread not created');
FHeartBeatThread.Terminate;
FHeartBeatThread.WaitFor;
FHeartBeatThread.Free;
end;
Frame := TStompFrame.Create;
Frame.SetCommand('DISCONNECT');
Frame.Command := 'DISCONNECT';
SendFrame(Frame);
{$IFDEF USESYNAPSE}
@ -396,10 +449,10 @@ end;
function TStompClient.FormatErrorFrame(const AErrorFrame: IStompFrame): string;
begin
if AErrorFrame.GetCommand <> 'ERROR' then
if AErrorFrame.Command <> 'ERROR' then
raise EStomp.Create('Not an ERROR frame');
Result := AErrorFrame.GetHeaders.Value('message') + ': ' +
AErrorFrame.GetBody;
Result := AErrorFrame.Headers.Value('message') + ': ' +
AErrorFrame.Body;
end;
function TStompClient.GetProtocolVersion: string;
@ -435,6 +488,7 @@ end;
{$IFDEF USESYNAPSE}
procedure TStompClient.SynapseSocketCallBack(Sender: TObject;
Reason: THookSocketReason; const Value: string);
begin
@ -448,6 +502,7 @@ end;
{$ENDIF}
procedure TStompClient.MergeHeaders(var AFrame: IStompFrame;
var AHeaders: IStompHeaders);
var
@ -459,12 +514,12 @@ begin
for i := 0 to AHeaders.Count - 1 do
begin
h := AHeaders.GetAt(i);
AFrame.GetHeaders.Add(h.Key, h.Value);
AFrame.Headers.Add(h.Key, h.Value);
end;
// If the frame has some content, then set the length of that content.
if (AFrame.ContentLength > 0) then
AFrame.GetHeaders.Add('content-length', intToStr(AFrame.ContentLength));
AFrame.Headers.Add('content-length', intToStr(AFrame.ContentLength));
end;
procedure TStompClient.Nack(const MessageID, TransactionIdentifier: string);
@ -472,22 +527,39 @@ var
Frame: IStompFrame;
begin
Frame := TStompFrame.Create;
Frame.SetCommand('NACK');
Frame.GetHeaders.Add('message-id', MessageID);
Frame.Command := 'NACK';
Frame.Headers.Add('message-id', MessageID);
if TransactionIdentifier <> '' then
Frame.GetHeaders.Add('transaction', TransactionIdentifier);
Frame.Headers.Add('transaction', TransactionIdentifier);
SendFrame(Frame);
end;
procedure TStompClient.ParseHeartBeat(Headers: IStompHeaders);
var
lValue: string;
lIntValue: string;
begin
FServerOutgoingHeartBeats := 0;
FServerIncomingHeartBeats := 0;
//WARNING!! server heart beat is reversed
lValue := Headers.Value('heart-beat');
if Trim(lValue) <> '' then
begin
lIntValue := Fetch(lValue, ',');
FServerIncomingHeartBeats := StrToInt(lIntValue);
FServerOutgoingHeartBeats := StrToInt(lValue);
end;
end;
procedure TStompClient.Receipt(const ReceiptID: string);
var
Frame: IStompFrame;
begin
if Receive(Frame, FReceiptTimeout) then
begin
if Frame.GetCommand <> 'RECEIPT' then
if Frame.Command <> 'RECEIPT' then
raise EStomp.Create('Receipt command error');
if Frame.GetHeaders.Value('receipt-id') <> ReceiptID then
if Frame.Headers.Value('receipt-id') <> ReceiptID then
raise EStomp.Create('Receipt receipt-id error');
end;
end;
@ -559,12 +631,13 @@ function TStompClient.Receive(ATimeout: Integer): IStompFrame;
{$ELSE}
function InternalReceiveINDY(ATimeout: Integer): IStompFrame;
var
s: string;
lLine: string;
lSBuilder: TStringBuilder;
Headers: TIdHeaderList;
ContentLength: Integer;
Charset: string;
lHeartBeat: boolean;
lTimestampFirstReadLn: TDateTime;
{$IF CompilerVersion < 24}
Encoding: TIdTextEncoding;
FreeEncoding: boolean;
@ -580,32 +653,54 @@ function TStompClient.Receive(ATimeout: Integer): IStompFrame;
{$IF CompilerVersion < 24}TIdTextEncoding.UTF8{$ELSE}IndyTextEncoding_UTF8{$ENDIF};
try
lTimestampFirstReadLn := Now;
// read command line
// repeat
s := FTCP.Socket.ReadLn(LF, ATimeout, -1,
FTCP.Socket.DefStringEncoding);
// until s <> '';
if s = '' then
while True do
begin
lLine := FTCP.Socket.ReadLn(LF, ATimeout, -1,
FTCP.Socket.DefStringEncoding);
if FTCP.Socket.ReadLnTimedout then
Break;
lHeartBeat := lLine = ''; // here is not timeout because of the previous line
if lHeartBeat then
WinApi.Windows.Beep(1500,200);
if FServerProtocolVersion = '1.1' then // 1.1 supports heart-beats
begin
if (not lHeartBeat) or (lLine <> '') then
Break;
if MilliSecondsBetween(lTimestampFirstReadLn, Now) >= ATimeout then
Break;
end
else
Break; // 1.0
end;
if lLine = '' then
Exit(nil);
lSBuilder.Append(s + LF);
lSBuilder.Append(lLine + LF);
// read headers
Headers := TIdHeaderList.Create(QuotePlain);
try
repeat
s := FTCP.Socket.ReadLn;
lSBuilder.Append(s + LF);
if s = '' then
lLine := FTCP.Socket.ReadLn;
lSBuilder.Append(lLine + LF);
if lLine = '' then
Break;
Headers.Add(s);
// in case of duplicated header, only the first is considered
// https://stomp.github.io/stomp-specification-1.1.html#Repeated_Header_Entries
if Headers.IndexOfName(Fetch(lLine, ':', False, False)) = -1 then
Headers.Add(lLine);
until False;
// read body
//
// NOTE: non-text data really should be read as a Stream instead of a String!!!
//
if IsHeaderMediaType(Headers.Values['content-type'], 'text') then
begin
Charset := Headers.Params['content-type', 'charset'];
@ -633,8 +728,8 @@ function TStompClient.Receive(ATimeout: Integer): IStompFrame;
ContentLength := IndyStrToInt(Headers.Values['content-length']);
if ContentLength > 0 then
begin
s := FTCP.Socket.ReadString(ContentLength, Encoding);
lSBuilder.Append(s);
lLine := FTCP.Socket.ReadString(ContentLength, Encoding);
lSBuilder.Append(lLine);
end;
// frame must still be terminated by a null
FTCP.Socket.ReadLn(#0 + LF);
@ -643,8 +738,8 @@ function TStompClient.Receive(ATimeout: Integer): IStompFrame;
begin
// no length specified, body terminated by frame terminating null
s := FTCP.Socket.ReadLn(#0 + LF, Encoding);
lSBuilder.Append(s);
lLine := FTCP.Socket.ReadLn(#0 + LF, Encoding);
lSBuilder.Append(lLine);
end;
lSBuilder.Append(#0);
@ -667,7 +762,7 @@ function TStompClient.Receive(ATimeout: Integer): IStompFrame;
end;
end;
Result := StompUtils.CreateFrame(lSBuilder.toString);
if Result.GetCommand = 'ERROR' then
if Result.Command = 'ERROR' then
raise EStomp.Create(FormatErrorFrame(Result));
finally
lSBuilder.Free;
@ -676,6 +771,7 @@ function TStompClient.Receive(ATimeout: Integer): IStompFrame;
{$ENDIF}
begin
{$IFDEF USESYNAPSE}
@ -698,9 +794,9 @@ var
Frame: IStompFrame;
begin
Frame := TStompFrame.Create;
Frame.SetCommand('SEND');
Frame.GetHeaders.Add('destination', QueueOrTopicName);
Frame.SetBody(TextMessage);
Frame.Command := 'SEND';
Frame.Headers.Add('destination', QueueOrTopicName);
Frame.Body := TextMessage;
MergeHeaders(Frame, Headers);
SendFrame(Frame);
end;
@ -711,39 +807,69 @@ var
Frame: IStompFrame;
begin
Frame := TStompFrame.Create;
Frame.SetCommand('SEND');
Frame.GetHeaders.Add('destination', QueueOrTopicName);
Frame.GetHeaders.Add('transaction', TransactionIdentifier);
Frame.SetBody(TextMessage);
Frame.Command := 'SEND';
Frame.Headers.Add('destination', QueueOrTopicName);
Frame.Headers.Add('transaction', TransactionIdentifier);
Frame.Body := TextMessage;
MergeHeaders(Frame, Headers);
SendFrame(Frame);
end;
procedure TStompClient.SendFrame(AFrame: IStompFrame);
begin
TMonitor.Enter(FLock);
try
{$IFDEF USESYNAPSE}
if Assigned(FOnBeforeSendFrame) then
FOnBeforeSendFrame(AFrame);
FSynapseTCP.SendString(AFrame.output);
if Assigned(FOnAfterSendFrame) then
FOnAfterSendFrame(AFrame);
if Assigned(FOnBeforeSendFrame) then
FOnBeforeSendFrame(AFrame);
FSynapseTCP.SendString(AFrame.output);
if Assigned(FOnAfterSendFrame) then
FOnAfterSendFrame(AFrame);
{$ELSE}
// FTCP.IOHandler.write(TEncoding.ASCII.GetBytes(AFrame.output));
if Assigned(FOnBeforeSendFrame) then
FOnBeforeSendFrame(AFrame);
// FTCP.IOHandler.write(TEncoding.ASCII.GetBytes(AFrame.output));
if Assigned(FOnBeforeSendFrame) then
FOnBeforeSendFrame(AFrame);
{$IF CompilerVersion < 25}
FTCP.IOHandler.write(TEncoding.UTF8.GetBytes(AFrame.output));
FTCP.IOHandler.write(TEncoding.UTF8.GetBytes(AFrame.output));
{$IFEND}
{$IF CompilerVersion >= 25}
FTCP.IOHandler.write(IndyTextEncoding_UTF8.GetBytes(AFrame.output));
FTCP.IOHandler.write(IndyTextEncoding_UTF8.GetBytes(AFrame.output));
{$IFEND}
if Assigned(FOnAfterSendFrame) then
FOnAfterSendFrame(AFrame);
if Assigned(FOnAfterSendFrame) then
FOnAfterSendFrame(AFrame);
{$ENDIF}
finally
TMonitor.Exit(FLock);
end;
end;
procedure TStompClient.SendHeartBeat;
begin
TMonitor.Enter(FLock);
try
Winapi.Windows.Beep(600, 200);
{$IFDEF USESYNAPSE}
FSynapseTCP.SendString(LF);
{$ELSE}
{$IF CompilerVersion < 25}
FTCP.IOHandler.write(TEncoding.UTF8.GetBytes(LF));
{$IFEND}
{$IF CompilerVersion >= 25}
FTCP.IOHandler.write(IndyTextEncoding_UTF8.GetBytes(LF));
{$IFEND}
{$ENDIF}
finally
TMonitor.Exit(FLock);
end;
end;
function TStompClient.ServerSupportsHeartBeat: boolean;
begin
Result := (FServerProtocolVersion = '1.1') and (FServerOutgoingHeartBeats > 0)
end;
procedure TStompClient.SetConnectionTimeout(const Value: UInt32);
@ -751,6 +877,13 @@ begin
FConnectionTimeout := Value;
end;
procedure TStompClient.SetHeartBeat(const OutgoingHeartBeats,
IncomingHeartBeats: Int64);
begin
FOutgoingHeartBeats := OutgoingHeartBeats;
FIncomingHeartBeats := IncomingHeartBeats;
end;
function TStompClient.SetPassword(const Value: string): IStompClient;
begin
FPassword := Value;
@ -781,8 +914,8 @@ var
Frame: IStompFrame;
begin
Frame := TStompFrame.Create;
Frame.SetCommand('SUBSCRIBE');
Frame.GetHeaders.Add('destination', QueueOrTopicName)
Frame.Command := 'SUBSCRIBE';
Frame.Headers.Add('destination', QueueOrTopicName)
.Add('ack', StompUtils.AckModeToStr(Ack));
if Headers <> nil then
MergeHeaders(Frame, Headers);
@ -794,9 +927,36 @@ var
Frame: IStompFrame;
begin
Frame := TStompFrame.Create;
Frame.SetCommand('UNSUBSCRIBE');
Frame.GetHeaders.Add('destination', Queue);
Frame.Command := 'UNSUBSCRIBE';
Frame.Headers.Add('destination', Queue);
SendFrame(Frame);
end;
{ THeartBeatThread }
constructor THeartBeatThread.Create(StompClient: TStompClient; Lock: TObject;
OutgoingHeatBeatTimeout: Int64);
begin
inherited Create(True);
FStompClient := StompClient;
FLock := Lock;
FOutgoingHeatBeatTimeout := OutgoingHeatBeatTimeout;
end;
procedure THeartBeatThread.Execute;
var
lStart: TDateTime;
begin
while not Terminated do
begin
lStart := Now;
while (not Terminated) and (MilliSecondsBetween(Now, lStart) < FOutgoingHeatBeatTimeout) do
begin
Sleep(100);
end;
if not Terminated then
FStompClient.SendHeartBeat;
end;
end;
end.

View File

@ -1,6 +1,6 @@
// Stomp Client for Embarcadero Delphi & FreePascal
// Tested With ApacheMQ 5.2/5.3, Apache Apollo 1.2, RabbitMQ
// Copyright (c) 2009-2015 Daniele Teti
// Copyright (c) 2009-2016 Daniele Teti
//
// Contributors:
// Daniel Gaspary: dgaspary@gmail.com
@ -29,7 +29,7 @@ const
type
TAckMode = (amAuto, amClient, amClientIndividual { STOMP 1.1 } );
TStompAcceptProtocol = (STOMP_Version_1_0, STOMP_Version_1_1);
TStompAcceptProtocol = (Ver_1_0, Ver_1_1);
EStomp = class(Exception)
end;
@ -66,6 +66,8 @@ type
function MessageID: string;
function ContentLength: Integer;
function ReplyTo: string;
property Headers: IStompHeaders read GetHeaders write SetHeaders;
property Command: string read GetCommand write SetCommand;
end;
IStompClient = interface
@ -77,7 +79,7 @@ type
procedure Receipt(const ReceiptID: string);
procedure Connect(Host: string = '127.0.0.1'; Port: Integer = 61613;
ClientID: string = '';
AcceptVersion: TStompAcceptProtocol = STOMP_Version_1_0);
AcceptVersion: TStompAcceptProtocol = Ver_1_0);
function Clone: IStompClient;
procedure Disconnect;
procedure Subscribe(QueueOrTopicName: string; Ack: TAckMode = amAuto;
@ -89,16 +91,17 @@ type
TransactionIdentifier: string; Headers: IStompHeaders = nil); overload;
procedure Ack(const MessageID: string;
const TransactionIdentifier: string = '');
{ STOMP 1.1 }
{ ** STOMP 1.1 ** }
procedure Nack(const MessageID: string;
const TransactionIdentifier: string = '');
procedure BeginTransaction(const TransactionIdentifier: string);
procedure CommitTransaction(const TransactionIdentifier: string);
procedure AbortTransaction(const TransactionIdentifier: string);
/// ////////////
{ ****************************************************************** }
function SetPassword(const Value: string): IStompClient;
function SetUserName(const Value: string): IStompClient;
function SetReceiveTimeout(const AMilliSeconds: Cardinal): IStompClient;
procedure SetHeartBeat(const OutgoingHeartBeats, IncomingHeartBeats: Int64);
function Connected: Boolean;
function GetProtocolVersion: string;
function GetServer: string;
@ -188,30 +191,29 @@ type
IStompListener = interface
['{CB3EB297-8616-408E-A0B2-7CCC11224DBC}']
procedure StopListening;
procedure StartListening;
end;
IStompClientListener = interface
['{C4C0D932-8994-43FB-9D32-A03FE86AEFE4}']
procedure OnMessage(StompClient: IStompClient; StompFrame: IStompFrame;
var StompListening: Boolean);
procedure OnStopListen(StompClient: IStompClient);
procedure OnMessage(MessageBody: string; var TerminateListener: Boolean);
procedure OnListenerStopped(StompClient: IStompClient);
end;
{ TODO -oDaniele -cGeneral : Use TThread by composition and not by inheritance }
TStompClientListener = class(TThread, IStompListener)
strict protected
TStompClientListener = class(TInterfacedObject, IStompListener)
strict private
FReceiverThread: TThread;
FTerminated: Boolean;
private
FStompClientListener: IStompClientListener;
strict protected
FStompClient: IStompClient;
procedure Execute; override;
public
constructor Create(StompClient: IStompClient;
StompClientListener: IStompClientListener);
constructor Create(const StompClient: IStompClient;
const StompClientListener: IStompClientListener); virtual;
destructor Destroy; override;
procedure StartListening;
procedure StopListening;
function QueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
end;
type
@ -225,6 +227,16 @@ type
class function TimestampAsDateTime(const HeaderValue: string): TDateTime;
end;
TReceiverThread = class(TThread)
private
FStompClient: IStompClient;
FStompClientListener: IStompClientListener;
protected
procedure Execute; override;
public
constructor Create(StompClient: IStompClient; StompClientListener: IStompClientListener);
end;
implementation
uses
@ -431,7 +443,7 @@ begin
on e: Exception do
begin
Result.Free;
raise EStomp.Create(e.message);
raise EStomp.Create(e.Message);
end;
end;
end;
@ -588,56 +600,72 @@ end;
{ TStompListener }
constructor TStompClientListener.Create(StompClient: IStompClient;
StompClientListener: IStompClientListener);
constructor TStompClientListener.Create(const StompClient: IStompClient;
const StompClientListener: IStompClientListener);
begin
FStompClientListener := StompClientListener;
FStompClient := StompClient;
inherited Create(false);
FTerminated := False;
FReceiverThread := nil;
inherited Create;
end;
procedure TStompClientListener.Execute;
var
frame: IStompFrame;
StopListen: Boolean;
destructor TStompClientListener.Destroy;
begin
StopListen := false;
while not terminated do
begin
if FStompClient.Receive(frame, 1000) then
begin
FStompClientListener.OnMessage(FStompClient, frame, StopListen);
if StopListen then
begin
FStompClientListener.OnStopListen(FStompClient);
if not terminated then
StopListening;
end;
end;
end;
FTerminated := true;
FReceiverThread.Free;
inherited;
end;
function TStompClientListener.QueryInterface(const IID: TGUID; out Obj)
: HRESULT;
procedure TStompClientListener.StartListening;
begin
Result := E_NOINTERFACE;
if Assigned(FReceiverThread) then
raise EStomp.Create('Already listening');
FReceiverThread := TReceiverThread.Create(FStompClient, FStompClientListener);
FReceiverThread.Start;
end;
procedure TStompClientListener.StopListening;
begin
Terminate;
// Free;
// WaitFor;
if not Assigned(FReceiverThread) then
exit;
FReceiverThread.Terminate;
FReceiverThread.Free;
FReceiverThread := nil;
end;
function TStompClientListener._AddRef: Integer;
{ TReceiverThread }
constructor TReceiverThread.Create(StompClient: IStompClient;
StompClientListener: IStompClientListener);
begin
Result := -1;
inherited Create(true);
FStompClient := StompClient;
FStompClientListener := StompClientListener;
end;
function TStompClientListener._Release: Integer;
procedure TReceiverThread.Execute;
var
LFrame: IStompFrame;
LTerminateListener: Boolean;
begin
Result := -1;
LTerminateListener := False;
while (not Terminated) and (not LTerminateListener) do
begin
if FStompClient.Receive(LFrame, 1000) then
begin
TThread.Synchronize(nil,
procedure
begin
FStompClientListener.OnMessage(LFrame.Body, LTerminateListener);
end);
end;
end;
TThread.Synchronize(nil,
procedure
begin
FStompClientListener.OnListenerStopped(FStompClient);
end);
end;
end.

View File

@ -1,7 +1,7 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{725AE3B6-F1CE-42B3-BA06-F919DCE3AB46}</ProjectGuid>
<ProjectVersion>16.1</ProjectVersion>
<ProjectVersion>18.1</ProjectVersion>
<MainSource>ChatClient.dpr</MainSource>
<Config Condition="'$(Config)'==''">Debug</Config>
<DCC_DCCCompiler>DCC32</DCC_DCCCompiler>
@ -52,6 +52,7 @@
<DCC_Platform>x86</DCC_Platform>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win32)'!=''">
<AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<Icon_MainIcon>ChatClient_Icon.ico</Icon_MainIcon>
<DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
@ -59,6 +60,7 @@
<Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win64)'!=''">
<AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
<Icon_MainIcon>ChatClient_Icon.ico</Icon_MainIcon>
<Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
</PropertyGroup>

View File

@ -39,8 +39,8 @@ procedure TForm5.Button1Click(Sender: TObject);
begin
roomname := '/topic/' + Edit2.Text;
stomp := TStompClient.Create;
stomp.SetUserName('admin');
stomp.SetPassword('password');
// stomp.SetUserName('admin');
// stomp.SetPassword('password');
stomp.Connect(Edit1.Text);
//Setup for reading messages

View File

@ -63,6 +63,7 @@ uses
{$R *.dfm}
procedure TForm1.ApplicationEvents1Idle(Sender: TObject; var Done: Boolean);
begin
ListBox1.Items.BeginUpdate;
@ -117,7 +118,10 @@ end;
procedure TForm1.Button5Click(Sender: TObject);
begin
LSTOMP.Subscribe(Edit1.Text, amAuto,
StompUtils.NewHeaders.Add(TStompHeaders.NewDurableSubscriptionHeader('pippo')));
StompUtils.Headers
.Add(TStompHeaders.Persistent(true))
.Add(TStompHeaders.Durable(true))
);
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);

View File

@ -11,6 +11,8 @@ object Form4: TForm4
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
OnDestroy = FormDestroy
DesignSize = (
527
506)
@ -19,17 +21,17 @@ object Form4: TForm4
object Button1: TButton
Left = 8
Top = 8
Width = 113
Height = 25
Width = 137
Height = 42
Caption = 'Start'
TabOrder = 0
OnClick = Button1Click
end
object Memo1: TMemo
Left = 8
Top = 39
Top = 56
Width = 511
Height = 459
Height = 442
Anchors = [akLeft, akTop, akRight, akBottom]
Font.Charset = ANSI_CHARSET
Font.Color = clWindowText
@ -39,4 +41,24 @@ object Form4: TForm4
ParentFont = False
TabOrder = 1
end
object Button2: TButton
Left = 151
Top = 8
Width = 137
Height = 42
Caption = 'Stop'
TabOrder = 2
OnClick = Button2Click
end
object Button3: TButton
Left = 392
Top = 8
Width = 127
Height = 42
Anchors = [akTop, akRight]
Caption = 'Produce messages continuosly'
TabOrder = 3
WordWrap = True
OnClick = Button3Click
end
end

View File

@ -19,16 +19,21 @@ type
TForm4 = class(TForm, IStompClientListener)
Button1: TButton;
Memo1: TMemo;
Button2: TButton;
Button3: TButton;
procedure Button1Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
th0: IStompListener;
th1: IStompListener;
th2: IStompListener;
{ Private declarations }
FSTOMPListener: IStompListener;
FSTOMPClient: IStompClient;
FFormClosing: Boolean;
FProducerThread: TThread;
public
procedure OnMessage(StompClient: IStompClient; StompFrame: IStompFrame;
var StopListening: boolean);
procedure OnStopListen(StompClient: IStompClient);
procedure OnMessage(MessageBody: string; var TerminateListener: Boolean);
procedure OnListenerStopped(StompClient: IStompClient);
end;
var
@ -38,92 +43,71 @@ implementation
uses StompClient;
type
TMyStompListener = class(TInterfacedObject, IStompClientListener)
public
procedure OnMessage(StompClient: IStompClient; StompFrame: IStompFrame;
var StopListening: boolean);
procedure OnStopListen(StompClient: IStompClient);
end;
{$R *.dfm}
procedure TForm4.Button1Click(Sender: TObject);
var
stomp0: IStompClient;
stomp1: IStompClient;
stomp2: IStompClient;
begin
stomp0 := TStompClient.CreateAndConnect;
stomp0.Subscribe('/topic/danieleteti', amAuto, StompUtils.NewHeaders.Add('include-seq', 'seq'));
th0 := TStompClientListener.Create(stomp0, TMyStompListener.Create);
FSTOMPListener.StopListening;
FSTOMPListener.StartListening;
end;
stomp1 := TStompClient.CreateAndConnect;
stomp1.Subscribe('/topic/danieleteti');
th1 := TStompClientListener.Create(stomp1, self);
procedure TForm4.Button2Click(Sender: TObject);
begin
FSTOMPListener.StopListening;
end;
stomp2 := TStompClient.CreateAndConnect;
stomp2.Subscribe('/topic/salvatore');
th2 := TStompClientListener.Create(stomp2, self);
TThread.CreateAnonymousThread(
procedure TForm4.Button3Click(Sender: TObject);
begin
FProducerThread := TThread.CreateAnonymousThread(
procedure
var
i: Integer;
stomp: IStompClient;
begin
stomp := TStompClient.CreateAndConnect;
for i := 1 to 10 do
i := 1;
while True do
begin
sleep(100);
sleep(300);
if FFormClosing then
Exit;
stomp.Send('/topic/danieleteti', 'Hello World ' + IntToStr(i));
stomp.Send('/topic/salvatore', 'Hello World ' + IntToStr(i));
inc(i);
end;
stomp.Send('/topic/danieleteti', 'SHUTDOWN');
stomp.Send('/topic/johndoe', 'SHUTDOWN');
stomp.Disconnect;
end).Start;
end;
procedure TForm4.OnMessage(StompClient: IStompClient; StompFrame: IStompFrame;
var StopListening: boolean);
begin
if StompFrame.GetBody = 'SHUTDOWN' then
StopListening := true;
TThread.Synchronize(nil,
procedure
begin
Memo1.Lines.Add(StompFrame.GetBody);
end);
FProducerThread.FreeOnTerminate := False;
FProducerThread.Start;
end;
procedure TForm4.OnStopListen(StompClient: IStompClient);
procedure TForm4.FormCreate(Sender: TObject);
begin
TThread.Synchronize(nil,
procedure
begin
Memo1.Lines.Add(StompClient.GetSession + ' has been stopped');
end);
FFormClosing := False;
FSTOMPClient := TStompClient.CreateAndConnect;
FSTOMPClient.Subscribe('/topic/danieleteti',
amAuto,
StompUtils.Headers.Add('include-seq', 'seq'));
FSTOMPListener := TStompClientListener.Create(FSTOMPClient, Self);
end;
{ TMyStompListener }
procedure TMyStompListener.OnMessage(StompClient: IStompClient; StompFrame: IStompFrame;
var StopListening: boolean);
procedure TForm4.FormDestroy(Sender: TObject);
begin
if StompFrame.GetBody = 'SHUTDOWN' then
StopListening := true;
Writeln('------');
Writeln(StompFrame.Output);
Writeln('------');
FFormClosing := True;
FProducerThread.WaitFor;
FProducerThread.Free;
FSTOMPListener := nil;
end;
procedure TMyStompListener.OnStopListen(StompClient: IStompClient);
procedure TForm4.OnMessage(MessageBody: string; var TerminateListener: Boolean);
begin
Writeln('Listener has been stopped');
Memo1.Lines.Add(MessageBody);
TerminateListener := FFormClosing;
end;
procedure TForm4.OnListenerStopped(StompClient: IStompClient);
begin
Memo1.Lines.Add('Listener Stopped');
end;
initialization

View File

@ -19,7 +19,7 @@ begin
lClient := TStompClient.Create;
lClient.Connect();
WriteLn('Subscribing to queue "myqueue"');
lClient.Subscribe('myqueue');
lClient.Subscribe('/queue/myqueue');
WriteLn('Reading just the following 2 messages...');
WriteLn(sLineBreak + sLineBreak + 'Waiting for the 1st message...' + sLineBreak +

View File

@ -172,12 +172,27 @@
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployClass Name="ProjectiOSDeviceResourceRules">
<DeployClass Name="DependencyModule">
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.dll;.bpl</Extensions>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXResource">
@ -528,27 +543,12 @@
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DependencyModule">
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.dll;.bpl</Extensions>
</Platform>
<DeployClass Name="ProjectiOSDeviceResourceRules">
<Platform Name="iOSDevice64">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
</DeployClass>
<ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>

View File

@ -10,17 +10,21 @@ program producer;
uses
System.SysUtils,
StompClient;
StompClient, StompTypes;
procedure Main;
var
lClient: TStompClient;
lFrame: IStompFrame;
begin
lClient := TStompClient.Create;
lClient.Connect();
WriteLn('Sending messages to queue "myqueue"');
lClient.Send('myqueue', 'Message 1');
lClient.Send('myqueue', 'Message 2');
lClient.Send('/queue/myqueue', 'Message 1');
// lFrame := lClient.Receive(100);
// if Assigned(lFrame) then
// WriteLn(lFrame.Output);
lClient.Send('/queue/myqueue', 'Message 2');
WriteLn('Messages sent');
lClient.Disconnect;
end;
@ -28,7 +32,7 @@ end;
begin
try
Main;
Write('Press return to quit');
write('Press return to quit');
ReadLn;
except
on E: Exception do

View File

@ -172,27 +172,12 @@
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployClass Name="DependencyModule">
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.dll;.bpl</Extensions>
</Platform>
<DeployClass Name="ProjectiOSDeviceResourceRules">
<Platform Name="iOSDevice64">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXResource">
@ -543,12 +528,27 @@
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceResourceRules">
<DeployClass Name="DependencyModule">
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.dll;.bpl</Extensions>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
</DeployClass>
<ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>

View File

@ -9,7 +9,9 @@ program consumer;
}
uses
System.SysUtils, StompClient, StompTypes;
System.SysUtils,
StompClient in '..\..\StompClient.pas',
StompTypes in '..\..\StompTypes.pas';
procedure Main;
var
@ -18,7 +20,8 @@ var
lMessage: string;
begin
lClient := TStompClient.Create;
lClient.Connect();
lClient.SetHeartBeat(0, 0);
lClient.Connect('127.0.0.1', 61613, '', TStompAcceptProtocol.Ver_1_1);
WriteLn('Subscribing to queue "myjobqueue"');
lClient.Subscribe('/topic/mytopic',
TAckMode.amClient

View File

@ -124,6 +124,8 @@
<DelphiCompile Include="$(MainSource)">
<MainSource>MainSource</MainSource>
</DelphiCompile>
<DCCReference Include="..\..\StompClient.pas"/>
<DCCReference Include="..\..\StompTypes.pas"/>
<BuildConfiguration Include="Release">
<Key>Cfg_2</Key>
<CfgParent>Base</CfgParent>
@ -172,12 +174,27 @@
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployClass Name="ProjectiOSDeviceResourceRules">
<DeployClass Name="DependencyModule">
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.dll;.bpl</Extensions>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXResource">
@ -528,27 +545,12 @@
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DependencyModule">
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.dll;.bpl</Extensions>
</Platform>
<DeployClass Name="ProjectiOSDeviceResourceRules">
<Platform Name="iOSDevice64">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
</DeployClass>
<ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>

View File

@ -10,7 +10,8 @@ program producer;
uses
System.SysUtils,
StompClient, StompTypes;
StompTypes in '..\..\StompTypes.pas',
StompClient in '..\..\StompClient.pas';
procedure Main;
var
@ -18,7 +19,8 @@ var
lMessage: string;
begin
lClient := TStompClient.Create;
lClient.Connect;
lClient.SetHeartBeat(0, 2000);
lClient.Connect('127.0.0.1', 61613, '', TStompAcceptProtocol.Ver_1_1);
WriteLn('Sending messages to topic "mytopic"');
WriteLn('NOTE: Consumers will wait a second for each "." present in the message.');
WriteLn(' empty message will terminate the program.');

View File

@ -124,6 +124,8 @@
<DelphiCompile Include="$(MainSource)">
<MainSource>MainSource</MainSource>
</DelphiCompile>
<DCCReference Include="..\..\StompTypes.pas"/>
<DCCReference Include="..\..\StompClient.pas"/>
<BuildConfiguration Include="Release">
<Key>Cfg_2</Key>
<CfgParent>Base</CfgParent>
@ -172,27 +174,12 @@
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployClass Name="DependencyModule">
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.dll;.bpl</Extensions>
</Platform>
<DeployClass Name="ProjectiOSDeviceResourceRules">
<Platform Name="iOSDevice64">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXResource">
@ -543,12 +530,27 @@
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceResourceRules">
<DeployClass Name="DependencyModule">
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.dll;.bpl</Extensions>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
</DeployClass>
<ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>

View File

@ -1,34 +1,61 @@
program TestStompClient;
{$IFDEF CONSOLE_TESTRUNNER}
{$IFNDEF TESTINSIGHT}
{$APPTYPE CONSOLE}
{$ENDIF}
{$ENDIF}{$STRONGLINKTYPES ON}
uses
Forms,
TestFramework,
GUITestRunner,
TextTestRunner,
TestStompClientU in 'TestStompClientU.pas';
{$R *.RES}
System.SysUtils,
{$IFDEF TESTINSIGHT}
TestInsight.DUnitX,
{$ENDIF }
DUnitX.Loggers.Console,
DUnitX.Loggers.Xml.NUnit,
DUnitX.TestFramework,
TestStompClientU in 'TestStompClientU.pas',
StompClient in '..\StompClient.pas',
StompTypes in '..\StompTypes.pas';
var
ExCode: Integer;
TestResult: TTestResult;
runner : ITestRunner;
results : IRunResults;
logger : ITestLogger;
nunitLogger : ITestLogger;
begin
ExCode := 0;
Application.Initialize;
if IsConsole then
begin
TestResult := TextTestRunner.RunRegisteredTests;
try
ExCode := TestResult.ErrorCount + TestResult.FailureCount;
finally
TestResult.Free;
{$IFDEF TESTINSIGHT}
TestInsight.DUnitX.RunRegisteredTests;
exit;
{$ENDIF}
try
//Check command line options, will exit if invalid
TDUnitX.CheckCommandLine;
//Create the test runner
runner := TDUnitX.CreateRunner;
//Tell the runner to use RTTI to find Fixtures
runner.UseRTTI := True;
//tell the runner how we will log things
//Log to the console window
logger := TDUnitXConsoleLogger.Create(true);
runner.AddLogger(logger);
//Generate an NUnit compatible XML File
nunitLogger := TDUnitXXMLNUnitFileLogger.Create(TDUnitX.Options.XMLOutputFile);
runner.AddLogger(nunitLogger);
runner.FailsOnNoAsserts := False; //When true, Assertions must be made during tests;
//Run tests
results := runner.Execute;
if not results.AllPassed then
System.ExitCode := EXIT_ERRORS;
{$IFNDEF CI}
//We don't want this happening when running under CI.
if TDUnitX.Options.ExitBehavior = TDUnitXExitBehavior.Pause then
begin
System.Write('Done.. press <Enter> key to quit.');
System.Readln;
end;
end
else
GUITestRunner.RunRegisteredTests;
Halt(ExCode);
{$ENDIF}
except
on E: Exception do
System.Writeln(E.ClassName, ': ', E.Message);
end;
end.

View File

@ -1,19 +1,43 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{8E4B2D47-EFD1-4ACD-9821-EF2EE2839C83}</ProjectGuid>
<ProjectGuid>{4255F8BF-BB1B-415B-88DE-DA55867C0D40}</ProjectGuid>
<ProjectVersion>18.1</ProjectVersion>
<MainSource>TestStompClient.dpr</MainSource>
<Config Condition="'$(Config)'==''">Debug</Config>
<DCC_DCCCompiler>DCC32</DCC_DCCCompiler>
<FrameworkType>VCL</FrameworkType>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Debug</Config>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<TargetedPlatforms>1025</TargetedPlatforms>
<AppType>Application</AppType>
<TargetedPlatforms>1</TargetedPlatforms>
<AppType>Console</AppType>
<FrameworkType>None</FrameworkType>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Android' and '$(Base)'=='true') or '$(Base_Android)'!=''">
<Base_Android>true</Base_Android>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='iOSDevice32' and '$(Base)'=='true') or '$(Base_iOSDevice32)'!=''">
<Base_iOSDevice32>true</Base_iOSDevice32>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='iOSDevice64' and '$(Base)'=='true') or '$(Base_iOSDevice64)'!=''">
<Base_iOSDevice64>true</Base_iOSDevice64>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='iOSSimulator' and '$(Base)'=='true') or '$(Base_iOSSimulator)'!=''">
<Base_iOSSimulator>true</Base_iOSSimulator>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='OSX32' and '$(Base)'=='true') or '$(Base_OSX32)'!=''">
<Base_OSX32>true</Base_OSX32>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
<Base_Win32>true</Base_Win32>
<CfgParent>Base</CfgParent>
@ -24,7 +48,7 @@
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''">
<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
<Cfg_1>true</Cfg_1>
<CfgParent>Base</CfgParent>
<Base>true</Base>
@ -35,162 +59,467 @@
<Cfg_1>true</Cfg_1>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''">
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
<Cfg_2>true</Cfg_2>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='iOSDevice64' and '$(Cfg_2)'=='true') or '$(Cfg_2_iOSDevice64)'!=''">
<Cfg_2_iOSDevice64>true</Cfg_2_iOSDevice64>
<CfgParent>Cfg_2</CfgParent>
<Cfg_2>true</Cfg_2>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
<Cfg_2_Win32>true</Cfg_2_Win32>
<CfgParent>Cfg_2</CfgParent>
<Cfg_2>true</Cfg_2>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Base)'!=''">
<VerInfo_Keys>CompanyName=www.instantobjects.org;FileDescription=InstantObjects;FileVersion=2.1.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=InstantObjects;ProductVersion=2.1.0.0;Comments=</VerInfo_Keys>
<VerInfo_MajorVer>2</VerInfo_MajorVer>
<SanitizedProjectName>TestStompClient</SanitizedProjectName>
<DCC_Namespace>Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;DUnitX;$(DCC_Namespace)</DCC_Namespace>
<VerInfo_MinorVer>1</VerInfo_MinorVer>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Locale>1040</VerInfo_Locale>
<DCC_TypedAtParameter>true</DCC_TypedAtParameter>
<DCC_DependencyCheckOutputName>TestStompClient.exe</DCC_DependencyCheckOutputName>
<DCC_UnitSearchPath>$(BDS)\Source\DUnit\src;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
<DCC_Define>CONSOLE_TESTRUNNER;$(DCC_Define)</DCC_Define>
<DCC_DcuOutput>.</DCC_DcuOutput>
<DCC_Description>InstantObjects BDE Design-Time Support (Delphi 2010)</DCC_Description>
<DCC_OutputNeverBuildDcps>true</DCC_OutputNeverBuildDcps>
<DllSuffix>_D14</DllSuffix>
<DCC_ImageBase>00400000</DCC_ImageBase>
<DCC_Platform>x86</DCC_Platform>
<DCC_Define>TESTINSIGHT;$(DCC_Define)</DCC_Define>
<UsingDelphiRTL>true</UsingDelphiRTL>
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)</DCC_Namespace>
<Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon>
<DCC_UnitSearchPath>$(DUnitX);$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
<Icns_MainIcns>$(BDS)\bin\delphi_PROJECTICNS.icns</Icns_MainIcns>
<DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput>
<DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput>
<DCC_E>false</DCC_E>
<DCC_N>false</DCC_N>
<DCC_S>false</DCC_S>
<DCC_F>false</DCC_F>
<DCC_K>false</DCC_K>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Android)'!=''">
<DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;emsclientfiredac;DataSnapFireDAC;tethering;bindcompfmx;FmxTeeUI;FireDACIBDriver;fmx;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;ibmonitor;FMXTee;soaprtl;DbxCommonDriver;ibxpress;xmlrtl;soapmidas;DataSnapNativeClient;ibxbindings;rtl;FireDACDSDriver;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)</DCC_UsePackage>
<EnabledSysJars>android-support-v4.dex.jar;cloud-messaging.dex.jar;fmx.dex.jar;google-analytics-v2.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar;google-play-services.dex.jar</EnabledSysJars>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_iOSDevice32)'!=''">
<DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;emsclientfiredac;DataSnapFireDAC;tethering;bindcompfmx;FmxTeeUI;FireDACIBDriver;fmx;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;ibmonitor;FMXTee;soaprtl;DbxCommonDriver;ibxpress;xmlrtl;soapmidas;DataSnapNativeClient;ibxbindings;rtl;FireDACDSDriver;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_iOSDevice64)'!=''">
<DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;emsclientfiredac;DataSnapFireDAC;tethering;rtcSDK;bindcompfmx;FmxTeeUI;FireDACIBDriver;fmx;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;rtcSDK_DBA;inet;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;ibmonitor;FMXTee;soaprtl;DbxCommonDriver;ibxpress;xmlrtl;soapmidas;DataSnapNativeClient;ibxbindings;rtl;FireDACDSDriver;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_iOSSimulator)'!=''">
<DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;emsclientfiredac;DataSnapFireDAC;tethering;bindcompfmx;FmxTeeUI;FireDACIBDriver;fmx;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;ibmonitor;FMXTee;soaprtl;DbxCommonDriver;ibxpress;xmlrtl;soapmidas;DataSnapNativeClient;ibxbindings;rtl;FireDACDSDriver;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_OSX32)'!=''">
<DCC_UsePackage>DBXSqliteDriver;RESTComponents;DataSnapServerMidas;DBXInterBaseDriver;emsclientfiredac;DataSnapFireDAC;tethering;FireDACMSSQLDriver;bindcompfmx;DBXOracleDriver;inetdb;FmxTeeUI;emsedge;FireDACIBDriver;fmx;fmxdae;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;soapserver;bindengine;DBXMySQLDriver;FireDACOracleDriver;CloudService;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;FireDACTDataDriver;FMXTee;soaprtl;DbxCommonDriver;ibxpress;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;ibxbindings;rtl;FireDACDSDriver;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;bindcomp;DBXInformixDriver;IndyIPClient;dbxcds;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;inetdbxpress;FireDACMongoDBDriver;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win32)'!=''">
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
<Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
<Icon_MainIcon>TestStompClient_Icon.ico</Icon_MainIcon>
<VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
<DCC_UsePackage>DBXSqliteDriver;RESTComponents;DataSnapServerMidas;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;emsclientfiredac;DataSnapFireDAC;svnui;tethering;FireDACADSDriver;rtcSDK;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;svn;Intraweb;DBXOracleDriver;inetdb;FmxTeeUI;emsedge;FireDACIBDriver;fmx;fmxdae;frx24;vclib;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;CloudService;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;rtcSDK_DBA;inet;bindcompdbx;IndyIPCommon;vcl;DBXSybaseASEDriver;IndyIPServer;IndySystem;FireDACDb2Driver;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;TeeDB;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;FMXTee;soaprtl;DbxCommonDriver;ibxpress;Tee;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;ibxbindings;rtl;FireDACDSDriver;DbxClientDriver;DBXSybaseASADriver;frxTee24;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;TeeUI;frxe24;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;frxDB24;dsnapxml;DataSnapProviderClient;dbrtl;inetdbxpress;FireDACMongoDBDriver;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
<VerInfo_Locale>1033</VerInfo_Locale>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win64)'!=''">
<Icon_MainIcon>TestStompClient_Icon.ico</Icon_MainIcon>
<Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
<AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
<DCC_UsePackage>DBXSqliteDriver;RESTComponents;DataSnapServerMidas;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;emsclientfiredac;DataSnapFireDAC;tethering;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;Intraweb;DBXOracleDriver;inetdb;FmxTeeUI;emsedge;FireDACIBDriver;fmx;fmxdae;vclib;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;CloudService;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;vcl;DBXSybaseASEDriver;IndyIPServer;IndySystem;FireDACDb2Driver;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;TeeDB;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;FMXTee;soaprtl;DbxCommonDriver;ibxpress;Tee;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;ibxbindings;rtl;FireDACDSDriver;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;TeeUI;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;inetdbxpress;FireDACMongoDBDriver;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1)'!=''">
<DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
<DCC_DebugDCUs>true</DCC_DebugDCUs>
<DCC_Optimize>false</DCC_Optimize>
<DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
<DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
<DCC_RemoteDebug>true</DCC_RemoteDebug>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
<DCC_RemoteDebug>false</DCC_RemoteDebug>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
<DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
<DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
<DCC_DebugInformation>0</DCC_DebugInformation>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
<AppEnableHighDPI>true</AppEnableHighDPI>
<AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2_iOSDevice64)'!=''">
<BT_BuildType>Debug</BT_BuildType>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
<AppEnableHighDPI>true</AppEnableHighDPI>
<AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
</PropertyGroup>
<ItemGroup>
<DelphiCompile Include="$(MainSource)">
<MainSource>MainSource</MainSource>
</DelphiCompile>
<DCCReference Include="TestStompClientU.pas"/>
<BuildConfiguration Include="Debug">
<DCCReference Include="..\StompClient.pas"/>
<DCCReference Include="..\StompTypes.pas"/>
<BuildConfiguration Include="Release">
<Key>Cfg_2</Key>
<CfgParent>Base</CfgParent>
</BuildConfiguration>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>
<BuildConfiguration Include="Release">
<BuildConfiguration Include="Debug">
<Key>Cfg_1</Key>
<CfgParent>Base</CfgParent>
</BuildConfiguration>
</ItemGroup>
<Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
<ProjectExtensions>
<Borland.Personality>Delphi.Personality.12</Borland.Personality>
<Borland.ProjectType/>
<Borland.ProjectType>Console</Borland.ProjectType>
<BorlandProject>
<Delphi.Personality>
<Parameters>
<Parameters Name="UseLauncher">False</Parameters>
<Parameters Name="LoadAllSymbols">True</Parameters>
<Parameters Name="LoadUnspecifiedSymbols">False</Parameters>
</Parameters>
<VersionInfo>
<VersionInfo Name="IncludeVerInfo">True</VersionInfo>
<VersionInfo Name="AutoIncBuild">False</VersionInfo>
<VersionInfo Name="MajorVer">2</VersionInfo>
<VersionInfo Name="MinorVer">1</VersionInfo>
<VersionInfo Name="Release">0</VersionInfo>
<VersionInfo Name="Build">0</VersionInfo>
<VersionInfo Name="Debug">False</VersionInfo>
<VersionInfo Name="PreRelease">False</VersionInfo>
<VersionInfo Name="Special">False</VersionInfo>
<VersionInfo Name="Private">False</VersionInfo>
<VersionInfo Name="DLL">False</VersionInfo>
<VersionInfo Name="Locale">1040</VersionInfo>
<VersionInfo Name="CodePage">1252</VersionInfo>
</VersionInfo>
<VersionInfoKeys>
<VersionInfoKeys Name="CompanyName">www.instantobjects.org</VersionInfoKeys>
<VersionInfoKeys Name="FileDescription">InstantObjects</VersionInfoKeys>
<VersionInfoKeys Name="FileVersion">2.1.0.0</VersionInfoKeys>
<VersionInfoKeys Name="InternalName"/>
<VersionInfoKeys Name="LegalCopyright"/>
<VersionInfoKeys Name="LegalTrademarks"/>
<VersionInfoKeys Name="OriginalFilename"/>
<VersionInfoKeys Name="ProductName">InstantObjects</VersionInfoKeys>
<VersionInfoKeys Name="ProductVersion">2.1.0.0</VersionInfoKeys>
<VersionInfoKeys Name="Comments"/>
</VersionInfoKeys>
<Excluded_Packages>
<Excluded_Packages Name="C:\Users\Public\Documents\RAD Studio\7.0\Bpl\dclHengenOPFCore.bpl">Hengen OPF Core</Excluded_Packages>
<Excluded_Packages Name="C:\Users\Public\Documents\RAD Studio\7.0\Bpl\HengenOPFCore.bpl">Hengen Computing OPF</Excluded_Packages>
<Excluded_Packages Name="C:\Users\Public\Documents\RAD Studio\7.0\Bpl\dclHengenADOLayer.bpl">Hengen ADO Persistence Layer</Excluded_Packages>
<Excluded_Packages Name="C:\Users\Public\Documents\RAD Studio\7.0\Bpl\dclHengenIBXLayer.bpl">Hengen IBX Persistence Layer</Excluded_Packages>
<Excluded_Packages Name="C:\Users\Public\Documents\RAD Studio\7.0\Bpl\dclHengenOPFGUI.bpl">Hengen OPF GUI Controls</Excluded_Packages>
<Excluded_Packages Name="C:\Users\Public\Documents\RAD Studio\7.0\Bpl\dclObjectListMgrMediators.bpl">Hengen OPF ObjectListMgr Demo Mediators</Excluded_Packages>
<Excluded_Packages Name="C:\Users\Public\Documents\RAD Studio\7.0\Bpl\Spring.Core.bpl">Delphi Spring Framework Core Library</Excluded_Packages>
<Excluded_Packages Name="C:\Users\Public\Documents\RAD Studio\7.0\Bpl\Spring.Base.bpl">Delphi Spring Framework Base Class Library</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\bcboffice2k140.bpl">Embarcadero C++Builder Office 2000 Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\bcbofficexp140.bpl">Embarcadero C++Builder Office XP Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k140.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dclofficexp140.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
</Excluded_Packages>
<Source>
<Source Name="MainSource">TestStompClient.dpr</Source>
</Source>
</Delphi.Personality>
<UnitTesting>
<TestFramework>DUnit / Delphi Win32</TestFramework>
<TestRunner>Console</TestRunner>
<TestProjectName/>
<SourceProjectName/>
</UnitTesting>
<Deployment Version="3">
<DeployFile LocalName="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib" Class="DependencyModule">
<Platform Name="OSX32">
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libcgunwind.1.0.dylib" Class="DependencyModule">
<Platform Name="iOSSimulator">
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libPCRE.dylib" Class="DependencyModule">
<Platform Name="iOSSimulator">
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="$(BDS)\Redist\osx32\libcgsqlite3.dylib" Class="DependencyModule">
<Platform Name="OSX32">
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="Win32\Debug\TestStompClient.exe" Configuration="Debug" Class="ProjectOutput">
<Platform Name="Win32">
<RemoteName>TestStompClient.exe</RemoteName>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployClass Name="ProjectiOSDeviceResourceRules"/>
<DeployClass Name="ProjectOSXResource">
<Platform Name="OSX32">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidClassesDexFile">
<Platform Name="Android">
<RemoteDir>classes</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AdditionalDebugSymbols">
<Platform Name="Win32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>0</Operation>
</Platform>
<Platform Name="OSX32">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch768">
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon144">
<Platform Name="Android">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidLibnativeMipsFile">
<Platform Name="Android">
<RemoteDir>library\lib\mips</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="ProjectOutput">
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
<Platform Name="Linux64">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<Operation>1</Operation>
</Platform>
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DependencyFramework">
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
<Platform Name="OSX32">
<Operation>1</Operation>
<Extensions>.framework</Extensions>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch640">
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1024">
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceDebug">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice32">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch320">
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSInfoPList"/>
<DeployClass Name="AndroidLibnativeArmeabiFile">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DebugSymbols">
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1536">
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage470">
<Platform Name="Android">
<RemoteDir>res\drawable-normal</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon96">
<Platform Name="Android">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage640">
<Platform Name="Android">
<RemoteDir>res\drawable-large</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch640x1136">
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSEntitlements"/>
<DeployClass Name="Android_LauncherIcon72">
<Platform Name="Android">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidGDBServer">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXInfoPList"/>
<DeployClass Name="ProjectOSXEntitlements"/>
<DeployClass Name="iPad_Launch2048">
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidSplashStyles">
<Platform Name="Android">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage426">
<Platform Name="Android">
<RemoteDir>res\drawable-small</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidSplashImageDef">
<Platform Name="Android">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSResource">
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectAndroidManifest">
<Platform Name="Android">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_DefaultAppIcon">
<Platform Name="Android">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="File">
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>0</Operation>
</Platform>
<Platform Name="OSX32">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>0</Operation>
</Platform>
<Platform Name="Android">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidServiceOutput">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="DependencyPackage">
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.bpl</Extensions>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon48">
<Platform Name="Android">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage960">
<Platform Name="Android">
<RemoteDir>res\drawable-xlarge</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon36">
<Platform Name="Android">
<RemoteDir>res\drawable-ldpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DependencyModule">
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.dll;.bpl</Extensions>
</Platform>
<Platform Name="OSX32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
</DeployClass>
<ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="OSX32" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
</Deployment>
<Platforms>
<Platform value="iOSDevice64">True</Platform>
<Platform value="Android">False</Platform>
<Platform value="iOSDevice32">False</Platform>
<Platform value="iOSDevice64">False</Platform>
<Platform value="iOSSimulator">False</Platform>
<Platform value="OSX32">False</Platform>
<Platform value="Win32">True</Platform>
<Platform value="Win64">False</Platform>
</Platforms>
</BorlandProject>
<ProjectFileVersion>12</ProjectFileVersion>
</ProjectExtensions>
<Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
<Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
<Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
</Project>

Binary file not shown.

View File

@ -3,31 +3,74 @@ unit TestStompClientU;
interface
uses
TestFramework;
DUnitX.TestFramework, StompClient, StompTypes, System.Diagnostics, System.SysUtils;
type
TTestStompClient = class(TTestCase)
published
procedure TestAssertTrue;
procedure TestAssertFalse;
[TestFixture]
TTestSTOMP = class(TObject)
private
FSTOMP: IStompClient;
public
[Setup]
procedure Setup;
[TearDown]
procedure TearDown;
// Sample Methods
// Simple single Test
[Test]
procedure TestPubSub10;
// Test with TestCase Attribute to supply parameters.
// [Test]
// [TestCase('TestA', '1,2')]
// [TestCase('TestB', '3,4')]
// procedure Test2(const AValue1: Integer; const AValue2: Integer);
end;
implementation
{ TTestStompClient }
procedure TTestStompClient.TestAssertFalse;
procedure TTestSTOMP.Setup;
begin
CheckTrue(false);
// FSTOMP := TStompClient.CreateAndConnect('127.0.0.1', 61613, '',
// TStompAcceptProtocol.Ver_1_0);
end;
procedure TTestStompClient.TestAssertTrue;
procedure TTestSTOMP.TearDown;
begin
CheckTrue(true);
// FSTOMP := nil;
end;
procedure TTestSTOMP.TestPubSub10;
var
lFrame: IStompFrame;
lSW: TStopWatch;
lSTOMP: IStompClient;
I: Integer;
begin
lSTOMP := TStompClient.Create;
lSTOMP.SetHeartBeat(1000, 0);
lSTOMP.Connect('127.0.0.1', 61613, '', TStompAcceptProtocol.Ver_1_1);
lSTOMP.Subscribe('/topic/mytopic');
Sleep(10000);
lSTOMP.Send('/topic/mytopic', 'Hello World1');
lSTOMP.Send('/topic/mytopic', 'Hello World2');
lSTOMP.Send('/topic/mytopic', 'Hello World3');
lSTOMP.Send('/topic/mytopic', 'Hello World4');
lSTOMP.Send('/topic/mytopic', 'Hello World5');
lSW := TStopWatch.Create;
for I := 1 to 5 do
begin
lFrame := lSTOMP.Receive(5000);
Assert.IsTrue(lSW.ElapsedMilliseconds <= 50);
Assert.IsNotNull(lFrame, 'Message not received by the sender');
Assert.AreEqual('Hello World' + I.ToString, lFrame.Body);
end;
lFrame := lSTOMP.Receive(50);
end;
initialization
RegisterTest(TTestStompClient.Suite);
TDUnitX.RegisterTestFixture(TTestSTOMP);
end.