示例#1
0
void UploadQueue::start_next_upload() {
    unsigned int files_started = 0;

    boost::shared_ptr<HTTPRequestData> data(new HTTPRequestData);
    data->method = "POST";
    data->cookies = cookies;

    current_upload_files.clear();
    current_batch_bytes = 0;
    current_batch_retry = 0;

    for (std::list<UploadQueueEntry>::iterator it = queue.begin(); it != queue.end(); ++it) {
        if (it->status != UploadQueueEntry::ENTRY_WAITING) continue;
        try {
            UploadQueueEntry& qe = *it;

            // Open and process the image.
            // We do this now so we can catch errors and attribute them to individual images;
            // letting the HTTPRequest do it would fail the whole request if a single image
            // was unreadable.
            qe.datablock->resolve();

            // Pull in post params
            for (std::map<std::string, std::string>::iterator pvit = post_vars.begin();
                pvit != post_vars.end(); ++pvit) {
                qe.target.query_data[pvit->first] = pvit->second;
            }

            if (files_started == 0) {
                // First match sets the target uri
                data->uri = qe.target;
            } else {
                // Subsequently, we can only batch up more uploads to the same endpoint
                if (!(data->uri == qe.target)) continue;
            }

            it->setStatus(UploadQueueEntry::ENTRY_IN_PROGRESS);
            --files_waiting;
            current_queue_bytes -= qe.filesize;

            std::string s = "file" + files_started;
            qe.post_field = s;
            data->addFile(s, FB::wstring_to_utf8(qe.filename), "application/octet-stream", qe.datablock);

            current_upload_files.insert(qe.source_path);
            current_batch_bytes += qe.filesize;
            ++files_started;
            if (files_started >= batch_size) break;

        } catch (const std::exception& e) {
            it->result = e.what();
            it->setStatus(UploadQueueEntry::ENTRY_ERROR);
        }
    }

    if (files_started) {
        // We had enough images left in the queue for another request, so kick that off now.
        current_upload_request = HTTPRequest::create();
        current_upload_request->onStatusChanged(
            bind(&UploadQueue::upload_request_status_changed, this, _1)
            );
        current_upload_request->startRequest(data);

        // As long as we're doing uploads, we want to keep the HTTP server
        // up to provide progress to the chat bar widget -- so enable deferred shutdown.
        // TODOTODO
        //try {
        //    boost::shared_ptr<HTTPService> h = http_srv_inst_weak.lock();
        //    if (h) h->setDeferShutdown(true);
        //} catch (...) {}

    } else {
#ifndef NDEBUG
        FBLOG_DEBUG("UploadQueue",
            "start_next_upload() found no waiting files, running completion handlers\n");
#endif
        // All done, post upload finished callback to all instances
        FB::VariantMap d = getEmptyProgressDict();
        FB::VariantMap failures;

        for (std::list<UploadQueueEntry>::iterator it = queue.begin(); it != queue.end(); ++it) {
            if (it->status == UploadQueueEntry::ENTRY_ERROR) {
                failures[FB::wstring_to_utf8(it->source_path)] = it->result;
#ifndef NDEBUG
                FBLOG_WARN("UploadQueue", "Reporting file \"" << it->source_path.c_str()
                    << "\" as failed: " << it->result.c_str() << std::endl);
#endif        
            }
        }
        queue.clear();

        if (! failures.empty()) d["failed_files"] = failures;

        status = UploadQueue::UPLOAD_COMPLETE;
        // fire completion handlers, if available
        for (std::list<FB::URI>::iterator it = completion_handlers.begin();
            it != completion_handlers.end(); ++it) {
            boost::shared_ptr<HTTPRequestData> reqdata(new HTTPRequestData(*it));
            reqdata->cookies = cookies;
            HTTPRequest::asyncStartRequest(reqdata);
        }

        if (queue_finished_callback)
            queue_finished_callback(shared_ptr());
        
        StatusUpdateEvent evt(d);
        SendEvent(&evt);
    }
}