1 ///////////////////////////////////////////////////////////////////////////// 2 // Name: thread.h 3 // Purpose: wxCurlDownloadThread, wxCurlUploadThread 4 // Author: Francesco Montorsi 5 // Created: 2007/04/14 6 // RCS-ID: $Id: thread.h 1237 2010-03-10 21:52:47Z frm $ 7 // Copyright: (c) 2007 Francesco Montorsi 8 // Licence: wxWidgets licence 9 ///////////////////////////////////////////////////////////////////////////// 10 11 #ifndef _WXCURL_THREAD_H_ 12 #define _WXCURL_THREAD_H_ 13 14 // wxWidgets headers 15 #include "wx/defs.h" 16 #include "wx/thread.h" 17 18 #include "wx/curl/base.h" 19 20 #include <memory> 21 22 //! One of the protocols supported by wxCurl. 23 enum wxCurlProtocol 24 { 25 wxCP_INVALID = -1, 26 27 wxCP_HTTP, 28 wxCP_FTP 29 }; 30 31 //! One of the possible errors code returned by wxCurl. 32 enum wxCurlThreadError 33 { 34 wxCTE_NO_ERROR = wxTHREAD_NO_ERROR, //!< There was no error. 35 36 wxCTE_NO_RESOURCE = wxTHREAD_NO_RESOURCE, //!< There were insufficient resources to create a new thread. 37 wxCTE_ALREADY_RUNNING = wxTHREAD_RUNNING, //!< The thread is already running. 38 wxCTE_INVALID_PROTOCOL, //!< The given URL requires an unspported protocol. 39 wxCTE_NO_VALID_STREAM, //!< The input/output stream could not be created or is invalid. 40 wxCTE_ABORTED, //!< The thread was user-aborted through wxCurlBaseThread::Abort(). 41 wxCTE_CURL_ERROR 42 //!< LibCURL failed. You can use thread->GetCurlSession()->GetErrorString() to get more info. 43 }; 44 45 //! The stack size for wxCurl threads. 46 #define wxCURL_THREAD_STACK_SIZE 1024 47 48 49 // ---------------------------------------------------------------------------- 50 // wxCurlBaseThread 51 // ---------------------------------------------------------------------------- 52 53 //! Base class for wxCurl threads. 54 class WXDLLIMPEXP_CURL wxCurlBaseThread : public wxThread 55 { 56 protected: 57 58 //! The URL identifying the resource to download/upload. 59 wxString m_url; 60 61 //! The libcurl handle being used for the transfer. 62 std::shared_ptr<wxCurlBase> m_pCurl; 63 64 //! The protocol being used for the transfer. 65 wxCurlProtocol m_protocol; 66 67 //! The event handler which gets m_pCurl's events. 68 wxEvtHandler *m_pHandler; 69 int m_nId; 70 71 //! This flag is set to true when the thread has been cancelled using Delete(). 72 //! Since it's continuosly read by the running thread and maybe written from 73 //! other threads, it needs a mutex. 74 bool m_bAbort; 75 wxMutex m_bAbortMutex; 76 77 public: 78 wxCurlBaseThread(wxEvtHandler *handler = NULL, 79 int id = wxID_ANY) wxThread(wxTHREAD_JOINABLE)80 : wxThread(wxTHREAD_JOINABLE) 81 { 82 m_protocol = wxCP_INVALID; 83 m_pCurl = 0; 84 85 m_nId = id; 86 m_pHandler = handler; 87 88 m_bAbort = false; 89 } 90 ~wxCurlBaseThread()91 ~wxCurlBaseThread() 92 { 93 m_pCurl = 0; 94 } 95 96 public: // thread execution management 97 98 //! Returns true if this thread is ready to be started using e.g. #StartTransfer. IsOk()99 virtual bool IsOk() const 100 { return !m_url.empty() && m_pCurl != 0; } 101 102 //! Starts the transfer. This is equivalent to call wxCurlDownloadThread::Download or 103 //! wxCurlUploadThread::Upload. 104 virtual wxCurlThreadError StartTransfer() = 0; 105 106 //! Aborts this thread. 107 virtual void Abort(); 108 109 //! Waits for the completion of the transfer. 110 virtual wxCurlThreadError Wait(); 111 112 //! Pauses the transfer. 113 virtual wxCurlThreadError Pause(); 114 115 //! Resumes the transfer. 116 virtual wxCurlThreadError Resume(); 117 118 119 public: // setters 120 121 //! Sets the event handler to which wxCurlBeginPerformEvent, wxCurlEndPerformEvent 122 //! and wxCurlDownloadEvent/wxCurlUploadEvents will be posted. 123 void SetEvtHandler(wxEvtHandler *handler, int id = wxID_ANY) 124 { 125 wxCHECK_RET(!IsAlive(), wxS("Cannot use this function after the tranfer has begun")); 126 m_pHandler=handler; m_nId=id; 127 } 128 129 //! Sets the URL to download/upload from/to. 130 wxCurlThreadError SetURL(const wxString &url); 131 wxCurlThreadError SetURL(const wxString &url, std::shared_ptr<wxCurlBase> pCurl); 132 133 public: // getters 134 GetEvtHandler()135 wxEvtHandler *GetEvtHandler() const 136 { return m_pHandler; } GetId()137 int GetId() const 138 { return m_nId; } 139 IsAborting()140 bool IsAborting() 141 { return m_bAbort; } 142 143 144 //! Returns the wxCurlBase-derived object which is being used for the transfer. 145 //! Note that the returned value will be NULL if you've not called #SetURL yet. 146 //! You can cast it to the wxCurlBase-derived class associated with the return 147 //! value of GetProtocol() (e.g. if GetProtocol() returns wxCP_HTTP, you can cast 148 //! GetCurlSession() to wxCurlHTTP). GetCurlSession()149 wxCurlBase *GetCurlSession() const 150 { return m_pCurl.get(); } 151 GetCurlSharedPtr()152 std::shared_ptr<wxCurlBase> &GetCurlSharedPtr() 153 { return m_pCurl; } 154 155 //! Returns the protocol used for the transfer. 156 //! This function will return something different from wxCP_INVALID only after 157 //! a call to #SetURL with a valid URL. GetProtocol()158 wxCurlProtocol GetProtocol() const 159 { return m_protocol; } 160 161 //! Returns the URL of current transfer. GetURL()162 wxString GetURL() const 163 { return m_url; } 164 165 public: // public utils 166 167 //! Returns the protocol which should be used to download the resource 168 //! associated with the given URL. 169 static wxCurlProtocol GetProtocolFromURL(const wxString &url); 170 171 //! Returns a pointer to a wxCurlBase-derived class suitable for handling 172 //! transfers on the given protocol. 173 //! You'll need to wx_static_cast the return value to the 174 //! right class in order to be able to set/get further options 175 //! (e.g. url/username/password/proxy/etc etc). 176 static std::shared_ptr<wxCurlBase>CreateHandlerFor(wxCurlProtocol prot); 177 178 protected: 179 180 virtual bool TestDestroy(); 181 virtual void OnExit(); 182 183 184 // change the access type of some wxThread functions which should not 185 // be used on wxCurlBaseThread-derived classes. 186 Create(unsigned int stackSize)187 virtual wxCurlThreadError Create(unsigned int stackSize) 188 { return (wxCurlThreadError)wxThread::Create(stackSize); } Run()189 virtual wxCurlThreadError Run() 190 { return (wxCurlThreadError)wxThread::Run(); } Delete()191 virtual wxCurlThreadError Delete() 192 { return (wxCurlThreadError)wxThread::Delete(); } 193 }; 194 195 196 // ---------------------------------------------------------------------------- 197 // wxCurlDownloadThreadOutputFilter 198 // ---------------------------------------------------------------------------- 199 200 class WXDLLIMPEXP_CURL wxCurlDownloadThread; 201 202 // private class used by wxCurlDownloadThread 203 class wxCurlDownloadThreadOutputFilter : public wxOutputStream 204 { 205 protected: 206 wxCurlDownloadThread *m_thread; 207 wxOutputStream *m_stream; 208 209 public: wxCurlDownloadThreadOutputFilter(wxCurlDownloadThread * thread)210 wxCurlDownloadThreadOutputFilter(wxCurlDownloadThread *thread) 211 { m_thread = thread; m_stream = NULL; } 212 SetStream(wxOutputStream * realStream)213 void SetStream(wxOutputStream *realStream) 214 { m_stream = realStream; } 215 216 virtual size_t OnSysWrite(const void *buffer, size_t bufsize); 217 IsOk()218 virtual bool IsOk() const 219 { return m_thread && m_stream && m_stream->IsOk(); } 220 GetRealStream()221 wxOutputStream *GetRealStream() const 222 { return m_stream; } 223 GetLength()224 wxFileOffset GetLength() const 225 { return m_stream->GetLength(); } 226 Close()227 bool Close() 228 { return m_stream->Close(); } 229 }; 230 231 232 // ---------------------------------------------------------------------------- 233 // wxCurlDownloadThread 234 // ---------------------------------------------------------------------------- 235 236 //! A simple joinable thread which allows downloading 237 //! resources from the net without blocking the GUI of your app. 238 class WXDLLIMPEXP_CURL wxCurlDownloadThread : public wxCurlBaseThread 239 { 240 friend class wxCurlDownloadThreadOutputFilter; // needs to access our TestDestroy() 241 242 protected: 243 244 //! The output stream for downloaded data. 245 wxCurlDownloadThreadOutputFilter m_output; 246 247 public: 248 wxCurlDownloadThread(wxEvtHandler *handler = NULL, 249 int id = wxID_ANY, 250 const wxString &url = wxEmptyString, 251 wxOutputStream *out = NULL) wxCurlBaseThread(handler,id)252 : wxCurlBaseThread(handler, id), 253 m_output(this) 254 { 255 if (!url.IsEmpty()) 256 Download(url, out); 257 } 258 259 public: // public API 260 261 //! Sets the output stream where the downloaded data are written. 262 //! If you pass NULL to this function, then a new temporary file will be used. 263 wxCurlThreadError SetOutputStream(wxOutputStream *out = NULL); 264 265 //! Returns the output stream for downloaded data. GetOutputStream()266 wxOutputStream *GetOutputStream() const 267 { 268 wxCHECK_MSG(!IsRunning(), NULL, 269 wxS("You cannot access the output stream while the thread is running!")); 270 return m_output.GetRealStream(); 271 } 272 273 //! Returns true if this thread is ready to be started using #Download. IsOk()274 virtual bool IsOk() const 275 { return wxCurlBaseThread::IsOk() && m_output.IsOk(); } 276 277 //! Creates and runs this thread for download of the given URL in the given 278 //! output stream (internally calls #SetURL and #SetOutputStream). 279 wxCurlThreadError Download(const wxString &url, wxOutputStream *out = NULL); 280 281 //! Downloads the URL previously set with #SetURL using the output stream 282 //! previously set with #SetOutputStream. 283 wxCurlThreadError Download(); 284 285 protected: 286 287 // change access policy to force the user of the better-readable Download() method: StartTransfer()288 virtual wxCurlThreadError StartTransfer() 289 { return Download(); } 290 291 virtual void *Entry(); 292 }; 293 294 295 // ---------------------------------------------------------------------------- 296 // wxCurlUploadThreadInputFilter 297 // ---------------------------------------------------------------------------- 298 299 class WXDLLIMPEXP_CURL wxCurlUploadThread; 300 301 // private class 302 class wxCurlUploadThreadInputFilter : public wxInputStream 303 { 304 protected: 305 wxCurlUploadThread *m_thread; 306 wxInputStream *m_stream; 307 308 public: wxCurlUploadThreadInputFilter(wxCurlUploadThread * thread)309 wxCurlUploadThreadInputFilter(wxCurlUploadThread *thread) 310 { m_thread = thread; m_stream = NULL; } 311 SetStream(wxInputStream * realStream)312 void SetStream(wxInputStream *realStream) 313 { m_stream = realStream; } 314 315 virtual size_t OnSysRead(void *buffer, size_t bufsize); 316 IsOk()317 virtual bool IsOk() const 318 { return m_thread && m_stream && m_stream->IsOk(); } 319 GetRealStream()320 wxInputStream *GetRealStream() const 321 { return m_stream; } 322 GetLength()323 wxFileOffset GetLength() const 324 { return m_stream->GetLength(); } 325 Peek()326 char Peek() 327 { return m_stream->Peek(); } 328 }; 329 330 331 // ---------------------------------------------------------------------------- 332 // wxCurlUploadThread 333 // ---------------------------------------------------------------------------- 334 335 //! A simple joinable thread which allows uploading 336 //! resources to the net without blocking the GUI of your app. 337 class WXDLLIMPEXP_CURL wxCurlUploadThread : public wxCurlBaseThread 338 { 339 friend class wxCurlUploadThreadInputFilter; // needs to access our TestDestroy() 340 341 protected: 342 343 //! The input stream for uploaded data. 344 wxCurlUploadThreadInputFilter m_input; 345 346 public: 347 wxCurlUploadThread(wxEvtHandler *handler = NULL, 348 int id = wxID_ANY, 349 const wxString &url = wxEmptyString, 350 wxInputStream *in = NULL) wxCurlBaseThread(handler,id)351 : wxCurlBaseThread(handler, id), 352 m_input(this) 353 { 354 if (!url.IsEmpty()) 355 Upload(url, in); 356 } 357 358 public: // public API 359 360 //! Sets the output stream where the downloaded data are written. 361 //! If you pass NULL to this function, then a new temporary file will be used. 362 wxCurlThreadError SetInputStream(wxInputStream *in = NULL); 363 364 //! Returns the output stream for downloaded data. GetInputStream()365 wxInputStream *GetInputStream() const 366 { 367 wxCHECK_MSG(!IsRunning(), NULL, 368 wxS("You cannot access the output stream while the thread is running!")); 369 return m_input.GetRealStream(); 370 } 371 372 //! Returns true if this thread is ready to be started using #Upload. IsOk()373 virtual bool IsOk() const 374 { return wxCurlBaseThread::IsOk() && m_input.IsOk(); } 375 376 //! Creates and runs this thread for upload to the given URL of the given 377 //! input stream (internally calls #SetURL and #SetOutputStream). 378 wxCurlThreadError Upload(const wxString &url, wxInputStream *in = NULL); 379 380 //! Uploads the URL previously set with #SetURL using the input stream 381 //! previously set with #SetInputStream. 382 wxCurlThreadError Upload(); 383 384 protected: 385 386 // change access policy to force the user of the better-readable Upload() method: StartTransfer()387 virtual wxCurlThreadError StartTransfer() 388 { return Upload(); } 389 390 virtual void *Entry(); 391 }; 392 393 394 #endif // _WXCURL_THREAD_H_ 395 396