Advertisement
Guest User

Untitled

a guest
Apr 25th, 2013
543
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. type
  2.  {
  3.   Default TIdIOHandler implementation hangs in ReadBytes until it reads at least
  4.   RecvBufferSize, see:
  5.     http://stackoverflow.com/questions/15615347/http-continuous-packeted-stream-with-indy
  6.   This is unacceptable with event streams as events have to be handled timely
  7.   as they received.
  8.  }
  9.   TIdStreamIoHandler = class(TIdIOHandlerStack)
  10.   public
  11.     function TryReadBytes(var VBuffer: TIdBytes; AByteCount: Integer;
  12.       AAppend: Boolean = True): integer; virtual;
  13.     procedure ReadStream(AStream: TStream; AByteCount: TIdStreamSize = -1;
  14.      AReadUntilDisconnect: Boolean = False); override;
  15.   end;
  16.  
  17.  
  18. //Reads up to AByteCount bytes in one go. Returns the number of bytes read, >0.
  19. //Copied from ReadBytes with some modifications.
  20. function TIdStreamIOHandler.TryReadBytes(var VBuffer: TIdBytes; AByteCount: Integer;
  21.   AAppend: Boolean = True): integer;
  22. begin
  23.   Assert(FInputBuffer<>nil);
  24.   if AByteCount > 0 then begin
  25.     // Read from stack if we have not enough data
  26.     if FInputBuffer.Size < AByteCount then begin
  27.       ReadFromSource(False); //whatever we can
  28.       CheckForDisconnect(True, True);
  29.     end;
  30.     Result := IndyMin(AByteCount, FInputBuffer.Size);
  31.     FInputBuffer.ExtractToBytes(VBuffer, Result, AAppend);
  32.   end else if AByteCount < 0 then begin
  33.     ReadFromSource(False, ReadTimeout, False);
  34.     CheckForDisconnect(True, True);
  35.     Result := FInputBuffer.Size;
  36.     FInputBuffer.ExtractToBytes(VBuffer, Result, AAppend);
  37.   end else
  38.     Result := 0;
  39. end;
  40.  
  41. { Copied from TIdIOHandler.ReadStream with adjustments and simplifications.
  42. ReadUntilDisconnect: Read all data until the connection closes.
  43.   Data is processed in RecvBufferSize chunks, or in how much is available.
  44. AByteCount>0 + !ReadUntilDisconnect: Read up to AByteCount in one go.
  45. AByteCount<0 + !ReadUntilDisconnect: Read all available data in one go.
  46. }
  47. procedure TIdStreamIOHandler.ReadStream(AStream: TStream; AByteCount: TIdStreamSize;
  48.   AReadUntilDisconnect: Boolean);
  49. var
  50.   i: Integer;
  51.   LBuf: TIdBytes;
  52.   LByteCount: TIdStreamSize;
  53. begin
  54.   Assert(AStream<>nil);
  55.   LByteCount := AByteCount;
  56.  
  57.   if AReadUntilDisconnect and (AByteCount>0) then
  58.     AByteCount := -1;
  59.  
  60.   if AReadUntilDisconnect then begin
  61.     BeginWork(wmRead);
  62.   end else begin
  63.     BeginWork(wmRead, LByteCount);
  64.   end;
  65.  
  66.   try
  67.     // If data already exists in the buffer, write it out first.
  68.     // should this loop for all data in buffer up to workcount? not just one block?
  69.     if FInputBuffer.Size > 0 then begin
  70.       if AByteCount<0 then begin
  71.         i := FInputBuffer.Size;
  72.       end else begin
  73.         i := IndyMin(FInputBuffer.Size, LByteCount);
  74.         Dec(LByteCount, i);
  75.       end;
  76.       FInputBuffer.ExtractToStream(AStream, i);
  77.     end;
  78.  
  79.     // RLebeau - don't call Connected() here!  ReadBytes() already
  80.     // does that internally. Calling Connected() here can cause an
  81.     // EIdConnClosedGracefully exception that breaks the loop
  82.     // prematurely and thus leave unread bytes in the InputBuffer.
  83.     // Let the loop catch the exception before exiting...
  84.  
  85.     SetLength(LBuf, RecvBufferSize); // preallocate the buffer
  86.     repeat
  87.  
  88.       if AByteCount<0 then begin
  89.         i := -1;
  90.       end else begin
  91.         i := IndyMin(LByteCount, RecvBufferSize);
  92.         if i < 1 then break;
  93.       end;
  94.  
  95.       try
  96.         try
  97.           i := TryReadBytes(LBuf, i, False);
  98.         except
  99.           on E: Exception do begin
  100.             // RLebeau - ReadFromSource() inside of ReadBytes()
  101.             // could have filled the InputBuffer with more bytes
  102.             // than actually requested, so don't extract too
  103.             // many bytes here...
  104.             if i>0 then //else it's already -1 or 0
  105.               i := IndyMin(i, FInputBuffer.Size);
  106.             FInputBuffer.ExtractToBytes(LBuf, i, False);
  107.             if (E is EIdConnClosedGracefully) and AReadUntilDisconnect then
  108.               break
  109.             else
  110.               raise;
  111.           end;
  112.         end;
  113.         TIdAntiFreezeBase.DoProcess;
  114.       finally
  115.         if i > 0 then begin //how much was read
  116.           TIdStreamHelper.Write(AStream, LBuf, i);
  117.           if not AReadUntilDisconnect then
  118.             Dec(LByteCount, i);
  119.         end;
  120.       end;
  121.  
  122.     until false;
  123.  
  124.   finally
  125.     EndWork(wmRead);
  126.     LBuf := nil;
  127.   end;
  128. end;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement