/** @file JCDownloadMgr.h @brief @author hugao @version 1.0 @date 2016_5_11 */ #ifndef __JCDownloadMgr_H__ #define __JCDownloadMgr_H__ #include "../buffer/JCBuffer.h" #include #include #include #include #include #include "../misc/JCLayaThreadPool.h" namespace laya{ #ifndef THIN_COMMON_WITHOUT_DOWNLOAD class Curl; #endif struct _QueryBase; class __Buffer; /** * @brief 只负责从网络下载资源。post数据。不管缓存。更新。 * 同时做转换层的工作:替换扩展名解密 */ class JCDownloadMgr{ public: struct maskinfo { unsigned int key; int len; }; //回调 typedef std::function onProgressFunc; //返回1表示终止下载 //数据,localip,svip,curlret,httpret,header typedef std::function onEndFunc; public: static void defCompleteFunc(JCBuffer&, const std::string&, const std::string&, int, int, const std::string&); static int defProgressFunc(unsigned int, unsigned int,float); ~JCDownloadMgr(); static JCDownloadMgr* getInstance(); static void delInstance(); //初始化。p_nWorkThreadNum 表示开启几个下载线程。 void init( int p_nWorkThreadNum ); //设置操作超时 void setOpt_optTimeout( int p_nTimeout); //设置超时后的重试次数。第一个是操作超时后的重试次数,第二个是连接超时后的重试次数。 void setOpt_tryNumOnTimeout(int p_nOptTry, int p_nConnTry){ m_nTryNumConn = p_nConnTry; m_nTryNumOpt=p_nOptTry;}; void getOpt_tryNumOnTimeout(int& p_nOptTry, int& p_nConnTry){ p_nConnTry=m_nTryNumConn ; p_nOptTry= m_nTryNumOpt;}; void setOpt_progCB(onProgressFunc p_ProgCb); void setOpt_completeCB(onEndFunc p_CompleteCb); /* * @brief 完整参数的下载请求 * @prame p_nOptTimeout 下载超时。单位是秒, 要求>2, 如果为0,则使用缺省的。 */ void download(const char *p_pszUrl,int p_nPriority, onProgressFunc p_ProgCb, onEndFunc p_CompleteCb, const char* p_pPostData, int p_nPostLen, //可以为0 bool p_bOnlyHeader, //一般是false int p_nTimeout, int p_nConnTimeout, //为0则缺省 std::vector p_vHeaders, //size()==0则忽略 const char* p_pLocalFile, //一边下载,一边保存,一般用在大文件下载,0则忽略 bool p_bChkRemoteChange=false //检查远端文件是否改变了,大文件用 ); void download(const char* p_pszURL); virtual void download(const char* p_pszURL,int p_nPriority, onProgressFunc p_ProgCb, onEndFunc p_CompleteCb ,int p_nOptTimeout); virtual void download(const char* p_pszURL, int p_nPriority, onProgressFunc p_ProgCb, onEndFunc p_CompleteCb, int p_nOptTimeout,int p_nConnTimeout); virtual void download(const char* p_pszURL,int p_nPriority, onProgressFunc p_ProgCb, onEndFunc p_CompleteCb , int p_nOptTimeout, std::vector& p_headers); /* * @brief * 下载大文件,如果失败,回自动断点续传。 * 中间过程会直接写文件,而普通的下载是下载到内存中。 * @pram p_pszLocal 本地文件位置,包括文件名,要求目录必须存在,且有写的权限。 */ void downloadBigFile(const char* p_pszURL, const char* p_pszLocal, onProgressFunc p_ProgCb, onEndFunc p_CompleteCb, int p_nTryNum, int p_nOptTimeout); void getHeader(const char* p_pszUrl, onEndFunc p_CompleteCb, int p_nTryNum, int p_nOptTimeout); void postData(const char* p_pszURL,const char* p_Buffer, int p_nLength, onEndFunc p_completeCb); void postData(const char* p_pszURL,const char* p_Buffer, int p_nLength, onEndFunc p_completeCb, std::vector& p_headers); //删除所有挂起的任务 void clearAllAsyncTask(); //结束当前的任务 void stopCurTask(); //设置代理 void setProxyString(const char* pProxy); /* * @brief 替换某个路径。 * 这个是为了解决有些cdn实在不好用而做的。如果路径中存在p_pstrPath(必须完全匹配), 则用p_pszReplace替换。 * 这样可以导致一个动态目录,从而规避cdn问题。 * 注意替换后url的长度不要增加太多。与下面的tail结合不许比原始大小大512 */ void setFinalReplacePath(const char* p_pstrPath, const char* p_pszReplace); /* * @brief 设置下载的时候附加的东西。 * 注意不要让url的长度增加太多。与上面的替换结合不许比原始大小大512 * @param type * 0表示不附加 * 1随机数,形式为rnd=xxxx * 2外面设置的字符串 * @param p_strTail */ void setDownloadTail(int type, const char* p_strTail); //根据替换和添加规则,得到一个新的url,内部会重新分配空间,所以需要外部delete char* getFinalUrl(const char* p_pszUrl); void resetFinalReplacePath(){ m_strStubPath=""; m_strStubReplace=""; } void resetDownloadTail(){ m_nDownloadTailType=0; m_strDownloadTail="";}; //下载的时候修改文件的扩展名,以防止中间路途被修改。 //由于没有进行多线程保护。这个必须要保证在程序刚开始的时候设置。 void setDownloadReplaceExt(const char* p_pszOrigin, const char* p_pszNew ); void resetDownloadReplaceExt(); //凡是扩展名为p_pszExt的文件,用key来进行异或操作,操作长度为p_nLen void setDownloadUnmask(const char* p_pszExt, unsigned char p_nKey, int p_nLen ); void resetDownloadUnmask(); //如果不存在,则key为0 maskinfo getMaskInfo(const char* p_pszExt ); //如果buffer长度太小,则mask整个buffer void maskBuffer( maskinfo& p_mask, char* p_pBuff, int p_nLen ); int getThreadNum(){ return m_nThreadNum; } void setCookieFile( const char* p_pszCookieFile ); //优先级最低的给一个独立的线程 void postToDownloadThread(std::function task, int p_nPriority); protected: //这是一个单件,不允许直接构造 JCDownloadMgr(); int __DownloadBigFile(void *p_pCurl, const char *p_pszUrl, const char* p_pszLocal, bool p_bHaveQuery, int p_nOptTimeout, int p_nTryNum); int __DownloadHeader(void *p_pCurl, const char *p_pszUrl, unsigned char **p_ppBuff, size_t *p_piSize, bool p_bHaveQuery, int p_nOptTimeout, int p_nTryNum); public://不对外的 void __WorkThread(); //下载完数据的处理。 bool postDownload(const char* p_pszUrl, unsigned char*& p_pBuff, int& p_nLen); //返回错误代码。实际使用的是 Curl::ErrorCode //p_bHaveQuery 是表示是否已经有Query了,因为需要决定添加?rnd=xx还是&rnd=xx int __Download(void *p_pCurl, const char *p_pszUrl, unsigned char **p_ppBuff, size_t *p_piSize, bool p_bHaveQuery); static bool m_bCancelTask; public: char** m_pCurDownloadingUrl; //正在下载的文件。调试用。如果某一个为0则表示正在空闲 static int s_nNoResponseTimeout; //如果下载中途没有数据了,则超过这么长时间之后就重来。 static std::string s_curlProxyString; static int s_nConnTimeout;//超时的全局设置 static int s_nOptTimeout; static bool s_bEncodeURI; protected: short m_nTryNumOpt; short m_nTryNumConn; short m_nThreadNum; JCThreadPool<_QueryBase *> m_ThreadPool; std::recursive_mutex m_CancelMutex; #ifdef WIN32 std::atomic_uint32_t m_nStopNum; //完成个数 #else std::atomic_uint m_nStopNum; //完成个数 #endif std::string m_strStubPath; std::string m_strStubReplace; int m_nDownloadTailType; std::string m_strDownloadTail; std::vector m_vExtReplace; //所有需要替换的扩展名。两个一对,第一个是原始的,第二个是新的 int m_nTimeout; onProgressFunc m_funcProgress; onEndFunc m_funcComplete; std::string m_strCookieFile; typedef std::map maskMap; maskMap m_maskInfo; }; std::string encodeURI(const char* url); } //------------------------------------------------------------------------------ #endif //__JCDownloadMgr_H__