unit ExtendedFileTransferClientDownloadThread; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, uROClient, uROClientIntf, uRORemoteService, uROBinMessage, uROIndyTCPChannel, uROIndyHTTPChannel, ExtendedFileTransferLibrary_Intf, uROTypes; type { TROThread } TDownloadThread = class(TThread) private fROMessage: TROBinMessage; fROChannel: TROIndyHTTPChannel; fRORemoteService: TRORemoteService; fOnAbort: TNotifyEvent; fOnFinished: TNotifyEvent; fOnProgress: TNotifyEvent; fOnStartDownload: TNotifyEvent; fOnError: TNotifyEvent; fDownloadOK: Boolean; fCurrentBytePos: Int64; fTimeStarted: TDateTime; fDownloadDir: string; fFileService: IExtendedFileTransferService; fErrortext: string; fFileName: string; fFileSize: Int64; fInfoStr: string; fMaxConnectionErrors, fChannelErrorscount: Integer; procedure RunDownload; procedure ROIndyChannelFailure(Sender: TROTransportChannel; anException: Exception; var Retry: Boolean); procedure Run; protected public property DownloadOK: Boolean read fDownloadOK; property FileName: string read fFileName; property FileSize: Int64 read fFileSize; property InfoStr: string read fInfoStr; property ErrorText: string read fErrortext; property CurrentBytePos: Int64 read fCurrentBytePos; property TimeStarted: TDateTime read fTimeStarted; constructor Create(aDownloadDir, aFilename: string; aFileSize: Int64; aOnStartDownload, aOnProgress, aOnFinished, aOnAbort, aOnError: TNotifyEvent); destructor Destroy; override; procedure Execute; override; end; implementation uses ExtendedFileTransferClientMain; { TROThread } constructor TDownloadThread.Create(aDownloadDir, aFilename: string; aFileSize: Int64; aOnStartDownload, aOnProgress, aOnFinished, aOnAbort, aOnError: TNotifyEvent); begin inherited Create(TRUE); fDownloadDir := aDownloadDir; fFilename := aFilename; fFileSize := aFileSize; fmaxconnectionerrors := 5; //try 5 times on channel-error fROMessage := TROBinMessage.Create(nil); fROChannel := TROIndyHTTPChannel.Create(nil); fROChannel.OnFailure := ROIndyChannelFailure; fROChannel.TargetURL := ExtendedFileTransferClientMainForm.ROChannel.TargetURL; fRORemoteService := TRORemoteService.Create(nil); fRORemoteService.Channel := fROChannel; fRORemoteService.Message := fROMessage; fRORemoteService.ServiceName := 'ExtendedFileTransferService'; fFileService := fRORemoteService as IExtendedFileTransferService; if assigned(aOnAbort) then fOnAbort := aOnAbort; if assigned(aOnFinished) then fOnFinished := aOnFinished; if assigned(aOnProgress) then fOnProgress := aOnProgress; if assigned(aOnStartDownload) then fOnStartDownload := aOnStartDownload; if assigned(aOnError) then fOnError := aOnError; FreeOnTerminate:=True; Resume; end; destructor TDownloadThread.Destroy; begin fFileService := nil; FreeAndNil(fROMessage); FreeAndNil(fROChannel); FreeAndNil(fRORemoteService); inherited; end; procedure TDownloadThread.Execute; begin Run; end; procedure TDownloadThread.Run; begin try RunDownload; finally if assigned(fOnFinished) then fOnFinished(Self); end; end; procedure TDownloadThread.RunDownload; var NewFile: TMemoryStream; Chunk: Binary; Sequence: Integer; begin fDownloadOK := false; Chunk := nil; try if Terminated then begin if assigned(fOnAbort) then fOnAbort(Self); exit; end; NewFile := TMemoryStream.Create; try fCurrentBytePos := 0; Sequence := 1; fTimeStarted := Now; fFileService.downloadsequence(fFilename, Sequence, chunk, fFileSize); fInfoStr := DateTimetoStr(fTimeStarted) + ' ' + ExtractFileName(fFilename) + ' ' + FloatToStrF(fFilesize / 1024, fffixed, 15, 1) + ' KB'; if assigned(fOnStartDownload) then fOnStartDownload(Self); while (chunk <> nil) and (Chunk.Size > 0) do begin if Terminated then begin FreeAndNil(Chunk); if assigned(fOnAbort) then fOnAbort(Self); exit; end; NewFile.Seek(0, soFromEnd); NewFile.CopyFrom(Chunk, Chunk.Size); Inc(fCurrentBytePos, Chunk.Size); FreeAndNil(Chunk); if assigned(fOnProgress) then fOnProgress(Self); Inc(Sequence); fFileService.downloadsequence(fFilename, Sequence, chunk, fFileSize); end; fDownloadOK := (NewFile.Size = 0) or (fFileSize = CurrentBytePos); if fDownloadOK then begin NewFile.SaveToFile(IncludeTrailingPathDelimiter(fDownloadDir) + fFilename); fDownloadOK := Fileexists(IncludeTrailingPathDelimiter(fDownloadDir) + fFilename); end; finally FreeAndNil(Chunk); NewFile.Free; end; except on e: Exception do begin fErrorText := e.Message; fDownloadOK := false; if assigned(fOnError) then fOnError(Self); end; end; end; procedure TDownloadThread.ROIndyChannelFailure(Sender: TROTransportChannel; anException: Exception; var Retry: Boolean); begin if fChannelErrorscount > fMaxConnectionerrors then begin fErrorText := anException.Message; Self.terminate; end else begin inc(fChannelErrorscount); sleep(1000); Retry := true; end; end; end.