unit uHTTPRequests_TPS_ChunkUploader;

interface

uses
  System.SysUtils, System.Classes, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
  IdHTTP,IdException, Vcl.Dialogs,IdMultipartFormData,system.NetEncoding,System.Types,
  System.IOUtils;

type
  THTTPRequests_TPS_ChunkUploader = class(TDataModule)
  IdHTTP: TIdHTTP;

  private
    { Private declarations }

    FHTTPServerToRequest:string;
    procedure EncodeParam(var AParam:string);


  public
    { Public declarations }

   constructor Create(AOwner: TComponent); override;

   function IsHTTPConnectionOk(): boolean;

   function CreateDirOnServer(Adir:String):Boolean; // encoded decoded done
   function DeleteDirOnServer(Adir:string):Boolean; // encoded decoded


   function SendOneWholeFile(     // encoded decoded done

      AFilepath:string;
      ARelativeDirOnServer: string;
      AFileNameOnServer:string;
      AidUsersString:String

   ):Boolean;

   function SendChunksInfoFile(ATempDirOnServer,AChunkInfoFilePath:string):Boolean;
   {< deprecated, all files sent from SendManyFiles function }

   function SendManyFiles(AbsTempDirOnClient:string; ARelativeDirOnServer:String):Boolean;
   function SendManyFilesFromLastSuccessfull( LastSuccessfullChunk: integer): Boolean;

   function IsCheckChunksIntegrityOk(ARelativeDirOnServer:string; AChunksInfoFileName:string):Boolean;
   function GatherFileFromChunks(ARelativeChunksDirOnServer, ARelativeOutPutDirOnServer, AOutPutFileName: string; AidUserString:String):Boolean;

   property HTTPServerToRequest:string read FHTTPServerToRequest write FHTTPServerToRequest;

  end;


implementation

{%CLASSGROUP 'Vcl.Controls.TControl'}

uses uVisualFrame_TPS_ChunkUploader;
var VisualFrame_TPS_ChunkUploader_UnitVar:TVisualFrame_TPS_ChunkUploader;

{$R *.dfm}

{ THTTPRequests_TPS_ChunkUploader }

constructor THTTPRequests_TPS_ChunkUploader.Create(AOwner: TComponent);
begin
  inherited;

  if (AOwner is TVisualFrame_TPS_ChunkUploader) then
     VisualFrame_TPS_ChunkUploader_UnitVar:=(AOwner as TVisualFrame_TPS_ChunkUploader);

end;




function THTTPRequests_TPS_ChunkUploader.CreateDirOnServer(Adir: String): Boolean;

var
  PostData: TIdMultiPartFormDataStream;
  MyServerResponse:string;

begin

Result:=false;

 if not IsHTTPConnectionOk() then Exit();

 PostData := TIdMultiPartFormDataStream.Create;
 try

       try
          //Encoding Params
          EncodeParam(Adir);

          //Sending
          idHTTP.Request.Referer := FHTTPServerToRequest+'/CreateDirOnServer';
          idHTTP.Request.ContentType := 'multipart/form-data';

          PostData.AddFormField('Login', 'SomeLogin');
          PostData.AddFormField('Password', 'SomePassword');

          PostData.AddFormField('DirectoryToCreate', Adir);
          MyServerResponse:=idHTTP.Post(FHTTPServerToRequest+'/CreateDirOnServer', PostData);

          Result:=true;

       except


             on E: EIdException do

               begin

               ShowMessage( 'Communication Exception at CreateDirOnServer: ' + E.Message);

               end;


            on E: Exception do

                 begin

                 ShowMessage( 'VCL Exception at CreateDirOnServer: ' + E.Message);

                 end;

       end;

 finally
 FreeAndNil(PostData);
 end;


end;




function THTTPRequests_TPS_ChunkUploader.DeleteDirOnServer(Adir: string): Boolean;

var PostData: TIdMultiPartFormDataStream;
    MyServerResponse:string;

begin

Result:=false;

 // checks
 if not IsHTTPConnectionOk() then Exit();
 Assert(Adir<>'','Please fill Adir');

 PostData := TIdMultiPartFormDataStream.Create;
 try

       try
          EncodeParam(Adir);

          idHTTP.Request.Referer := FHTTPServerToRequest+'/DeleteDirOnServer';
          idHTTP.Request.ContentType := 'multipart/form-data';

          PostData.AddFormField('Login', 'SomeLogin');
          PostData.AddFormField('Password', 'SomePassword');

          PostData.AddFormField('DirectoryToDelete', Adir);
          MyServerResponse:=idHTTP.Post(FHTTPServerToRequest+'/DeleteDirOnServer', PostData);

          if MyServerResponse='ok' then Result:=true;

       except

             on E: EIdException do
               ShowMessage( 'Communication Exception at CreateDirOnServer: ' + E.Message);


             on E: Exception do
                 ShowMessage( 'VCL Exception at CreateDirOnServer: ' + E.Message);


       end;

 finally
 FreeAndNil(PostData);

 end;


