Files
harbour-core/contrib/hbcurl/tests/multi.prg
Aleksander Czajczynski c2870ac7d8 2025-01-07 22:49 UTC+0100 Aleksander Czajczynski (hb fki.pl)
* contrib/hbcurl/hbcurl.ch
    * updated HB_CURLOPT_SSL_OPTIONS: HB_CURLSSLOPT_*

    + added HB_CURLMSG_RESP_HANDLE, HB_CURLMSG_RESP_HPOS
      mappings of array elements returned by
      curl_multi_info_read( <hMulti>[, <aHandles> ]) -> <aResults>

  * contrib/hbcurl/core.c
    * adapted @emazv72 contribution from:
      https://github.com/vszakats/hb/pull/344
      Many thanks, it could be useful for managing multiple transfers,
      by extending some kind of Inkey() loop or in many other
      scenarios.

    + added curl lib version guards

    * minor code and code formattings

    + extended function
      curl_multi_info_read( <hMulti>[, <aHandles> ]) -> <aResults>
      with a possibility to return real GC pointer of specific
      transfer related to reported event. <aHandles> should be
      specified if this is expected.

  + contrib/hbcurl/tests/multi.prg
    + demo of the additions
2025-01-07 22:49:07 +01:00

157 lines
4.2 KiB
Plaintext

#define REMOTE_1 "https://github.com/"
#define REMOTE_2 "https://github.com/harbour/core/"
#define REMOTE_3 "https://raw.githubusercontent.com/harbour/core/refs/heads/master/contrib/hbcurl/hbcurl.hbm"
#require "hbcurl"
#include "inkey.ch"
PROCEDURE Main( cRemote4 )
LOCAL hMulti
LOCAL hEasy, aResult, nKey := 0
LOCAL aUrls := { REMOTE_1, REMOTE_2, REMOTE_3 }
LOCAL aHandles, i, nErr, nRun := 0, nLastRun := 0
/* add a remote from command-line if you want */
IF ! Empty( cRemote4 )
AAdd( aUrls, cRemote4 )
ENDIF
/* add the individual transfers */
aHandles := Array( Len( aUrls ) )
curl_global_init()
hMulti := curl_multi_init()
FOR i := 1 TO Len( aUrls )
hEasy := curl_easy_init()
IF hEasy != NIL
curl_easy_setopt( hEasy, HB_CURLOPT_URL, aUrls[ i ] )
curl_easy_setopt( hEasy, HB_CURLOPT_DOWNLOAD )
curl_easy_setopt( hEasy, HB_CURLOPT_DL_BUFF_SETUP )
// curl_easy_setopt( hEasy, HB_CURLOPT_VERBOSE, .T. )
curl_easy_setopt( hEasy, HB_CURLOPT_SSL_OPTIONS, HB_CURLSSLOPT_NATIVE_CA )
curl_multi_add_handle( hMulti, hEasy )
aHandles[ i ] := hEasy
ENDIF
NEXT
CLS
nErr := curl_multi_perform( hMulti, @nLastRun )
IF nErr != HB_CURLM_OK
? "curl_multi_perform() failed, err=", nErr
Cleanup( aHandles, hMulti )
RETURN
ENDIF
SetPos( 3, 0 )
DO WHILE curl_multi_perform( hMulti, @nRun ) == HB_CURLM_OK
aResult := CurGet()
@ 1, 1 SAY Time()
@ 2, 1 SAY "downloading... (" + hb_ntos( nRun ) + " transfers left)"
CurSet( aResult )
IF nRun < nLastRun
FOR i := 1 TO nLastRun - nRun
/*
* passing possible aHandles is required to receive curl_easy_*
* compatible GC-pointer in aResult[ HB_CURLMSG_RESP_HANDLE ]
*/
aResult := curl_multi_info_read( hMulti, aHandles )
IF aResult # NIL
/*
* instead of FOR loop you could possibly
* DO WHILE HB_IsArray( aResult := curl_multi_info_read( hMulti ) ) .AND. ;
* aResult[ HB_CURLMSG_RESP_LEN ] > 0
*/
? "HB_CURLMSG_RESP_LEN :", aResult[ HB_CURLMSG_RESP_LEN ]
? "HB_CURLMSG_RESP_RESPONSE_CODE:", aResult[ HB_CURLMSG_RESP_RESPONSE_CODE ]
? "HB_CURLMSG_RESP_MSG :", aResult[ HB_CURLMSG_RESP_MSG ]
? "HB_CURLMSG_RESP_RESULT :", aResult[ HB_CURLMSG_RESP_RESULT ]
? "HB_CURLMSG_RESP_HPOS :", aResult[ HB_CURLMSG_RESP_HPOS ]
IF aResult[ HB_CURLMSG_RESP_HPOS ] > 0
? "URL :", aUrls[ aResult[ HB_CURLMSG_RESP_HPOS ] ]
IF ! Empty( curl_easy_getinfo( aResult[ HB_CURLMSG_RESP_HANDLE ], HB_CURLINFO_REDIRECT_URL ) )
? "HB_CURLINFO_REDIRECT_URL :", curl_easy_getinfo( aResult[ HB_CURLMSG_RESP_HANDLE ], HB_CURLINFO_REDIRECT_URL )
ENDIF
ENDIF
? "--"
ENDIF
NEXT
ENDIF
IF nRun == 0 .OR. nKey == K_ESC
EXIT
ENDIF
nLastRun := nRun
nKey := Inkey( 0.1 )
ENDDO
PrintAllDownloaded( aHandles )
Cleanup( aHandles, hMulti )
RETURN
STATIC PROCEDURE PrintAllDownloaded( aHandles )
LOCAL h
FOR EACH h IN aHandles
IF h == NIL
LOOP
ENDIF
? "Transfer #" + hb_ntos( h:__enumIndex ) + " (" + hb_ntos( curl_easy_getinfo( h, HB_CURLINFO_RESPONSE_CODE ) ) + "): "
IF curl_easy_getinfo( h, HB_CURLINFO_RESPONSE_CODE ) == 0
?? "aborted"
ELSE
?? Left( curl_easy_dl_buff_get( h ), 40 ) + IIF( Len( curl_easy_dl_buff_get( h ) ) > 40, "...", "" )
ENDIF
NEXT
RETURN
STATIC PROCEDURE Cleanup( aHandles, hMulti )
LOCAL h
FOR EACH h IN aHandles
IF h == NIL
LOOP
ENDIF
curl_multi_remove_handle( hMulti, h )
curl_easy_cleanup( h )
NEXT
curl_multi_cleanup( hMulti )
curl_global_cleanup()
RETURN
STATIC FUNCTION CurGet()
RETURN { Row(), Col() }
STATIC PROCEDURE CurSet( a )
SetPos( a[ 1 ], a[ 2 ] )
RETURN