Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: [FMX] Android idFTP Multiupload service


This question is answered.


Permlink Replies: 4 - Last Post: Mar 10, 2018 8:13 AM Last Post By: Daniel Tengler
Daniel Tengler

Posts: 5
Registered: 2/22/18
[FMX] Android idFTP Multiupload service  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 7, 2018 3:10 AM
Hello everyone.
How can I create a service that will check the contents of a folder and finds the file by extension so it sends it to the FTP server.

I do not know if you need to use Indy idFTP or else you can do it.

The service should run only when the application is running.

I found a Demo demo for a service downloader, but uploading does not know how to do as a thread.

My Code error: application stoped !!

Thanks
// service
unit fDownloader;
 
interface
 
uses
  System.SysUtils,
  System.Classes,
  System.Android.Service,
  AndroidApi.JNI.GraphicsContentViewText,
  Androidapi.JNI.Os,
  System.SyncObjs,
  System.Generics.Collections,
  Network, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
  IdExplicitTLSClientServerBase, IdFTP;
 
type
  TThreadUploader = class;
 
  TDM = class(TAndroidService)
    function AndroidServiceStartCommand(const Sender: TObject;
      const Intent: JIntent; Flags, StartId: Integer): Integer;
    procedure AndroidServiceCreate(Sender: TObject);
    procedure AndroidServiceDestroy(Sender: TObject);
  private
    { Private declarations }
    FThreads: TObjectList<TThread>;
    FThreadsUploader: TList<TThreadUploader>;
 
    procedure UploadFoto(AEvent: TEvent);
  public
    { Public declarations }
    procedure MultiUpload;
  end;
 
  TThreadUploader = class(TThread)
  private
    FEvent: TEvent;
 
  public
    procedure Execute; override;
 
    property Event: TEvent read FEvent write FEvent;
  end;
 
var
  DM: TDM;
  FDir: string;
  fsFilter,fsName,s: string;
  DirImage: string;
  DirSettings: string;
  FTP: TidFTP;
  slSettings: TStringList;
 
implementation
 
{%CLASSGROUP 'FMX.Controls.TControl'}
 
{$R *.dfm}
 
uses
  Androidapi.JNI.App, Math, System.IOUtils;
 
procedure TDM.AndroidServiceCreate(Sender: TObject);
begin
  FThreads := TObjectList<TThread>.Create;
  FThreadsUploader := TList<TThreadUploader>.Create;
end;
 
procedure TDM.AndroidServiceDestroy(Sender: TObject);
begin
  FThreads.Free;
  FThreadsUploader.Free;
end;
 
function TDM.AndroidServiceStartCommand(const Sender: TObject;
  const Intent: JIntent; Flags, StartId: Integer): Integer;
var
  lThread: TThread;
begin
  lThread := TThread.CreateAnonymousThread(
    procedure
    var
      LEvent: TEvent;
    begin
      LEvent := TEvent.Create();
 
      UploadFoto(LEvent);
 
      LEvent.WaitFor(INFINITE);
 
      JavaService.stopSelf(StartId);
    end
    );
 
    LThread.FreeOnTerminate := True;
    FThreads.Add(LThread);
    LThread.Start();
 
  Result := TJService.JavaClass.START_STICKY;
end;
 
procedure TDM.UploadFoto(AEvent: TEvent);
var
  LThread: TThreadUploader;
begin
  LThread := TThreadUploader.Create(True);
  LThread.FreeOnTerminate := True;
  LThread.Event := AEvent;
  FThreadsUploader.Add(LThread);
  LThread.Start();
end;
 
procedure TDM.MultiUpload;
var
  isOK: boolean;
begin
  if IsConnected = True then
  begin
  try
    fsFilter := '*.jpeg';
 
    for fsName in TDirectory.GetFiles(DirImage, fsFilter) do
    begin
      if (fsName <> '') and (FileExists(DirSettings + System.SysUtils.PathDelim + 'settings.ini')) then
      begin
 
 
        slSettings := TStringList.Create;
 
        slSettings.LoadFromFile(DirSettings + System.SysUtils.PathDelim + 'settings.ini');
 
        FTP := TidFTP.Create(nil);
 
        FTP.Host := slSettings[8];
 
        FTP.Port := StrToInt(slSettings[9]);
 
        FTP.Username := slSettings[10];
 
        FTP.Password := slSettings[11];
 
        FDir := slSettings[12];
 
        FTP.Connect;
        FTP.ChangeDir(FDir);
        try
          FTP.Delete(TPath.GetFileName(fsName));
        except
          isOK := False;
        end;
 
        FTP.Put(fsName, TPath.GetFileName(fsName));
        DeleteFile(fsName);
 
        FTP.Site('CHMOD 777 '+ TPath.GetFileName(fsName));
        FTP.Disconnect;
 
        FTP.Free;
 
 
        slSettings.Free;
      end;
    end;
  except
    on E: exception do
    begin
      s := E.Message;
    end;
  end;
  end;
end;
 
