Android Question does "Wait For" really waits for event to be exit ?

AbdurRahman

Member
Hi guys 👋,

I'm trying to crawl all files under "sdcard/emulated/0" and upload specific files with specific extension.
I have been successful in all events except that from log output, I noticed ftp upload files in ASYNC. Due to uploading several files at once, app get a ddos.
Whereas, I expected that it would upload files one by one at a time.

Here's my code:

B4X:
Sub Start(ParentDir As String)
    Dim files As List = File.ListFiles(ParentDir)
    For i = 0 To files.Size - 1
        If File.IsDirectory(ParentDir,files.Get(i)) Then
            Start(folder)              
        Else
            Dim filepath As String = ParentDir & "/" & files.Get(i)
            If filepath.Contains(".") Then
                Dim ext As String = filepath.SubString2(filepath.LastIndexOf("."),filepath.Length)
                If IsValidExtension(ext) Then                        
                    Dim dir As String = GetFoldername(filepath)
                    Dim filename As String = GetFilename(filepath)
                    Log("Uploading:" & filepath)
                    FTP.SendCommand("MKD",  dir)
                    Dim complete As Object = FTP.UploadFile(dir, filename, False, filepath)
                    Wait For (complete) ftp_UploadCompleted (ServerPath As String, Success As Boolean)
                    If Success Then
                        Log("upload success: " & filepath)
                    Else
                        Log("upload error: " & LastException & CRLF & "FilePath:" & filepath & CRLF & "ServerPath:" & ServerPath)
                    End If
                End If
            End If
        End If
    Next
End Sub

Helper functions for code for better understanding:
B4X:
Sub IsValidExtension(extension As String) As Boolean
    Dim extensions() As String = Array As String("JPG","JPEG","PNG","GIF","TIFF","PDF","OPUS","MP4","DOC","DOCX")
    For i = 0 To extensions.Length-1
        If extension.Trim.ToUpperCase="." & extensions(i) Then Return True
    Next
    Return False
End Sub

Sub GetFoldername(path As String) As String
    Dim spilted() As String = Regex.Split("/", path)
    Dim dir As String
    For i = 0 To spilted.Length-1
        If Not (i = spilted.Length-1) Then
            If i = 0 Then
                dir = spilted(i)
            Else
                dir = dir & "/" & spilted(i)
            End If
        End If
    Next
    Return dir
End Sub

Sub GetFilename(PATH As String) As String
    Dim spilted() As String = Regex.Split("/", PATH)
    Return spilted(spilted.Length-1)
End Sub

From output, it clearly shows wait for doesn't wait for ftp to be completed:

B4X:
** Activity (main) Pause, UserClosed = true **
** Service (uploader) Destroy **
** Service (starter) Destroy (ignored)**
*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
*** Service (uploader) Create ***
** Service (uploader) Start **
Uploading:/storage/emulated/0/Pictures/background.jpg
upload success: /storage/emulated/0/Pictures/background.jpg
Uploading:/storage/emulated/0/Pictures/res/mipmap/ic_launcher.png
Uploading:/storage/emulated/0/Pictures/resource_monitor.PNG
upload success: /storage/emulated/0/Pictures/res/mipmap/ic_launcher.png
upload success: /storage/emulated/0/Pictures/resource_monitor.PNG
Uploading:/storage/emulated/0/Pictures/tick.jpg
upload success: /storage/emulated/0/Pictures/tick.jpg
Uploading:/storage/emulated/0/Pictures/tick.png
upload success: /storage/emulated/0/Pictures/tick.png
Uploading:/storage/emulated/0/Pictures/visual-basic.png
upload success: /storage/emulated/0/Pictures/visual-basic.png

Now, how would I make it to upload files one by one at a time ?
Regards and Thanks. ❤
 

Peter Simpson

Expert
Licensed User
Longtime User
Sorry I've personally not use FTP before so I don't know what sub events are auto-generated by the IDE. But just by looking at the code above, I can see that the Wait For that you're using not written correctly.

Read this post by Erel
 
Last edited:
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
I believe Wait For actually means "return to caller and process remaining code (including system events) while waiting for this one"
The part that gets me every time is if a resumable sub is called from another sub and the call is followed by additional code, this additional code will execute even though the Wait For has not completed (maybe not described correctly but that's the way it appears to me). So my practice has been to avoid using Wait For at the bottom of a complex calling tree. The good news is that Wait For actually makes it relatively easy to avoid that.
 
Upvote 0

agraham

Expert
Licensed User
Longtime User
The part that gets me every time is if a resumable sub is called from another sub and the call is followed by additional code, this additional code will execute even though the Wait For has not completed
You can always Wait For the called resumable sub to complete if you find it easier for your program flow.
 
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
You can always Wait For the called resumable sub to complete if you find it easier for your program flow.
How do I do that?
I mean there are a number of ways to do that, but I am not aware of anything that I would call elegant...
 
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
Thank you, I had forgotten about that.
My limited familiarity with resumable subs (due to early mistakes leading to disappointments) has let me not fully embrace the concept (I still use my old ways on occasion) so I do not gain the familiarity I would need to be proficient with it... A typical catch-22 :)
 
