summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2014-01-07 15:06:15 +0000
committerCarl Hetherington <cth@carlh.net>2014-01-07 15:06:15 +0000
commit4983b57d7ccba4ea0b393cf3a40043c1ed5c6b77 (patch)
tree485144028325765093e2268d779ea23eb42eaa38 /src/lib
parent95faa6568854b5f861db07e9b8697169aaceec3c (diff)
Basic dialog reporting of manual update checks.
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/update.cc112
-rw-r--r--src/lib/update.h48
2 files changed, 132 insertions, 28 deletions
diff --git a/src/lib/update.cc b/src/lib/update.cc
index 6e9d1169a..d68979e60 100644
--- a/src/lib/update.cc
+++ b/src/lib/update.cc
@@ -19,10 +19,12 @@
#include <string>
#include <sstream>
+#include <boost/algorithm/string.hpp>
#include <curl/curl.h>
#include <libcxml/cxml.h>
#include "update.h"
#include "version.h"
+#include "ui_signaller.h"
#define BUFFER_SIZE 1024
@@ -30,59 +32,121 @@ using std::cout;
using std::min;
using std::string;
using std::stringstream;
+using boost::lexical_cast;
+
+UpdateChecker* UpdateChecker::_instance = 0;
+
+static size_t
+write_callback_wrapper (void* data, size_t size, size_t nmemb, void* user)
+{
+ return reinterpret_cast<UpdateChecker*>(user)->write_callback (data, size, nmemb);
+}
UpdateChecker::UpdateChecker ()
: _buffer (new char[BUFFER_SIZE])
, _offset (0)
+ , _curl (0)
+ , _state (NOT_RUN)
+ , _startup (true)
{
+ 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 ());
}
UpdateChecker::~UpdateChecker ()
{
+ 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)
+void
+UpdateChecker::run (bool startup)
+try
{
- return reinterpret_cast<UpdateChecker*>(user)->write_callback (data, size, nmemb);
-}
+ boost::mutex::scoped_lock lm (_single_thread_mutex);
-UpdateChecker::Result
-UpdateChecker::run ()
-{
- curl_global_init (CURL_GLOBAL_ALL);
- CURL* curl = curl_easy_init ();
- if (!curl) {
- return MAYBE;
+ {
+ boost::mutex::scoped_lock lm (_data_mutex);
+ _startup = startup;
}
-
- 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);
+
+ _offset = 0;
+
+ int r = curl_easy_perform (_curl);
if (r != CURLE_OK) {
- return MAYBE;
+ set_state (FAILED);
+ return;
}
-
- _buffer[BUFFER_SIZE-1] = '\0';
+
+ _buffer[_offset] = '\0';
stringstream s;
s << _buffer;
cxml::Document doc ("Update");
doc.read_stream (s);
- cout << doc.string_child ("Stable") << "\n";
- return YES;
+ {
+ boost::mutex::scoped_lock lm (_data_mutex);
+ _stable = doc.string_child ("Stable");
+ }
+
+ 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 = lexical_cast<float> (current);
+ if (current_pre) {
+ current_float -= 0.005;
+ }
+
+ if (current_float < lexical_cast<float> (_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;
+ }
+
+ ui_signaller->emit (boost::bind (boost::ref (StateChanged)));
+}
+
+UpdateChecker *
+UpdateChecker::instance ()
+{
+ if (!_instance) {
+ _instance = new UpdateChecker ();
+ }
+
+ return _instance;
+}
+
+
diff --git a/src/lib/update.h b/src/lib/update.h
index 2063dd484..b879e9026 100644
--- a/src/lib/update.h
+++ b/src/lib/update.h
@@ -17,23 +17,63 @@
*/
+#include <boost/signals2.hpp>
+#include <boost/thread/mutex.hpp>
+#include <curl/curl.h>
+
class UpdateChecker
{
public:
UpdateChecker ();
~UpdateChecker ();
- enum Result {
+ void run (bool);
+
+ enum State {
YES,
- MAYBE,
- NO
+ FAILED,
+ NO,
+ NOT_RUN
};
- Result run ();
+ State state () {
+ boost::mutex::scoped_lock lm (_data_mutex);
+ return _state;
+ }
+
+ std::string stable () {
+ boost::mutex::scoped_lock lm (_data_mutex);
+ return _stable;
+ }
+
+ /** @return true if this check was run at startup, otherwise false */
+ bool startup () const {
+ boost::mutex::scoped_lock lm (_data_mutex);
+ return _startup;
+ }
size_t write_callback (void *, size_t, size_t);
+ boost::signals2::signal<void (void)> StateChanged;
+
+ static UpdateChecker* instance ();
+
private:
+ static UpdateChecker* _instance;
+
+ void set_state (State);
+
char* _buffer;
int _offset;
+ CURL* _curl;
+
+ /** mutex to protect _state, _stable and _startup */
+ mutable boost::mutex _data_mutex;
+ State _state;
+ std::string _stable;
+ /** true if this check was run at startup, otherwise false */
+ bool _startup;
+
+ /** mutex to ensure that only one query runs at once */
+ boost::mutex _single_thread_mutex;
};