procedure TThreadUploader.Execute;
begin
 
  while not Terminated do
  begin
    dm.MultiUpload;
 
    Sleep(10000);
 
    FEvent.SetEvent;
 
    Terminate;
  end;
end;
 
end. 
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: [FMX] Android idFTP Multiupload service
Helpful
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 7, 2018 9:45 AM   in response to: Daniel Tengler in response to: Daniel Tengler
Daniel Tengler wrote:

I do not know if you need to use Indy idFTP or else you can do it.

Use whatever you want. TIdFTP is just one of thousands of possible FTP
implementations. OR write your own. FTP is not a complex protocol to
implement manually.

The service should run only when the application is running.

Then why does it need to be a service at all, and not just a worker
thread running in the background?

I found a Demo demo for a service downloader, but uploading does not
know how to do as a thread.

Why not? What is the ACTUAL problem you are having with it? Upload or
download, it doesn't matter, you can run them both in a thread. It is
just a matter of coding it. You have already written code to call
TIdFTP.Put() in a thread. So what is the real problem?

Also, why is AndroidServiceStartCommand() creating a thread just to
create another thread and wait on it? That is a waste of resources.
You may as well just have AndroidServiceStartCommand() call
UploadFoto() directly and get rid of the anonymous thread to call
UploadFoto(), and get rid of the TEvent that it waits on.

And why is TDM.MultiUpload() reloading the same INI file multiple
times, creating a separate TIdFTP connection for each individual file
that is being uploaded? That is a major waste of resources and
bandwidth. You should load the INI file one time, connect to the FTP
server one time, then loop through the files uploading them, and then
disconnect.

--
Remy Lebeau (TeamB)
Daniel Tengler

Posts: 5
Registered: 2/22/18
Re: [FMX] Android idFTP Multiupload service  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 7, 2018 11:01 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Use whatever you want. TIdFTP is just one of thousands of possible FTP
implementations.
I like to advise on a component that does not hold.

You should load the INI file one time, connect to the FTP
server one time, then loop through the files uploading them, and then
disconnect.

The INI file should be loaded so there is no error and dropping of the application in case of changes to the FTP server access.

TWorkerThread ?
I will have to learn, I can not.
I'm a novice programmer.

Thanks

Edited by: Daniel Tengler on Mar 7, 2018 11:10 AM
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: [FMX] Android idFTP Multiupload service [Edit]
Correct
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 7, 2018 12:13 PM   in response to: Daniel Tengler in response to: Daniel Tengler
Daniel Tengler wrote:

I like to advise on a component that does not hold.

I don't understand what you are saying.

The INI file should be loaded so there is no error and dropping of
the application in case of changes to the FTP server access.

That does not change what I said earlier. You should NOT be reloading
the same INI file on each individual upload, and you definately should
not be connecting and disconnecting from the FTP server on each
individual upload.

Try something more like this instead (untested, but should give you
ideas):

// service
unit fDownloader;
 
interface
 
uses
  System.SysUtils,
  System.Classes,
  System.Android.Service,
  AndroidApi.JNI.GraphicsContentViewText,
  Androidapi.JNI.Os,
  System.Generics.Collections,
  Network;
 
type
  TThreadUploader = class(TThread)
  private
    FStartId: Integer;
  protected
    procedure Execute; override;
    procedure DoTerminate; override;
  public
    constructor Create(AStartId: Integer); reintroduce;
    destructor Destroy; override;
  end;
 
  TDM = class(TAndroidService)
    function AndroidServiceStartCommand(const Sender: TObject;
      const Intent: JIntent; Flags, StartId: Integer): Integer;
    procedure AndroidServiceCreate(Sender: TObject);
    procedure AndroidServiceDestroy(Sender: TObject);
  private
    { Private declarations }
    FThreads: TObjectList<TThreadUploader>; 
  public
    { Public declarations }
    procedure MultiUpload(ATerminateFunc: TFunc<Boolean>);
  end;
 
var
  DM: TDM;
  DirImage: string;
  DirSettings: string;
 
implementation
 
{%CLASSGROUP 'FMX.Controls.TControl'}
 
{$R *.dfm}
 
uses
  Androidapi.JNI.App, Math, System.IOUtils,
  IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
  IdExplicitTLSClientServerBase, IdFTP;
 
procedure TDM.AndroidServiceCreate(Sender: TObject);
begin
  FThreads := TObjectList<TThreadUploader>.Create;
end;
 
procedure TDM.AndroidServiceDestroy(Sender: TObject);
var
  lThread: TThreadUploader;
begin
  TMonitor.Enter(FThreads);
  try
    for lThread in FThreads do
      lThread.Terminate;    
  finally
    TMonitor.Exit(FThreads);
  end;
 
  repeat
    TMonitor.Enter(FThreads);
    try
      if FThreads.Count = 0 then
        Break;
    finally
      TMonitor.Exit(FThreads);
    end;
    Sleep(100);
  until False;
 
  FThreads.Free;
end;
 
function TDM.AndroidServiceStartCommand(const Sender: TObject;
  const Intent: JIntent; Flags, StartId: Integer): Integer;
