void ModuleDownloader::batchDownloadSync(const DownloadUnits &units, const std::string &batchId/* = ""*/)
{
    if (units.size() == 0)
    {
        return;
    }
    // Make sure ModuleDownloader won't be released
    std::weak_ptr<ModuleDownloader> ptr = shared_from_this();
    
    // Test server download resuming support with the first unit
    _supportResuming = false;
    CURL *header = curl_easy_init();
    // Make a resume request
    curl_easy_setopt(header, CURLOPT_RESUME_FROM_LARGE, 0);
    if (prepareHeader(header, units.begin()->second.srcUrl))
    {
        long responseCode;
        curl_easy_getinfo(header, CURLINFO_RESPONSE_CODE, &responseCode);
        if (responseCode == HTTP_CODE_SUPPORT_RESUME)
        {
            _supportResuming = true;
        }
    }
    curl_easy_cleanup(header);
    
    int count = 0;
    DownloadUnits group;
    for (auto it = units.cbegin(); it != units.cend(); ++it, ++count)
    {
        if (count == FOPEN_MAX)
        {
            groupBatchDownload(group);
            group.clear();
            count = 0;
        }
        const std::string &key = it->first;
        const DownloadUnit &unit = it->second;
        group.emplace(key, unit);
    }
    if (group.size() > 0)
    {
        groupBatchDownload(group);
    }
    
    Director::getInstance()->getScheduler()->performFunctionInCocosThread([ptr, batchId]{
        if (!ptr.expired()) {
            std::shared_ptr<ModuleDownloader> downloader = ptr.lock();
            auto callback = downloader->getSuccessCallback();
            if (callback != nullptr)
            {
                callback("", "", batchId);
            }
        }
    });
    _supportResuming = false;
}
long Downloader::getContentSize(const std::string &srcUrl) const
{
    double contentLength = -1;
    CURL *header = curl_easy_init();
    if (prepareHeader(header, srcUrl))
    {
        curl_easy_getinfo(header, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &contentLength);
    }
    curl_easy_cleanup(header);
    
    return contentLength;
}
bool MCCacheWriter::writeCacheFile(FileHandle *objFile, FileHandle *infoFile,
                                 Script *S, uint32_t libRS_threadable) {
  if (!objFile || objFile->getFD() < 0 || !infoFile || infoFile->getFD() < 0) {
    return false;
  }

  mObjFile = objFile;
  mInfoFile = infoFile;
  mpOwner = S;

  bool result = prepareHeader(libRS_threadable)
             && prepareDependencyTable()
             && preparePragmaList()
             && prepareExportVarNameList()
             && prepareExportFuncNameList()
             && prepareExportForEachNameList()
             && prepareStringPool()
             && prepareObjectSlotList()
             && calcSectionOffset()
             && writeAll()
             ;

  return result;
}