Aegisub/aegisub/reporter/upload.cpp
Amar Takhar 930f593d6a dd the beginings of the Aegisub Reporter, this is my first C++ program from scratch. (yes, that's a disclaimer)
What's left to be done:
  * Crash support. (only works for 'reports')
  * UI cleanups.
  * Interfacing with Aegisub to get proper metrics.
  * OSX support.
  * Windows support. (someone else will have to do this)
  * Server-side code.

There's probably a lot of other things I'm forgetting, anyone is free to commit to this, if you want to make major changes let me know beforehand.

Originally committed to SVN as r3475.
2009-09-03 06:53:55 +00:00

145 lines
4.2 KiB
C++

// Copyright (c) 2009, Amar Takhar <verm@aegisub.org>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
// $Id$
/// @@file upload.cpp
/// @brief Handle uploading of data.
#ifndef R_PRECOMP
#include <wx/file.h>
#endif
#include "upload.h"
/// @brief Constructor.
Upload::Upload(Progress *prog) {
/// XXX: error checking.
progress = prog;
handle = curl_easy_init();
// curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(handle, CURLOPT_USERAGENT, "Reporter v1.0");
curl_easy_setopt(handle, CURLOPT_READFUNCTION, CBRead);
curl_easy_setopt(handle, CURLOPT_PROGRESSFUNCTION, CBProgress);
curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0L);
curl_easy_setopt(handle, CURLOPT_PROGRESSDATA, progress);
}
/// @brief Destructor.
Upload::~Upload() {
curl_free(handle);
}
/// @brief Submit an XML report.
/// @param report filename of the report.
void Upload::Report(wxString report) {
wxFile file(report, wxFile::read);
SendFile("http://reporter.darkbeer.org/PUT/", file);
}
/// @brief Progress callback.
/// @param p pointer to progress info.
/// @param dlt download size.
/// @param dln downloaded.
/// @param ult upload size.
/// @param uln uploaded.
int Upload::CBProgress(void *p, double dlt, double dln, double ult, double uln) {
if (uln > 0) {
Progress *progress = (Progress*) p;
// Update returns false if the user has hit abort.
if (progress->Update(round(ult / uln) * 100) == false)
// Returning non-zero will cause curl to abort the transfer.
return 1;
}
return 0;
}
/// @brief Callback to read data from a FD.
/// @param p buffer to fill.
/// @param size byte length.
/// @param nmemb object size.
/// @param filep FP to read from.
size_t Upload::CBRead(char *p, size_t size, size_t nmemb, void *filep) {
// This is on purpose to wx doesn't close the fp, curl does that for us.
wxFile *file = new wxFile((int)filep);
if (file->Eof())
return 0;
int ret = file->Read(p, file->Length());
if (ret == wxInvalidOffset)
return CURL_READFUNC_ABORT;
return ret;
}
/// @brief Send a file to the server
/// @param file file to send.
/// @return 1/0 for success/failure.
bool Upload::SendFile(const char *url, wxFile &file) {
progress->Update(0, _("Connecting..."));
curl_easy_setopt(handle, CURLOPT_URL, url);
Error(curl_easy_perform(handle));
curl_easy_setopt(handle, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(handle, CURLOPT_PUT, 1L);
curl_easy_setopt(handle, CURLOPT_READDATA, file.fd());
curl_easy_setopt(handle, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file.Length());
CURLcode res = curl_easy_perform(handle);
Error(res);
curl_easy_setopt(handle, CURLOPT_HTTPGET, 1L); // Reset to HTTP GET
curl_easy_cleanup(handle);
if (res == CURLE_OK)
return 1;
return 0;
}
/// @brief Handle error codes
/// @param error CURLcode.
void Upload::Error(CURLcode error) {
switch (error) {
case CURLE_OK:
progress->Update(0, _("Sending data..."));
break;
case CURLE_COULDNT_RESOLVE_HOST:
progress->Update(0, _("Couldn't resolve host."));
break;
case CURLE_COULDNT_CONNECT:
progress->Update(0, _("Couldn't connect to server."));
break;
case CURLE_SEND_ERROR: // socket error
case CURLE_RECV_ERROR: // socket error
progress->Update(0, _("Connection error."));
break;
case CURLE_GOT_NOTHING: // no response from server
case CURLE_HTTP_RETURNED_ERROR: // HTTP error >= 400
progress->Update(0, _("Server error."));
break;
case CURLE_OPERATION_TIMEDOUT:
progress->Update(0, _("Operation timeout."));
break;
default:
progress->Update(0, wxString::Format("Transfer error. (%d)\n", error));
}
}