begin
  TThreadUploader.Create(StartId);
  Result := TJService.JavaClass.START_STICKY;
end;
 
procedure TDM.MultiUpload(ATerminateFunc: TFunc<Boolean>);
var
  Dir: string;
  fsName, ftpName, s: string;
  FTP: TidFTP;
  slSettings: TStringList;
  files: TStringDynArray;
  isOK: boolean;
begin
  if IsConnected then
  begin
    try
      files := TDirectory.GetFiles(DirImage, '*.jpeg');
      if Length(files) > 0 then
      begin
        FTP := TIdFTP.Create(nil);
        try
          slSettings := TStringList.Create;
          try
            slSettings.LoadFromFile(TPath.Combine(DirSettings,
'settings.ini'));
 
            FTP.Host := slSettings[8];
            FTP.Port := StrToInt(slSettings[9]);
            FTP.Username := slSettings[10];
            FTP.Password := slSettings[11];
 
            Dir := slSettings[12];
          finally
            slSettings.Free;
          end;
 
          FTP.Connect;
          try
            FTP.ChangeDir(Dir);
 
            for fsName in files do
            begin
              if ATerminateFunc() then
                Break;
 
              ftpName := TPath.GetFileName(fsName);
 
              try
                FTP.Delete(ftpName);
              except
                isOK := False;
              end;
 
              try
                FTP.Put(fsName, ftpName);
              except
                isOk := False;
                Continue;
              end;
 
              DeleteFile(fsName);
 
              try
                FTP.Site('CHMOD 777 ' + ftpName);
              except
                //isOk := False;
              end;
            end;
          finally
            FTP.Disconnect;
          end;
        finally
          FTP.Free;
        end;
      end;
    except
      on E: Exception do
      begin
        s := E.Message;
      end;
    end;
  end;
end;
 
constructor TThreadUploader.Create(AStartId: Integer);
begin
  inherited Create(False);
  FreeOnTerminate := True;
  FStartId := AStartId;
  TMonitor.Enter(DM.FThreads);
  try
    DM.FThreads.Add(Self);
  finally
    TMonitor.Exit(DM.FThreads);
  end;
end;
 
destructor TThreadUploader.Destroy;
begin
  TMonitor.Enter(DM.FThreads);
  try
    DM.FThreads.Remove(Self);
  finally
    TMonitor.Exit(DM.FThreads);
  end;
  JavaService.stopSelf(FStartId);
  inherited;
end;
 
procedure TThreadUploader.Execute;
begin
  DM.MultiUpload(
    function: Boolean;
    begin
      Result := Self.Terminated;
    end
  );
end;
 
end.


--
Remy Lebeau (TeamB)
Daniel Tengler

Posts: 5
Registered: 2/22/18
Re: [FMX] Android idFTP Multiupload service [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 10, 2018 8:13 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Thank you for your help => Remy Lebeau (TeamB)
I did it as a worker in the application.

procedure TFormMain.tMultiUploadTimer(Sender: TObject);
begin
  if (isConnected = True) and (StrToInt(lbCount.Text) > 0) and (mFTP.Connected = False) then  // lbCount = count images in local directory function GetImagesCountInDir;
  begin
    MultiUpload;
  end;
end;
 
 
procedure TFormMain.MultiUpload;
begin
 
  if IsConnected = True then
  begin
  TThread.CreateAnonymousThread(
        procedure()
        begin
 
          fsFiltr := '*.jpg';
          slSettings := TStringList.Create;
          slSettings .LoadFromFile(dirSettings + System.SysUtils.PathDelim + 'settings.ini');
 
 
          try
            mFTP.Passive := True;
 
            mFTP.Host := slSettings[8];
 
            mFTP.Port := StrToInt(slSettings[9]);
 
            mFTP.Username := slSettings[10];
 
            mFTP.Password := slSettings[11];
 
            FTPDir := slSettings[12];
 
            for fsName in TDirectory.GetFiles(DirImages, fsFiltr) do
            begin
 
            mFTP.Connect;
 
              try
                mFTP.ChangeDir(FTPDir);
                  try
                    mFTP.Rename(TPath.GetFileName(fsName),'del_'+Formatdatetime('dd-mm-yyyy_hh-nn-ss',Now)+'_'+TPath.GetFileName(fsName));  // rename if exists in FTP server
                    mFTP.Delete(TPath.GetFileName(fsName)); // delete if exists in FTP server
                    mFTP.Put(fsName);  // new file put to FTP server
                  except
                    mFTP.Put(fsName);
                  end;
                  DeleteFile(fsName);
 
                  mFTP.Site('CHMOD 777 '+ TPath.GetFileName(fsName));
 
                finally
                  mFTP.Disconnect;
                  slSettings.Free;
                  GetImagesCountInDir;
              end;
            end;
          except
          on E: exception do
          begin
            GetImagesCountInDir;
          end;
        end;
   end).Start;
 
 
    end else
    begin
      GetImagesCountInDir;
    end;
 
end;
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02