end;


procedure THTTPRequests_TPS_ChunkUploader.EncodeParam(var AParam: string);
begin
AParam:=TNetEncoding.URL.Encode(AParam);
end;

//
function THTTPRequests_TPS_ChunkUploader.GatherFileFromChunks(

            ARelativeChunksDirOnServer,
            ARelativeOutPutDirOnServer,
            AOutPutFileName,
            AidUserString: String

             ): Boolean;

var
  PostData: TIdMultiPartFormDataStream;
  MyServerResponse:String;

begin

Result:=false;

//checks
if not IsHTTPConnectionOk() then Exit();
Assert( ARelativeChunksDirOnServer<>'','Please fill ARelativeChunksDirOnServer');
Assert( ARelativeOutPutDirOnServer<>'', 'Please fill ARelativeOutPutDirOnServer');
Assert( AOutPutFileName<>'','Please fill AOutPutFileName');
Assert( AidUserString<>'', 'Please fill AidUserString');
Assert( Assigned(VisualFrame_TPS_ChunkUploader_UnitVar), 'Please assign VisualFrame_TPS_ChunkUploader_UnitVar');

    with VisualFrame_TPS_ChunkUploader_UnitVar do begin


      begin


            PostData := TIdMultiPartFormDataStream.Create;

            try

               try

                  //Encoding params that could be more than ANSI, with Russian lang for example
                 // AOutPutFileName:=TNetEncoding.URL.Encode(AOutPutFileName);

                  EncodeParam(ARelativeChunksDirOnServer);
                  EncodeParam(ARelativeOutPutDirOnServer);
                  EncodeParam(AOutPutFileName);

                  idHTTP.Request.Referer := FHTTPServerToRequest+'/JustGatherFileFromChunks'; // 'http://localhost:40000/sendfile'; //   http://www.link.net/download';
                  idHTTP.Request.ContentType := 'multipart/form-data';

                  PostData.AddFormField('Login', 'SomeLogin');
                  PostData.AddFormField('Password', 'SomePassword');

                  PostData.AddFormField('AChunksDir', ARelativeChunksDirOnServer);
                  PostData.AddFormField('AOutPutDir', ARelativeOutPutDirOnServer);
                  PostData.AddFormField('AOutPutFileName', AOutPutFileName);
                  PostData.AddFormField('AidUserString', AidUserString);

                  MyServerResponse:=
                  idHTTP.Post(FHTTPServerToRequest+'/JustGatherFileFromChunks', PostData);

               if MyServerResponse='ok' then Result:=true;

               except

               on E: EIdException do
               ShowMessage( 'Communication Exception: ' + E.Message);

               on E: Exception do
               ShowMessage( 'VCL Exception: ' + E.Message);


               end;


            finally

            if(Assigned(PostData)) then PostData.Free;

            end;


            end;


    end;


end;




function THTTPRequests_TPS_ChunkUploader.IsCheckChunksIntegrityOk(ARelativeDirOnServer, AChunksInfoFileName: string): Boolean;
var
  PostData: TIdMultiPartFormDataStream;
  MyServerResponse:String;

begin

Result:=false;

//checks
if not IsHTTPConnectionOk() then Exit();
Assert( ARelativeDirOnServer<>'','Please fill ARelativeDirOnServer');
Assert( AChunksInfoFileName<>'', 'Please fill AChunksInfoFileName');
Assert( Assigned(VisualFrame_TPS_ChunkUploader_UnitVar), 'Please assign VisualFrame_TPS_ChunkUploader_UnitVar');

    with VisualFrame_TPS_ChunkUploader_UnitVar do begin


    begin


          PostData := TIdMultiPartFormDataStream.Create;

          try

             try

              EncodeParam(ARelativeDirOnServer);
              EncodeParam(AChunksInfoFileName);

              idHTTP.Request.Referer := FHTTPServerToRequest+'/checkChunksIntegrity';
              idHTTP.Request.ContentType := 'multipart/form-data';

              PostData.AddFormField('Login', 'SomeLogin');
              PostData.AddFormField('Password', 'SomePassword');

              PostData.AddFormField('dirOnServer', ARelativeDirOnServer);
              PostData.AddFormField('ChunksInfoFileName', AChunksInfoFileName);

              MyServerResponse:=
              idHTTP.Post(FHTTPServerToRequest+'/checkChunksIntegrity', PostData);

             if MyServerResponse='ok' then Result:=true;

             except

             on E: EIdException do
             ShowMessage( 'Communication Exception: ' + E.Message);

             on E: Exception do
             ShowMessage( 'VCL Exception: ' + E.Message);


             end;




          finally

          if(Assigned(PostData)) then PostData.Free;

          end;


          end;


    end;


