restemplate/indy/SuperCore/IdWorkOpUnits.pas

432 lines
10 KiB
Plaintext

{
$Project$
$Workfile$
$Revision$
$DateUTC$
$Id$
This file is part of the Indy (Internet Direct) project, and is offered
under the dual-licensing agreement described on the Indy website.
(http://www.indyproject.org/)
Copyright:
(c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
}
{
$Log$
}
{
Rev 1.4 6/11/2004 8:40:12 AM DSiders
Added "Do not Localize" comments.
Rev 1.3 2004.05.06 1:47:28 PM czhower
Now uses IndexOf
Rev 1.2 2004.04.22 11:45:18 PM czhower
Bug fixes
Rev 1.1 2004.02.09 9:16:58 PM czhower
Updated to compile and match lib changes.
Rev 1.0 2004.02.03 12:39:10 AM czhower
Move
Rev 1.14 2003.10.19 2:50:42 PM czhower
Fiber cleanup
Rev 1.13 2003.10.11 5:44:20 PM czhower
Chained servers now functional.
Rev 1.12 2003.07.17 4:42:08 PM czhower
More IOCP improvements.
Rev 1.11 2003.07.17 3:55:18 PM czhower
Removed IdIOChainEngineIOCP and merged it into TIdChaingEngine in
IdIOHandlerChain.pas.
Rev 1.7 2003.07.14 11:00:52 PM czhower
More IOCP fixes.
Rev 1.6 2003.07.14 12:54:34 AM czhower
Fixed graceful close detection if it occurs after connect.
Rev 1.5 7/7/2003 1:25:26 PM BGooijen
Added BytesSent property to TIdWorkOpUnitWriteFile
Rev 1.4 7/5/2003 11:47:14 PM BGooijen
Added TIdWorkOpUnitCheckForDisconnect and TIdWorkOpUnitWriteFile
Rev 1.3 3/27/2003 2:43:06 PM BGooijen
Added woWriteStream and woWriteBuffer
Rev 1.2 3/22/2003 09:45:30 PM JPMugaas
Now should compile under D4.
Rev 1.1 3/2/2003 12:36:26 AM BGooijen
Added woReadBuffer and TIdWorkOpUnitReadBuffer to read a buffer. Now
ReadBuffer doesn't use ReadStream any more.
TIdIOHandlerChain.ReadLn now supports MaxLineLength (splitting, and
exceptions).
woReadLn doesn't check the intire buffer any more, but continued where it
stopped the last time.
Added basic support for timeouts (probably only on read operations, and maybe
connect), accuratie of timeout is currently 500msec.
Rev 1.0 2/27/2003 10:11:50 PM BGooijen
WorkOpUnits combined in one file
}
unit IdWorkOpUnits;
interface
uses
Classes,
IdWorkOpUnit, IdGlobal,
SysUtils;
type
TIdWorkOpUnitStreamBaseRead = class(TIdWorkOpUnitRead)
protected
FStream: TStream;
public
constructor Create(AStream: TStream); reintroduce; virtual;
end;
TIdWorkOpUnitStreamBaseWrite = class(TIdWorkOpUnitWrite)
protected
FFreeStream: Boolean;
FStream: TStream;
public
constructor Create(
AStream: TStream;
AFreeStream: Boolean = True
); reintroduce; virtual;
destructor Destroy; override;
end;
TIdWorkOpUnitWriteBuffer = class(TIdWorkOpUnitWrite)
protected
FBuffer: Pointer;
FFreeBuffer: Boolean;
FSize: Integer;
//
procedure Processing(ABytes: Integer); override;
procedure Starting; override;
public
constructor Create(ABuffer: Pointer; ASize: Integer;
AFreeBuffer: Boolean = True); reintroduce; virtual;
destructor Destroy; override;
end;
TIdWorkOpUnitWriteFile = class(TIdWorkOpUnitWrite)
protected
FFilename: String;
FBytesSent: Integer;
//
procedure Processing(ABytes: Integer); override;
procedure Starting; override;
public
constructor Create(AFileName: string); reintroduce;
end;
TIdWorkOpUnitWriteStream = class(TIdWorkOpUnitStreamBaseWrite)
protected
FCount: Integer;
FStartPos: Integer;
//
procedure Processing(ABytes: Integer); override;
procedure Starting; override;
public
constructor Create(AStream: TStream; AStartPos, ACount: Integer;
AFreeStream: Boolean); reintroduce; virtual;
end;
TIdWorkOpUnitWaitConnected = class(TIdWorkOpUnit)
protected
procedure Starting; override;
public
procedure Process(
AOverlapped: PIdOverlapped;
AByteCount: Integer
); override;
end;
TIdWorkOpUnitReadSized = class(TIdWorkOpUnitRead)
protected
FSize: Integer;
//
procedure Processing(
ABuffer: TIdBytes
); override;
public
constructor Create(ASize: Integer); reintroduce;
end;
TIdWorkOpUnitReadSizedStream = class(TIdWorkOpUnitStreamBaseRead)
protected
FSize: Integer;
//
procedure Processing(
ABuffer: TIdBytes
); override;
public
constructor Create(AStream: TStream; ASize: Integer);
reintroduce;
end;
TIdWorkOpUnitReadLn = class(TIdWorkOpUnitRead)
protected
FLastPos: Integer;
FMaxLength: Integer;
FTerminator: string;
//
procedure Processing(
ABuffer: TIdBytes
); override;
public
constructor Create(
ATerminator: string;
AMaxLength: Integer
); reintroduce;
end;
TIdWorkOpUnitReadUntilDisconnect = class(TIdWorkOpUnitStreamBaseRead)
protected
procedure Processing(
ABuffer: TIdBytes
); override;
end;
TIdWorkOpUnitReadAvailable = class(TIdWorkOpUnitRead)
protected
procedure Processing(
ABuffer: TIdBytes
); override;
end;
implementation
{ TIdWorkOpUnitWriteStream }
constructor TIdWorkOpUnitWriteStream.Create(AStream: TStream; AStartPos,ACount:integer; AFreeStream: Boolean);
begin
inherited Create(AStream, AFreeStream);
FStream.Position := AStartPos;
FCount := ACount;
end;
procedure TIdWorkOpUnitWriteStream.Processing(ABytes: Integer);
//TODO: This used to use pages from IdBuffer, which because of .Net do not exist
// anymore. We need to maybe keep a local persistent buffer instead then for
// storage reasons.
var
LBuffer: TIdBytes;
LSize: Integer;
begin
FCount := FCount - ABytes;
if FCount = 0 then begin
Complete;
end else begin
FStream.Position := ABytes;
//
//TODO: Dont hard code this value. Also find an optimal size for IOCP
LSize := Min(FCount, WOPageSize);
SetLength(LBuffer, LSize);
//
FStream.ReadBuffer(LBuffer[0], LSize);
Write(@LBuffer[0], LSize);
end;
end;
procedure TIdWorkOpUnitWriteStream.Starting;
begin
Processing(0);
end;
{ TIdWorkOpUnitWriteBuffer }
constructor TIdWorkOpUnitWriteBuffer.Create(ABuffer: pointer; ASize: integer; AFreeBuffer: Boolean = True);
begin
inherited Create;
FSize := ASize;
FBuffer := ABuffer;
FFreeBuffer := AFreeBuffer;
end;
destructor TIdWorkOpUnitWriteBuffer.Destroy;
begin
if FFreeBuffer then begin
FreeMem(FBuffer);
FBuffer := nil;
end;
inherited;
end;
procedure TIdWorkOpUnitWriteBuffer.Processing(ABytes: Integer);
begin
//TODO: Change the pointer to a type that points to bytes
FBuffer := Pointer(Cardinal(FBuffer) + Cardinal(ABytes));
FSize := FSize - ABytes;
if FSize = 0 then begin
Complete;
end else begin
//TODO: Reduce this down so it never sends more than a page
Write(FBuffer, Min(FSize, WOPageSize));
end;
end;
procedure TIdWorkOpUnitWriteBuffer.Starting;
begin
Processing(0);
end;
{ TIdWorkOpUnitWriteFile }
constructor TIdWorkOpUnitWriteFile.Create(AFileName:string);
begin
inherited Create;
FFilename := AFileName;
end;
procedure TIdWorkOpUnitWriteFile.Processing(ABytes: Integer);
begin
Assert(False, 'Need to implement WriteFile, also add to a bubble'); {do not localize}
end;
procedure TIdWorkOpUnitWriteFile.Starting;
begin
end;
{ TIdWorkOpUnitSizedStream }
constructor TIdWorkOpUnitReadSizedStream.Create(AStream: TStream; ASize:integer);
begin
inherited Create(AStream);
FSize := ASize;
end;
procedure TIdWorkOpUnitWaitConnected.Process(
AOverlapped: PIdOverlapped;
AByteCount: Integer
);
begin
end;
procedure TIdWorkOpUnitWaitConnected.Starting;
begin
end;
{ TIdWorkOpUnitReadLn }
constructor TIdWorkOpUnitReadLn.Create(
ATerminator: string;
AMaxLength: Integer);
begin
inherited Create;
FLastPos := 1;
FTerminator := ATerminator;
FMaxLength := AMaxLength;
end;
procedure TIdWorkOpUnitReadLn.Processing(
ABuffer: TIdBytes
);
begin
//TODO: ReadLn is very common. Need to optimize this class and maybe
// even pass pack the result directly so we dont search twice.
//Also allow for hinting from the user.
IOHandler.InputBuffer.Write(ABuffer);
if not IOHandler.Connected then begin
Complete;
end else if IOHandler.InputBuffer.IndexOf(FTerminator, FLastPos) = -1 then begin
Read;
end else begin
Complete;
end;
end;
procedure TIdWorkOpUnitReadUntilDisconnect.Processing(
ABuffer: TIdBytes
);
begin
// 0 is disconnected, so keep requesting til 0
if Length(ABuffer) = 0 then begin
Complete;
end else begin
FStream.WriteBuffer(ABuffer[0], Length(ABuffer));
Read;
end;
end;
{ TIdWorkOpUnitReadAvailable }
procedure TIdWorkOpUnitReadAvailable.Processing(
ABuffer: TIdBytes
);
begin
Complete;
end;
{ TIdWorkOpUnitReadSized }
constructor TIdWorkOpUnitReadSized.Create(ASize: Integer);
begin
inherited Create;
FSize := ASize;
end;
procedure TIdWorkOpUnitReadSized.Processing(
ABuffer: TIdBytes
);
begin
IOHandler.InputBuffer.Write(ABuffer);
FSize := FSize - Length(ABuffer);
if FSize = 0 then begin
Complete;
end else begin
Read;
end;
end;
{ TIdWorkOpUnitStreamBaseRead }
constructor TIdWorkOpUnitStreamBaseRead.Create(AStream: TStream);
begin
inherited Create;
FStream := AStream;
end;
{ TIdWorkOpUnitStreamBaseWrite }
constructor TIdWorkOpUnitStreamBaseWrite.Create(AStream: TStream;
AFreeStream: Boolean);
begin
inherited Create;
FStream := AStream;
FFreeStream := AFreeStream;
end;
destructor TIdWorkOpUnitStreamBaseWrite.Destroy;
begin
if FFreeStream then begin
FreeAndNil(FStream);
end;
inherited;
end;
procedure TIdWorkOpUnitReadSizedStream.Processing(
ABuffer: TIdBytes
);
begin
FStream.WriteBuffer(ABuffer[0], Length(ABuffer));
FSize := FSize - Length(ABuffer);
if FSize = 0 then begin
Complete;
end else begin
Read;
end;
end;
end.