Easier multi transfer for our Xojo CURL Plugin

For next plugin version we simplify the use of CURLSMultiMBS class. You can use it as before or skip making your own instance and just call the new sharedInstance method. This will create an instance if needed and returns you one. If you create an instance yourself, sharedInstance will return that one.

For CURLSMultiMBS to work, you need a timer which calls Perform regularly. We add an AutoPerform property to enable automatic mode, where the plugin runs a timer to call Perform regularly. The AutoPerform will be true on the automatic created instance from sharedInstance method.

Next the AddCURL function gets a new handler parameter for a delegate of type CURLSTransferFinishedMBS. This allows you to add a curl object and provide a delegate address to call when the transfer is finished. Since the CURL object is retained by the multi handle, we don’t need to keep a reference around. Just create one, add it and wait for the delegate method to be called.

Let me show you a bit of source code:

Sub DownloadOneURL()
	If UBound(urls) = -1 Then Return
	
	Dim URL As String = URLs.Pop
	
	Dim c As New CURLSMBS
	
	// setup request and any options you need
	c.OptionURL = URL
	c.OptionUserAgent = "MyDownloader 1.0"
	
	If CURLSMultiMBS.SharedInstance.AddCURL(c, AddressOf TransferFinished) Then
		Log "Downloading: "+URL
	else
		Break
	end if
End Sub

As you see, we pop an URL from a list of URLs. Then we create a new CURLSMBS object, set some options and add it. The TransferFinished method is passed with addressOf operator as the method to call when finished. We don’t need to keep the curl object around in some property since it gets retained by the multi object. The handler method may look like this:

Sub TransferFinished(CURL as CURLSMBS, ErrorCode as Integer)
	// check this in debugger if you like
	Dim outputData    As String = curl.OutputData
	Dim DebugMessages As String = curl.DebugMessages
	
	#Pragma Unused outputData
	#Pragma Unused DebugMessages
	
	If ErrorCode <> 0 Then
		// failed, so please inspect debug messages
		Break
	End If
	
	MainWindow.Log "Transfer done with error code "+Str(ErrorCode)+" for "+curl.OptionURL+", "+_
	 	 Str(CURLSMultiMBS.SharedInstance.RunningTransfers)+" transfers running."
	
	MainWindow.DownloadOneURL
End Sub

First we query output (the data we received) and the debug messages. We break if the error code indicates a failure. And then we can schedule the next transfer if needed. For a HTTP or FTP request, you may use GetInfoResponseCode to check if the request was okay. Usually if send a request to a REST service, you would check for ErrorCode to be okay (value 0 or constant kError_OK), then check the Response Code for being 200 (HTTP Okay). Then you would check the response for the answer from server, whether your request was not just transferred, but also okay for the server.

You can reuse the same CURLSMBS object for the next transfer of course. Put in a new URL and add it again. Or create a new one, depending on how you like to do your logic. If you don’t keep a reference to the object, the plugin will release it after the method finished.

For the CURLSMultiMBS object, you can now use it in three ways:

  • Old way: Make your subclass, create it, have a timer call Perform yourself.
  • New way: Use sharedInstance to get an automatically created object and add CURL transfers there.
  • Middle way: Create your own instance, but maybe use AutoPerform property here or just the new delegate.

Please try this new class in the 23.2pr2 pre-release.

2 Likes

FYI I’m not finding this to be true with 23.2pr6. I use the Sharedinstance method but AutoPerfom is not automatically set to True.

Thanks for reporting this.
The timer is started, but the property not set to true. So the class works.
We’ll fix that for 23.3 then.

1 Like

Yes, the class works and the new features are a great enhancement, especially being able to pass a delegate for TransferFinished.

What I’d like to see added is a “convenience” property, (FolderItem or Variant), added to CURLSMBS, so that arbitrary info can be passed to TransferFinished by setting its value in the CURLSMBS object before adding it to the Multi queue. Typically when you finish a transfer there is cleanup to do - I need to delete or move the file that was uploaded or downloaded. Currently I extract the filename from OptionURL and remember the file location by other means, but it would be easier and more straightforward if I could pass a FolderItem through the process. Maybe I can pass a path through some unused Option property, but that’s ugly.

I may just add a tag property for you.

2 Likes

Thanks, that’d be awesome :smiley:

Seems like this is still not fixed in 23.3?