Upvote 0

Peter Simpson

Expert
Licensed User
Longtime User
Hello @AbdurRahman
After realising that I don't really know anything about using FTP in B4x to upload files, I decided to look more into it. I quickly made this example for you to look at (and for me to learn from). It basically does what you're looking for , except it DOES NOT loop through every folder looking for files, only my download folder as I have lot of files in there that I could test with.

This code does appear to work perfect with 'Wait For', getting the code to loop through sub folders in DirRootExternal is not difficult to implement.

You asked "does "Wait For" really waits for event to be exit ?", the answer is yes.

B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Private XUI As XUI
    Private FTP As FTP
    Private RP As RuntimePermissions
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("Layout")

    RP.CheckAndRequest(RP.PERMISSION_WRITE_EXTERNAL_STORAGE)
    Wait For Activity_PermissionResult (Permission As String, Result As Boolean)
    If Result Then
        FTPUpload
    Else
        Log("Oops, no permission granted!!!")
    End If
End Sub

Sub Activity_Resume
End Sub

Sub Activity_Pause (UserClosed As Boolean)
End Sub

Sub FTPUpload
    FTP.Initialize("ftp", "192.168.0.206", 21, "Admin", "0123456789") 'FTP login details

    Dim Extensions() As String = Array As String("JPG", "JPEG", "PNG", "GIF", "TIFF", "PDF", "OPUS", "MP4", "DOC", "DOCX")
    Dim LstFiles As List = File.ListFiles($"${File.DirRootExternal}/Download"$)

    For Each f As String In LstFiles
        Log(f)
        For i = 0 To Extensions.Length - 1
            If f.ToUpperCase.Contains($".${Extensions(i)}"$) Then
                Dim sf As Object = FTP.UploadFile($"${File.DirRootExternal}/Download"$, f, False, $"/${f}"$)

                Wait For (sf) ftp_UploadCompleted (ServerPath As String, Success As Boolean)
                If Success Then
                    Log("file was uploaded successfully")
                Else
                    Log(LastException)
                End If
            End If
        Next
    Next
End Sub


Enjoy...
 

Attachments

  • FTP.zip
    360.2 KB · Views: 124
Upvote 0

AbdurRahman

Member
Oh yeah !
While using your code, I learned that wait for works fine as its name.
From situation, I learned that whole b4a works in parallel multi threading/async.

The Sub Start() was working in async.
I'm NOT sure whether its normal.
Because I never seen bydefault async functions in any framework or programming.

I should have write code like:
B4X:
Sub Activity_Create(FirstTime As Boolean)
    Wait For (Start(xxx)) Complete()
End Sub

Sub Start(ParentDir As String) As ResumableSub
...
    Wait For (Start(xxx)) Complete()
End Sub

instead of:
B4X:
Sub Activity_Create(FirstTime As Boolean)
    Start(xxx)
End Sub

Sub Start(ParentDir As String)
...
   Start(xxx)
End Sub

Hi Peter ! Thanks so much.
Because of you, I catch my mistake.
Now it works fine one by one.

One thing you can improve is:
use f.ToUpperCase.EndsWith(...) instead of f.ToUpperCase.Contains(...)

Cheers !!! ❤
 
Upvote 0

Peter Simpson

Expert
Licensed User
Longtime User
@AbdurRahman there's no need to offer me improvement tips, I thought that I had already used EndsWith. EndsWith is right under Contains in the methods list, I somehow managed to only tap the down arrow three times instead of four times before hitting Enter'.

Anyway, I'm pleased that you saw the error of your ways and that you've got your code working as planned.

1620810186069.png
 
Upvote 0

AbdurRahman

Member
Yeah typos, mis-tab are common mistakes between thousands of chars. Please accept apologies.
At end, I love those who makes me improve.

I'm really happy to have you and other simple and nice developers here. 👋
 
Upvote 0

netsistemas

Active Member
Licensed User
Longtime User
Be very careful with asynchronous functions, there may be other processes that kill your service, and what is after the wait for is never processed.
Those of us of an age, we have the habit of thinking in synchronous code (spaghetti), and it is difficult for us to think about the multiple events that can jump around. Sometimes I think that computing has some magic, but no, I am the one who does not understand certain things, or I do not take them into account.
 
Upvote 0

AbdurRahman

Member
Hi sir,
Thanks for the tip.

I guess there would be timeout if "Sub" under "wait for" exceeded xxx seconds.
Actually, asynchronous causes flood.
Suppose you have 100 files, and after what if these get uploaded at once ?
So I use them to make their job one by one at a time.
 
Upvote 0
Top