end;

function THTTPRequests_TPS_ChunkUploader.IsHTTPConnectionOk(): boolean;

var MyServerResponse:String;


begin

Result:=false;

 if Assigned(VisualFrame_TPS_ChunkUploader_UnitVar) then begin


    try

    MyServerResponse:=IdHTTP.Get(FHTTPServerToRequest+'/testConnection'); // //for example like http://localhost:40000

    Result:=true;

    except

    on E: EIdException do


      Synchronize(
      procedure
      begin


        with ExampleMain do begin

        ProgressBar.Position:=Trunc( (ACountOfBytes/FFileSizeDivideInChunks)*100);
        Memo.Lines.add('OnDivideInChunksOnClient '+ProgressBar.Position.ToString+' %');

        end;

      end
      );


         ShowMessage( 'Communication Exception, SERVER CONNECTION ERROR: ' + E.Message);

    on E: Exception do
         ShowMessage( 'VCL Exception, SERVER CONNECTION ERROR: ' + E.Message);


    end;


 end;



end;


//-------------

function THTTPRequests_TPS_ChunkUploader.SendChunksInfoFile(ATempDirOnServer, AChunkInfoFilePath: string): Boolean;

var

PostData :TIdMultiPartFormDataStream;
MyServerResponse:string;


begin

 // checks
 if not IsHTTPConnectionOk() then Exit();
 Assert(ATempDirOnServer<>'','Please fill ATempDirOnServer');
 Assert(AChunkInfoFilePath<>'','Please fill AChunkInfoFilePath');

 PostData := TIdMultiPartFormDataStream.Create;

  try


     try

        idHTTP.Request.Referer := FHTTPServerToRequest+'/SendChunksInfoFile';
        idHTTP.Request.ContentType := 'multipart/form-data';

        PostData.AddFormField('login', 'SomeLogin');
        PostData.AddFormField('password', 'SomePassword');
        PostData.AddFormField('AchunksDirOnServer', ATempDirOnServer);
        PostData.AddFile('attach', AChunkInfoFilePath, 'application/x-rar-compressed');

        MyServerResponse:=idHTTP.Post(FHTTPServerToRequest+'/SendChunksInfoFile', PostData);

        Result:=true;

     except


          on E: EIdException do
           ShowMessage( 'Communication Exception at SendChunksInfoFile: ' + E.Message);

          on E: Exception do
             ShowMessage( 'VCL Exception at SendChunksInfoFile: ' + E.Message);

     end;



  finally
  FreeAndNil(PostData);

  end;


end;



function THTTPRequests_TPS_ChunkUploader.SendManyFiles(AbsTempDirOnClient: string; ARelativeDirOnServer:String): Boolean;

var
   FilesSDA:TStringDynArray;
   i:Integer;
   TotalChunkSize:Int64;

   SomeReturnValue:Boolean;

begin

Result:=False;

 //checks
 if not IsHTTPConnectionOk() then Exit();
 Assert(AbsTempDirOnClient<>'','Please fill AbsTempDirOnClient');


 // which files to send?
 FilesSDA:=TDirectory.GetFiles(AbsTempDirOnClient);
 TotalChunkSize:=0;

  // sending one by one
   for i := 0 to High(FilesSDA) do begin

   SomeReturnValue:=
   VisualFrame_TPS_ChunkUploader_UnitVar.
   SendFileInChunks.SendOneWholeFile(FilesSDA[i],ARelativeDirOnServer);

     {
     // mark last successfull chunk params for SendManyFilesFromLastSuccessfull function
     if not SomeReturnValue then begin

       with VisualFrame_TPS_ChunkUploader_UnitVar do begin

        with FilesInterruptedNotUploaded do begin

          if i>0 then begin

          FileNamesSL.Add(SendFileInChunks.FileName);
          TempDirsOnClientSL.Add(SendFileInChunks.AbsoluteTempDirOnClient);
          TempDirsOnServerSL.Add(SendFileInChunks.RelativeTempDirOnServer);
          NumberOfLastSuccessfullUploadedChunk:=2;//i-1; // Previous chunk was successfull

          end;

        end;

       end;


     end;
     }

     // Event OnUploadInChunks
     if Assigned(VisualFrame_TPS_ChunkUploader_UnitVar) then

       with VisualFrame_TPS_ChunkUploader_UnitVar do begin

       ChunkSize:=SendFileInChunks.GetFileSize(FilesSDA[i]);
       TotalChunkSize:=TotalChunkSize+ChunkSize;

         if Assigned(SendFileInChunks.OnUploadInChunks) then
         SendFileInChunks.OnUploadInChunks(Self,TotalChunkSize);


       end;



   end;

   Result:=true;

