Skip to content

Commit

Permalink
1.0.1 - rewrite progress bar+stop button without using storage and pr…
Browse files Browse the repository at this point in the history
…oject variable
  • Loading branch information
ThomasMaul committed Apr 27, 2022
1 parent 05e0a8d commit 0afdf83
Show file tree
Hide file tree
Showing 15 changed files with 485 additions and 503 deletions.
13 changes: 13 additions & 0 deletions Documentation/Classes/FileTransfer_Dropbox.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ End if
|[.executeCommand](#executecommand)<p>&nbsp;&nbsp;&nbsp;&nbsp;Allows to pass any valid Dropbox command and directly execute it.|
|[.version](#version)<p>&nbsp;&nbsp;&nbsp;&nbsp;returns in result.data version information from Dropbox Command Line Interface Tool|
|[.setPath](#setpath)<p>&nbsp;&nbsp;&nbsp;&nbsp;Allows to use another dbxcli installation.|
|[.enableStopButton](#enablestopbutton)<p>&nbsp;&nbsp;&nbsp;&nbsp;Display stop button in progress dialog.|
|[.setAsyncMode](#setasyncmode)<p>&nbsp;&nbsp;&nbsp;&nbsp;By default all commands are executed synchronously, meaning the command do not return till execution is completed or a timeout occurred. This allows all command to return the result or execution information..|
|[.setTimeout](#settimeout)<p>&nbsp;&nbsp;&nbsp;&nbsp;sets a maximum worker execution time, stopping everything.|
|[.stop](#stop)<p>&nbsp;&nbsp;&nbsp;&nbsp;Terminates the execution of a running operation, such as upload or download.|
Expand Down Expand Up @@ -239,6 +240,18 @@ sets a maximum execution time for the worker. By default all operations are stop
The timeout is not considered when asynchronous mode is enabled.


## enableStopButton

### .enableStopButton(enable:Shared Object)
|Parameter|Type||Description|
|---------|--- |:---:|------|
|enable|Object|->|Shared Object with Attribut Stop|

#### Description
Only useable if included or similar ProgressCallback method is used.
If passed it enables the stop button in progress bar, allowing the end user to abort the operation. If Stop button is clicked, attribut of shared object enable.stop is set to true


## setAsyncMode

### .setAsyncMode(async:Boolean)
Expand Down
13 changes: 13 additions & 0 deletions Documentation/Classes/FileTransfer_GDrive.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ End if
|[.executeCommand](#executecommand)<p>&nbsp;&nbsp;&nbsp;&nbsp;Allows to pass any valid GDrive command and directly execute it.|
|[.version](#version)<p>&nbsp;&nbsp;&nbsp;&nbsp;returns in result.data version information from Gdrive Command Line Interface Tool|
|[.setPath](#setpath)<p>&nbsp;&nbsp;&nbsp;&nbsp;Allows to specify the installation path.|
|[.enableStopButton](#enablestopbutton)<p>&nbsp;&nbsp;&nbsp;&nbsp;Display stop button in progress dialog.|
|[.setAsyncMode](#setasyncmode)<p>&nbsp;&nbsp;&nbsp;&nbsp;By default all commands are executed synchronously, meaning the command do not return till execution is completed or a timeout occurred. This allows all command to return the result or execution information..|
|[.setTimeout](#settimeout)<p>&nbsp;&nbsp;&nbsp;&nbsp;sets a maximum worker execution time, stopping everything.|
|[.stop](#stop)<p>&nbsp;&nbsp;&nbsp;&nbsp;Terminates the execution of a running operation, such as upload or download.|
Expand Down Expand Up @@ -350,6 +351,18 @@ Precompiled versions for Mac and Windows can be downloaded from:
[gdrive](https://github.com/prasmussen/gdrive/releases)


## enableStopButton

### .enableStopButton(enable:Shared Object)
|Parameter|Type||Description|
|---------|--- |:---:|------|
|enable|Object|->|Shared Object with Attribut Stop|

#### Description
Only useable if included or similar ProgressCallback method is used.
If passed it enables the stop button in progress bar, allowing the end user to abort the operation. If Stop button is clicked, attribut of shared object enable.stop is set to true


## setAsyncMode

### .setAsyncMode(async:Boolean)
Expand Down
85 changes: 54 additions & 31 deletions Documentation/Classes/FileTransfer_curl.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ For more examples see the method "test_curl".
|[.setCurlPrefix](#setcurlprefix)<p>&nbsp;&nbsp;&nbsp;&nbsp;Allows to use any additional cURL options.|
|[.setPath](#setpath)<p>&nbsp;&nbsp;&nbsp;&nbsp;Allows to use another cURL installation.|
|[.enableProgressData](#enableprogressdata)<p>&nbsp;&nbsp;&nbsp;&nbsp;If enabled, result.data will include progress information text.|
|[.enableStopButton](#enablestopbutton)<p>&nbsp;&nbsp;&nbsp;&nbsp;Display stop button in progress dialog.|
|[.setAsyncMode](#setasyncmode)<p>&nbsp;&nbsp;&nbsp;&nbsp;By default all commands are executed synchronously, meaning the command do not return till execution is completed or a timeout occurred. This allows all command to return the result or execution information..|
|[.setTimeout](#settimeout)<p>&nbsp;&nbsp;&nbsp;&nbsp;sets a maximum worker execution time, stopping everything.|
|[.stop](#stop)<p>&nbsp;&nbsp;&nbsp;&nbsp;Terminates the execution of a running operation, such as upload or download.|
Expand Down Expand Up @@ -400,6 +401,17 @@ If enabled, result.data will include progress information text, allowing to get
Depending of total transfer time, the text will include additional lines with progress info.
Automatically enabled if useCallback is enabled.

## enableStopButton

### .enableStopButton(enable:Shared Object)
|Parameter|Type||Description|
|---------|--- |:---:|------|
|enable|Object|->|Shared Object with Attribut Stop|

#### Description
Only useable if included or similar ProgressCallback method is used.
If passed it enables the stop button in progress bar, allowing the end user to abort the operation. If Stop button is clicked, attribut of shared object enable.stop is set to true

## setAsyncMode

### .setAsyncMode(async:Boolean)
Expand Down Expand Up @@ -470,7 +482,7 @@ The command returns after given wait time or before if execution is finished.
|Parameter|Type||Description|
|---------|--- |:---:|------|
|callback|4D.Function|->|4d function to call during progress|
|ID|Text|->|unique text to pass to callback method to identify job|
|ID|Text|->|text to display in progress title, such as download file name|

#### Description
Allows to show a progress bar during long running operations or to get informed when command execution is complete.
Expand All @@ -481,52 +493,63 @@ The callback method is called whenever a new progress message is available from

```4D
$ftp.useCallback(Formula(ProgressCallback); "Download 4D.dmg")
$ftp.setAsyncMode(True)
$result:=$ftp.download($source; $target)
Repeat
$ftp.wait(1) // needed while our process is running
// wait is not needed if a form would be open or if a worker would handle the job
$status:=$ftp.status()
Until (Bool($status.terminated))
If ($checkstop.stop=True) // user clicked stop button
...
End if
```

Method ProgressCallback

```4D
#DECLARE($ID : Text; $message : Text; $value : Integer)
#DECLARE($ID : Text; $message : Text; $value : Integer; $sharedForProgressBar : Object)
// called from cs.FileTransfer if callback is set via .useCallback()
// $ID is set through code - $message comes from curl
// shared object to pass progress ID back/forth and to share stop button result
var ProgressBarID : Integer
$ProgressBarID:=$sharedForProgressBar.ID
If (ProgressBarID=0)
ProgressBarID:=Progress New
Progress SET MESSAGE(ProgressBarID; $ID)
If (($ProgressBarID=0) && ($value#100))
$ProgressBarID:=Progress New
Use ($sharedForProgressBar)
$sharedForProgressBar.ID:=$ProgressBarID
End use
Progress SET TITLE($ProgressBarID; $ID)
// check if we want stop, if yes, add stop button
If ($sharedForProgressBar.EnableButton#Null)
Progress SET BUTTON ENABLED($ProgressBarID; True)
End if
End if
If ($value=100)
Progress QUIT(ProgressBarID)
ProgressBarID:=0
Else
Progress SET PROGRESS(ProgressBarID; $value/100)
If ($ProgressBarID#0)
If (Progress Stopped($ProgressBarID)) // only if stop button is enabled
Use ($sharedForProgressBar)
$sharedForProgressBar.Stop:=True
Use ($sharedForProgressBar.EnableButton)
$sharedForProgressBar.EnableButton.stop:=True
End use
End use
End if
Case of
: ($value=100)
Progress QUIT($ProgressBarID)
Use ($sharedForProgressBar)
$sharedForProgressBar.ID:=0
End use
: ($value<0)
$message2:=Replace string($message; " "; "") // ignore totally empty messages, happens with gdrive
If ($message2#"")
Progress SET MESSAGE($ProgressBarID; $message)
End if
Else
Progress SET PROGRESS($ProgressBarID; $value/100)
End case
End if
```
To support the stop button in the progress bar, Storage needs to be used to share progress bar and worker IDs. See example in test_curl - download.
```4D
// enable stop button in progress bar
Use (Storage.FileTransfer_Progress)
Storage.FileTransfer_Progress[$progressid]:=New shared object()
End use
$ftp.useCallback(Formula(ProgressCallback); $progressid)
```

After execution of download/upload/etc, check:
```4D
If (Bool(Storage.FileTransfer_Progress[$progressid].Stop)) // check stop button if it was set, remove from storage
// user canceled!!
```

Don't forget to remove the object from storage when done.
See test_curl - download for a full example
13 changes: 1 addition & 12 deletions Documentation/Readme_curl.MD
Original file line number Diff line number Diff line change
Expand Up @@ -92,18 +92,7 @@ While FTPS is using standard TLS certificates (similar to HTTPS), SFTP is using
[From Wikipedia](https://en.wikipedia.org/wiki/SSH_File_Transfer_Protocol)
This protocol assumes that it is run over a secure channel, such as SSH, that the server has already authenticated the client, and that the identity of the client user is available to the protocol.

While you normally do not simply provide credentials (user+password) to login, you need to estabilish upfront a SSH connection to store the ssh key from the SFTP Server in the local keyring. The benefit is that you do not need username+password for login, all goes through keys. But it is possible to use user+password similar as for FTPS, while you need to be aware that in this case you cannot trust that the connection really go to the right server, this is a possible security issue.

Most easiest way to check, exchange and store client and server keys is to open a terminal window (using Terminal on Mac/Terminal or Console on Windows) and enter:
```
ssh username@sftp.servername.com
```

This will request the password and display the ssh hash, asking if you accept to store it in your .ssh/authorized_keys file.
In a similar way you could exchange keys upfront to avoid using passwords at all to enhance security.
Google "ssh key authentication" for more help and examples.

As soon the authentication was done once via ssh (or the key is stored in your authorized_keys file by another way), the class can be used without providing credentials, just the URL is enough.
Using SFTP you might either use username+password as you would do with FTPS, or exchange keys. To use SFTP via keys, establish upfront a SSH connection using Terminal, this setup will be reused from cURL.

# Class Documentation

Expand Down
5 changes: 4 additions & 1 deletion Project/Sources/Classes/FileTransfer_Dropbox.4dm
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ Function setTimeout($timeout : Integer)
Function setAsyncMode($async : Boolean)
This:C1470._async:=$async

Function enableStopButton($enable : Object)
This:C1470._enableStopButton:=$enable

Function stop()
If (This:C1470._worker#Null:C1517)
This:C1470._worker.terminate()
Expand Down Expand Up @@ -155,7 +158,7 @@ Function _parseDirListing($success : Object)

Function _runWorker($para : Text)->$result : Object
If (This:C1470._Callback#Null:C1517)
$workerpara:=cs:C1710.SystemWorkerProperties.new("dropbox"; This:C1470.onData; This:C1470._Callback; This:C1470._CallbackID)
$workerpara:=cs:C1710.SystemWorkerProperties.new("dropbox"; This:C1470.onData; This:C1470._Callback; This:C1470._CallbackID; This:C1470._enableStopButton)
Else
$workerpara:=cs:C1710.SystemWorkerProperties.new("dropbox"; This:C1470.onData)
End if
Expand Down
5 changes: 4 additions & 1 deletion Project/Sources/Classes/FileTransfer_GDrive.4dm
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,9 @@ Function useCallback($callback : 4D:C1709.Function; $ID : Text)
Function setAsyncMode($async : Boolean)
This:C1470._async:=$async

Function enableStopButton($enable : Object)
This:C1470._enableStopButton:=$enable

Function setTimeout($timeout : Integer)
This:C1470._timeout:=$timeout

Expand Down Expand Up @@ -373,7 +376,7 @@ Function _parseDirListing($success : Object)

Function _runWorker($para : Text)->$result : Object
If (This:C1470._Callback#Null:C1517)
$workerpara:=cs:C1710.SystemWorkerProperties.new("gdrive"; This:C1470.onData; This:C1470._Callback; This:C1470._CallbackID)
$workerpara:=cs:C1710.SystemWorkerProperties.new("gdrive"; This:C1470.onData; This:C1470._Callback; This:C1470._CallbackID; This:C1470._enableStopButton)
Else
$workerpara:=cs:C1710.SystemWorkerProperties.new("gdrive"; This:C1470.onData)
End if
Expand Down
36 changes: 18 additions & 18 deletions Project/Sources/Classes/FileTransfer_curl.4dm
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Class constructor($hostname : Text; $username : Text; $password : Text; $protoco
This:C1470._return:=Char:C90(10) //Char(13)+Char(10)
End if
This:C1470._timeout:=0
This:C1470._enableStopButton:=False:C215

//MARK: Settings
Function validate()->$success : Object
Expand Down Expand Up @@ -75,6 +76,9 @@ Function setPath($path : Text)
Function enableProgressData($enable : Boolean)
This:C1470._noProgress:=Not:C34($enable)

Function enableStopButton($enable : Object)
This:C1470._enableStopButton:=$enable

Function useCallback($callback : 4D:C1709.Function; $ID : Text)
ASSERT:C1129(Value type:C1509($callback)=Is object:K8:27; "Callback must be of type function")
ASSERT:C1129(OB Instance of:C1731($callback; 4D:C1709.Function); "Callback must be of type function")
Expand Down Expand Up @@ -303,7 +307,7 @@ Function _buildURL()->$url : Text

Function _runWorker($para : Text)->$result : Object
If (This:C1470._Callback#Null:C1517)
$workerpara:=cs:C1710.SystemWorkerProperties.new("curl"; This:C1470.onData; This:C1470._Callback; This:C1470._CallbackID)
$workerpara:=cs:C1710.SystemWorkerProperties.new("curl"; This:C1470.onData; This:C1470._Callback; This:C1470._CallbackID; This:C1470._enableStopButton)
Else
$workerpara:=cs:C1710.SystemWorkerProperties.new("curl"; This:C1470.onData)
End if
Expand Down Expand Up @@ -338,7 +342,6 @@ Function _runWorker($para : Text)->$result : Object
$command:=$path+" "+$para
$old:=Method called on error:C704
ON ERR CALL:C155(Formula:C1597(ErrorHandler).source)
$workerpara.variables:=New object:C1471("userCancel"; "false")
This:C1470._worker:=4D:C1709.SystemWorker.new($command; $workerpara)
$worker:=This:C1470._worker

Expand All @@ -348,25 +351,22 @@ Function _runWorker($para : Text)->$result : Object
Else
$waittimeout:=(This:C1470._timeout=0) ? 60 : This:C1470._timeout
$worker.wait($waittimeout)
If (Bool:C1537($worker.userCancel))
$result:=New object:C1471("responseError"; "Cancel by user"; "success"; False:C215)
Else
If (($worker.responseError#Null:C1517) && ($worker.responseError#""))
$result:=New object:C1471("responseError"; $worker.responseError; "success"; False:C215)
$pos:=Position:C15("curl: "; $worker.responseError; *)
If ($pos>0)
$result.error:=Replace string:C233(Substring:C12($worker.responseError; $pos+6); Char:C90(10); "")

If (($worker.responseError#Null:C1517) && ($worker.responseError#""))
$result:=New object:C1471("responseError"; $worker.responseError; "success"; False:C215)
$pos:=Position:C15("curl: "; $worker.responseError; *)
If ($pos>0)
$result.error:=Replace string:C233(Substring:C12($worker.responseError; $pos+6); Char:C90(10); "")
Else
// seems not to be an error, curl set's process bar in error and no result in response.
If ($worker.response#"")
$result:=New object:C1471("data"; $worker.response; "success"; True:C214)
Else
// seems not to be an error, curl set's process bar in error and no result in response.
If ($worker.response#"")
$result:=New object:C1471("data"; $worker.response; "success"; True:C214)
Else
$result:=New object:C1471("data"; $worker.responseError; "success"; True:C214)
End if
$result:=New object:C1471("data"; $worker.responseError; "success"; True:C214)
End if
Else
$result:=New object:C1471("data"; $worker.response; "success"; True:C214)
End if
Else
$result:=New object:C1471("data"; $worker.response; "success"; True:C214)
End if
End if
Else
Expand Down
Loading

0 comments on commit 0afdf83

Please sign in to comment.