{ $HDR$}
{**********************************************************************}
{ Unit archived using Team Coherence                                   }
{ Team Coherence is Copyright 2002 by Quality Software Components      }
{                                                                      }
{ For further information / comments, visit our WEB site at            }
{ http://www.TeamCoherence.com                                         }
{**********************************************************************}
{}
{ $Log:  18245: ChainClients.pas 
{
{   Rev 1.5    6/24/2003 01:15:08 PM  JPMugaas
{ Updated for API change.
}
{
{   Rev 1.4    2003.05.19 10:18:02 AM  czhower
}
{
{   Rev 1.3    2003.04.22 9:56:18 PM  czhower
}
{
    Rev 1.2    4/16/2003 4:51:54 PM  BGooijen
}
{
{   Rev 1.1    2003.04.15 12:46:10 PM  czhower
}
{
{   Rev 1.11    2003.04.10 11:23:46 PM  czhower
}
{
{   Rev 1.10    2003.03.27 1:32:06 AM  czhower
{ More fiber tests
}
{
{   Rev 1.9    2003.03.27 12:46:20 AM  czhower
}
{
{   Rev 1.8    2003.03.27 12:29:34 AM  czhower
}
{
{   Rev 1.7    2003.02.27 12:55:40 AM  czhower
}
{
{   Rev 1.6    2003.02.25 1:38:28 AM  czhower
}
{
{   Rev 1.5    2003.02.18 1:36:18 PM  czhower
}
{
{   Rev 1.4    2003.01.17 4:41:30 PM  czhower
}
{
{   Rev 1.3    2003.01.09 11:25:30 PM  czhower
}
{
{   Rev 1.0    2002.12.07 6:44:02 PM  czhower
}
unit ChainClients;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls,
  IdFiber, IdTCPClient, IdSync, ExtCtrls, IdIOHandlerChain,
  ComCtrls, BXBubble;

type
  TformChainClients = class(TForm)
    Panel1: TPanel;
    Label2: TLabel;
    Label1: TLabel;
    Label4: TLabel;
    Label3: TLabel;
    lablThreads: TLabel;
    lablReturns: TLabel;
    butnFiber: TButton;
    editFibers: TEdit;
    editRepeat: TEdit;
    editDocument: TEdit;
    editHost: TEdit;
    memoTest: TMemo;
    ChainClient: TBXBubble;
    GroupBox1: TGroupBox;
    radoTCP: TRadioButton;
    radoHTTP: TRadioButton;
    GroupBox2: TGroupBox;
    radoWinsock: TRadioButton;
    radoIOCP: TRadioButton;
    procedure butnFiberClick(Sender: TObject);
    procedure ChainClientPlayground(Sender: TBXBubble);
  private
  protected
    FMainFiber: TIdConvertedFiber;
    FStream: TStringStream;
    FReturnCount: Integer;
    FThreadCount: Integer;
    //
    procedure HTTPTestFiber(const AUseHTTP: Boolean; const AUseIOCP: Boolean);
    procedure OnFiberIdle(AFiber: TObject);
    procedure OnFiberSwitch(AFiberWeaver: TIdFiberWeaver; AFiber: TIdFiberBase);
    procedure UpdateLabels;
  public
  end;

  TClientFiber = class(TIdFiber)
  protected
    FChainEngine: TIdChainEngine;
    FDocument: string;
    FFiberWeaver: TIdFiberWeaver;
    FHost: string;
  end;

  TTCPFiber = class(TClientFiber)
  protected
    procedure Execute; override;
  end;

  THTTPFiber = class(TClientFiber)
  protected
    procedure Execute; override;
  end;

var
  formChainClients: TformChainClients;

implementation
{$R *.dfm}

uses
  IdIOHandlerStack, IdChainEngineIOCP, IdCoreGlobal, IdStack,
  IdChainEngineStack, IdHTTP, IdFiberWeaverDefault,
  SyncObjs;

procedure TformChainClients.UpdateLabels;
begin
  lablThreads.Caption := 'Threads: ' + IntToStr(FThreadCount);
  lablReturns.Caption := 'Returns: ' + IntToStr(FReturnCount);
end;

procedure TformChainClients.butnFiberClick(Sender: TObject);
var
  i: Integer;
begin
  for i := 1 to StrToInt(editRepeat.Text) do begin
    HTTPTestFiber(radoHTTP.Checked, radoIOCP.Checked);
  end;
  memoTest.Lines.Add(' ======= Done ========== ');
end;

{ TTCPFiber }

procedure TTCPFiber.Execute;
var
  LHTTPResult: TStringStream;
  LIOHandler: TIdIOHandlerChain;
begin
  // The IOHandlerChain "links" the IOHandler to the FiberWeaver and integrates
  // with its scheduling mechanism
  //
  // The fiber is also passed so it knows which fiber it will use for this
  // instance of IOHandler.
  //
  // The IOHandlerChain is actually independent of the IO itself, it merely
  // queues and communicates with the ChainEngine. The ChainEngine does all the
  // actuall IO and will be pluggable. Right now its using Stack as Phase I, but
  // later will have options to use IOCP, Overlapped IO or other.
  LIOHandler := TIdIOHandlerChain.Create(nil, FChainEngine, FFiberWeaver
   , Self); try
    with TIdTCPClient.Create(nil) do try
      IOHandler := LIOHandler;
      Host := FHost;
      Port := 80;
      Connect; try
        IOHandler.Write('GET ' + FDocument + ' HTTP/1.0' + EOL + EOL);
        LHTTPResult := TStringStream.Create(''); try
          IOHandler.ReadStream(LHTTPResult, -1, True);
          with formChainClients.memoTest.Lines do begin
            Add(LHTTPResult.DataString);
            Add(EOL + '_____________________' + EOL);
          end;
          Inc(formChainClients.FReturnCount);
          formChainClients.UpdateLabels;
        finally FreeAndNil(LHTTPResult); end;
      finally Disconnect; end;
    finally Free; end;
  finally FreeAndNil(LIOHandler); end;
end;

procedure TformChainClients.HTTPTestFiber(const AUseHTTP: Boolean;
 const AUseIOCP: Boolean);
var
  i: Integer;
  LChainEngine: TIdChainEngine;
  LFiberWeaver: TIdFiberWeaverDefault;
  LFibers: TList;
  LFiber: TClientFiber;
  LSelfFiber: TIdConvertedFiber;
begin
  if AUseIOCP then begin
    LChainEngine := TIdChainEngineIOCP.Create(nil);
  end else begin
    LChainEngine := TIdChainEngineStack.Create(nil);
  end;
  try
    // All fibers MUST have a parent fiber. The parent fiber is the
    // fiber that gets "fallen back" on when all other fibers have finished.
    // A converted fiber is a special fiber, its a fiber that is created "out of"
    // the current thread.
    LSelfFiber := TIdConvertedFiber.Create; try
      LSelfFiber.Name := 'Converted';
      // The fiber weaver is a scheduler for the fibers. It schedules the fibers
      // onto threads and
      LFiberWeaver := TIdFiberWeaverDefault.Create(nil); try
        // This is a list of fibers so we can destroy them later.
        LFibers := TList.Create; try
          // Create the specified number of fibers and add them to the FiberWeaver
          for i := 1 to StrToInt(editFibers.Text) do begin
            if AUseHTTP then begin
              LFiber := THTTPFiber.Create(LSelfFiber, LFiberWeaver);
            end else begin
              LFiber := TTCPFiber.Create(LSelfFiber, LFiberWeaver);
            end;
            LFiber.Name := 'Fiber ' + IntToStr(i);
            with LFiber do begin
              FChainEngine := LChainEngine;
              FFiberWeaver := LFiberWeaver;
              FHost := Trim(editHost.Text);
              FDocument := Trim(editDocument.Text);
            end;
            LFibers.Add(LFiber);
          end;
          // Run fibers. This will run all fibers until every fiber has run and
          // completed. It will then return. In this case, all fibers will run
          // under this thread.
          LFiberWeaver.ProcessInThisFiber(LSelfFiber);
          // Free the fibers
          for i := 0 to LFibers.Count - 1 do begin
            TIdFiber(LFibers[i]).Free;
          end;
        finally FreeAndNil(LFibers); end;
      // Freeing causes AVs - trying to fix this now
      finally FreeAndNil(LFiberWeaver); end;
    finally FreeAndNil(LSelfFiber); end;
  finally FreeAndNil(LChainEngine); end;
end;

procedure TformChainClients.OnFiberSwitch(AFiberWeaver: TIdFiberWeaver;
 AFiber: TIdFiberBase);
begin
  Application.ProcessMessages;
end;

procedure TformChainClients.OnFiberIdle(AFiber: TObject);
begin
  Application.ProcessMessages;
end;

{ THTTPFiber }

procedure THTTPFiber.Execute;
var
  LHTTPResult: TStringStream;
  LIOHandler: TIdIOHandlerChain;
begin
  LIOHandler := TIdIOHandlerChain.Create(nil, FChainEngine, FFiberWeaver
   , Self); try
    with TIdHTTP.Create(nil) do try
      IOHandler := LIOHandler;
      LHTTPResult := TStringStream.Create(''); try
        Get('http://' + FHost + FDocument, LHTTPResult);
        with formChainClients.memoTest.Lines do begin
          Add(LHTTPResult.DataString);
          Add(EOL + '_____________________' + EOL);
        end;
        Inc(formChainClients.FReturnCount);
        formChainClients.UpdateLabels;
      finally FreeAndNil(LHTTPResult); end;
    finally Free; end;
  finally FreeAndNil(LIOHandler); end;
end;

procedure TformChainClients.ChainClientPlayground(Sender: TBXBubble);
begin
  ShowModal;
end;

end.