end;





function THTTPRequests_TPS_ChunkUploader.
SendManyFilesFromLastSuccessfull( LastSuccessfullChunk:integer): Boolean;

var
   FilesSDA:TStringDynArray;
   i:Integer;
   TotalChunkSize:Int64;


   TempDirOnClient:string;
   TempDirOnServer:string;

   j,k:integer;
   FileName:string;

begin

Result:=False;

 //checks
 if not IsHTTPConnectionOk() then Exit();


 Filename:=VisualFrame_TPS_ChunkUploader_UnitVar.SendFileInChunks.FileName;

//
k:=
  VisualFrame_TPS_ChunkUploader_UnitVar.FilesInterruptedNotUploaded.FileNamesSL.IndexOf(
  Filename
  );


if k<>-1 then begin
TempDirOnClient:=VisualFrame_TPS_ChunkUploader_UnitVar.FilesInterruptedNotUploaded.TempDirsOnClientSL[k];
TempDirOnServer:=VisualFrame_TPS_ChunkUploader_UnitVar.FilesInterruptedNotUploaded.TempDirsOnServerSL[k];

end;

//TempDirOnClient:=
//VisualFrame_TPS_ChunkUploader_UnitVar.FilesInterruptedNotUploaded.TempDirsOnClientSL

 // which files to send?
 FilesSDA:=TDirectory.GetFiles(TempDirOnClient);
 TotalChunkSize:=0;

  // start index
   for i := 0 to High(FilesSDA) do begin

   if ( FilesSDA[i].contains('chunk') ) and ( FilesSDA[i].contains(LastSuccessfullChunk.ToString()) )  then

   j:=i; break;

   end;

   if j<High(FilesSDA) then // High(FilesSDA) means - all chunks uploaded

   begin

          // starting from next after successfull
       for i := j+1 to High(FilesSDA) do begin

          VisualFrame_TPS_ChunkUploader_UnitVar.
          SendFileInChunks.SendOneWholeFile(FilesSDA[i],TempDirOnServer);


         // Event OnUploadInChunks
         if Assigned(VisualFrame_TPS_ChunkUploader_UnitVar) then

           with VisualFrame_TPS_ChunkUploader_UnitVar do begin

           ChunkSize:=SendFileInChunks.GetFileSize(FilesSDA[i]);
           TotalChunkSize:=TotalChunkSize+ChunkSize;

             if Assigned(SendFileInChunks.OnUploadInChunks) then
             SendFileInChunks.OnUploadInChunks(Self,TotalChunkSize);


           end;

       end;



   end;


   Result:=true;

end;



function THTTPRequests_TPS_ChunkUploader.SendOneWholeFile(

                        AFilepath:string;
                        ARelativeDirOnServer: string;
                        AFileNameOnServer:string;
                        AidUsersString:String

            ): Boolean;


var
  PostData: TIdMultiPartFormDataStream;
  MyServerResponse:string;


begin

Result:=false;

   // checks
   if not IsHTTPConnectionOk() then Exit();
   Assert(AFilePath<>'','Please fill AFilePath');
   Assert(ARelativeDirOnServer<>'','Please fill AdirOnServer');
   Assert(AFileNameOnServer<>'','Please fill AFileNameOnServer');
   Assert(AidUsersString<>'','Please fill AidUsersString');
   Assert( Assigned(VisualFrame_TPS_ChunkUploader_UnitVar), ' Please Assign VisualFrame_TPS_ChunkUploader_UnitVar ' );


PostData := TIdMultiPartFormDataStream.Create;


 try

       try

          EncodeParam(ARelativeDirOnServer);
          EncodeParam(AFileNameOnServer);


          idHTTP.Request.Referer := FHTTPServerToRequest+'/sendOneWholeFile';
          idHTTP.Request.ContentType := 'multipart/form-data';

                    PostData.AddFormField('login', 'SomeLogin');
                    PostData.AddFormField('password', 'SomePassword');
                    PostData.AddFormField('dirOnServer', ARelativeDirOnServer);
                    PostData.AddFormField('fileNameOnServer',AFileNameOnServer);
                    PostData.AddFormField('idUsersString',AidUsersString);

                    PostData.AddFile('attach', AFilePath, 'application/x-rar-compressed');

          MyServerResponse:=idHTTP.Post(FHTTPServerToRequest+'/sendOneWholeFile', PostData);
          if MyServerResponse='ok' then Result:=true;

       except


             on E: EIdException do
               ShowMessage( 'Communication Exception at SendOneWholeFile: ' + E.Message);


             on E: Exception do
                 ShowMessage( 'VCL Exception at SendOneWholeFile: ' + E.Message);

       end;

 finally
 FreeAndNil(PostData);
 end;


end;

end.
