X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fupdate.cc;h=c7527ee493624247468b365cde6b2363acb5496f;hb=bb0a36c3a6bea9cd1ebdde7b8a3a04765e317569;hp=6e9d1169acbfc968c9f28bb1f0196ed7f8291d00;hpb=95faa6568854b5f861db07e9b8697169aaceec3c;p=dcpomatic.git diff --git a/src/lib/update.cc b/src/lib/update.cc index 6e9d1169a..c7527ee49 100644 --- a/src/lib/update.cc +++ b/src/lib/update.cc @@ -19,10 +19,13 @@ #include #include +#include #include #include +#include #include "update.h" #include "version.h" +#include "ui_signaller.h" #define BUFFER_SIZE 1024 @@ -30,59 +33,149 @@ using std::cout; using std::min; using std::string; using std::stringstream; +using dcp::raw_convert; +/** Singleton instance */ +UpdateChecker* UpdateChecker::_instance = 0; + +static size_t +write_callback_wrapper (void* data, size_t size, size_t nmemb, void* user) +{ + return reinterpret_cast(user)->write_callback (data, size, nmemb); +} + +/** Construct an UpdateChecker. This sets things up and starts a thread to + * do the work. + */ UpdateChecker::UpdateChecker () : _buffer (new char[BUFFER_SIZE]) , _offset (0) + , _curl (0) + , _state (NOT_RUN) + , _emits (0) + , _to_do (0) { + curl_global_init (CURL_GLOBAL_ALL); + _curl = curl_easy_init (); + + curl_easy_setopt (_curl, CURLOPT_URL, "http://dcpomatic.com/update"); + curl_easy_setopt (_curl, CURLOPT_WRITEFUNCTION, write_callback_wrapper); + curl_easy_setopt (_curl, CURLOPT_WRITEDATA, this); + curl_easy_setopt (_curl, CURLOPT_TIMEOUT, 20); + string const agent = "dcpomatic/" + string (dcpomatic_version); + curl_easy_setopt (_curl, CURLOPT_USERAGENT, agent.c_str ()); + + _thread = new boost::thread (boost::bind (&UpdateChecker::thread, this)); } UpdateChecker::~UpdateChecker () { + /* We are not cleaning up our thread, but hey well */ + + curl_easy_cleanup (_curl); + curl_global_cleanup (); delete[] _buffer; } -static size_t -write_callback_wrapper (void* data, size_t size, size_t nmemb, void* user) +/** Start running the update check */ +void +UpdateChecker::run () { - return reinterpret_cast(user)->write_callback (data, size, nmemb); + boost::mutex::scoped_lock lm (_process_mutex); + _to_do++; + _condition.notify_one (); } -UpdateChecker::Result -UpdateChecker::run () +void +UpdateChecker::thread () { - curl_global_init (CURL_GLOBAL_ALL); - CURL* curl = curl_easy_init (); - if (!curl) { - return MAYBE; - } + while (1) { + /* Block until there is something to do */ + boost::mutex::scoped_lock lock (_process_mutex); + while (_to_do == 0) { + _condition.wait (lock); + } + --_to_do; + lock.unlock (); + + try { + _offset = 0; - curl_easy_setopt (curl, CURLOPT_URL, "http://dcpomatic.com/update.php"); - curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, write_callback_wrapper); - curl_easy_setopt (curl, CURLOPT_WRITEDATA, this); - string const agent = "dcpomatic/" + string (dcpomatic_version); - curl_easy_setopt (curl, CURLOPT_USERAGENT, agent.c_str ()); - int r = curl_easy_perform (curl); - if (r != CURLE_OK) { - return MAYBE; - } - - _buffer[BUFFER_SIZE-1] = '\0'; - stringstream s; - s << _buffer; - cxml::Document doc ("Update"); - doc.read_stream (s); + /* Perform the request */ + + int r = curl_easy_perform (_curl); + if (r != CURLE_OK) { + set_state (FAILED); + return; + } - cout << doc.string_child ("Stable") << "\n"; - return YES; + /* Parse the reply */ + + _buffer[_offset] = '\0'; + stringstream s; + s << _buffer; + cxml::Document doc ("Update"); + doc.read_stream (s); + + { + boost::mutex::scoped_lock lm (_data_mutex); + _stable = doc.string_child ("Stable"); + _test = doc.string_child ("Test"); + } + + string current = string (dcpomatic_version); + bool current_pre = false; + if (boost::algorithm::ends_with (current, "pre")) { + current = current.substr (0, current.length() - 3); + current_pre = true; + } + + float current_float = raw_convert (current); + if (current_pre) { + current_float -= 0.005; + } + + if (current_float < raw_convert (_stable)) { + set_state (YES); + } else { + set_state (NO); + } + } catch (...) { + set_state (FAILED); + } + } } - + size_t UpdateChecker::write_callback (void* data, size_t size, size_t nmemb) { - size_t const t = min (size * nmemb, size_t (BUFFER_SIZE - _offset)); + size_t const t = min (size * nmemb, size_t (BUFFER_SIZE - _offset - 1)); memcpy (_buffer + _offset, data, t); _offset += t; return t; } + +void +UpdateChecker::set_state (State s) +{ + { + boost::mutex::scoped_lock lm (_data_mutex); + _state = s; + _emits++; + } + + ui_signaller->emit (boost::bind (boost::ref (StateChanged))); +} + +UpdateChecker * +UpdateChecker::instance () +{ + if (!_instance) { + _instance = new UpdateChecker (); + } + + return _instance; +} + +