Preparation to remove network_http (its work will be
taken over by the reqeust manager). Initialise news and addons manager in a separate thread and not from the network_http thread anymore. Icons are also downloaded now from the request manager instead of the network_http. git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@15006 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
parent
9804cbddeb
commit
b136e16f7a
@ -20,6 +20,21 @@
|
||||
|
||||
#include "addons/addons_manager.hpp"
|
||||
|
||||
#include "addons/inetwork_http.hpp"
|
||||
#include "addons./news_manager.hpp"
|
||||
#include "addons/zip.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "io/xml_node.hpp"
|
||||
#include "karts/kart_properties.hpp"
|
||||
#include "karts/kart_properties_manager.hpp"
|
||||
#include "online/http_request.hpp"
|
||||
#include "online/request_manager.hpp"
|
||||
#include "states_screens/kart_selection.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
#include "tracks/track_manager.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
@ -27,18 +42,6 @@
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
|
||||
#include "addons/inetwork_http.hpp"
|
||||
#include "addons/request.hpp"
|
||||
#include "addons/zip.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "io/xml_node.hpp"
|
||||
#include "karts/kart_properties.hpp"
|
||||
#include "karts/kart_properties_manager.hpp"
|
||||
#include "states_screens/kart_selection.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
#include "tracks/track_manager.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
|
||||
AddonsManager* addons_manager = 0;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -68,6 +71,59 @@ AddonsManager::~AddonsManager()
|
||||
saveInstalled();
|
||||
} // ~AddonsManager
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void AddonsManager::init(const XMLNode *xml,
|
||||
bool force_refresh)
|
||||
{
|
||||
std::string addon_list_url("");
|
||||
StkTime::TimeType mtime(0);
|
||||
const XMLNode *include = xml->getNode("include");
|
||||
std::string filename=file_manager->getAddonsFile("addons.xml");
|
||||
if(!include)
|
||||
{
|
||||
file_manager->removeFile(filename);
|
||||
NewsManager::get()->addNewsMessage(_("Can't access stkaddons server..."));
|
||||
// Use a curl error code here:
|
||||
//return CURLE_COULDNT_CONNECT;
|
||||
return;
|
||||
}
|
||||
|
||||
include->get("file", &addon_list_url);
|
||||
|
||||
int64_t tmp;
|
||||
include->get("mtime", &tmp);
|
||||
mtime = tmp;
|
||||
|
||||
bool download = mtime > UserConfigParams::m_addons_last_updated ||
|
||||
force_refresh ||
|
||||
!file_manager->fileExists(filename);
|
||||
|
||||
if (download)
|
||||
{
|
||||
Log::info("NetworkHttp", "Downloading updated addons.xml");
|
||||
Online::HTTPRequest *download_request = new Online::HTTPRequest("addons.xml");
|
||||
download_request->setURL(addon_list_url);
|
||||
download_request->executeNow();
|
||||
if(download_request->hadDownloadError())
|
||||
{
|
||||
Log::error("addons", "Error on download addons.xml: %s\n",
|
||||
download_request->getDownloadErrorMessage());
|
||||
delete download_request;
|
||||
return;
|
||||
}
|
||||
delete download_request;
|
||||
UserConfigParams::m_addons_last_updated=StkTime::getTimeSinceEpoch();
|
||||
}
|
||||
else
|
||||
Log::info("NetworkHttp", "Using cached addons.xml");
|
||||
|
||||
const XMLNode *xml_addons = new XMLNode(filename);
|
||||
addons_manager->initAddons(xml_addons); // will free xml_addons
|
||||
if(UserConfigParams::logAddons())
|
||||
Log::info("addons", "Addons manager list downloaded");
|
||||
|
||||
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
/** This initialises the online portion of the addons manager. It uses the
|
||||
* downloaded list of available addons. This is called by network_http before
|
||||
@ -76,7 +132,7 @@ AddonsManager::~AddonsManager()
|
||||
* main GUI is not blocked anyway). This function will update the state
|
||||
* variable
|
||||
*/
|
||||
void AddonsManager::initOnline(const XMLNode *xml)
|
||||
void AddonsManager::initAddons(const XMLNode *xml)
|
||||
{
|
||||
m_addons_list.lock();
|
||||
// Clear the list in case that a reinit is being done.
|
||||
@ -204,7 +260,7 @@ void AddonsManager::initOnline(const XMLNode *xml)
|
||||
|
||||
if (UserConfigParams::m_internet_status == INetworkHttp::IPERM_ALLOWED)
|
||||
downloadIcons();
|
||||
} // initOnline
|
||||
} // initAddons
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Reinitialises the addon manager, which happens when the user selects
|
||||
@ -297,12 +353,25 @@ void AddonsManager::downloadIcons()
|
||||
addon.getId().c_str());
|
||||
continue;
|
||||
}
|
||||
std::string save = "icons/"+icon;
|
||||
Request *r = INetworkHttp::get()->downloadFileAsynchron(url, save,
|
||||
/*priority*/1,
|
||||
/*manage_mem*/true);
|
||||
if (r != NULL)
|
||||
r->setAddonIconNotification(&addon);
|
||||
|
||||
// A simple class that will notify the addon via a callback
|
||||
class IconRequest : public Online::HTTPRequest
|
||||
{
|
||||
Addon *m_addon; // stores this addon object
|
||||
void afterOperation()
|
||||
{
|
||||
m_addon->setIconReady();
|
||||
} // callback
|
||||
public:
|
||||
IconRequest(const std::string &filename,
|
||||
const std::string &url,
|
||||
Addon *addon ) : HTTPRequest(filename, true, 1)
|
||||
{
|
||||
m_addon = addon; setURL(url);
|
||||
} // IconRequest
|
||||
};
|
||||
IconRequest *r = new IconRequest("icons/"+icon, url, &addon);
|
||||
r->queue();
|
||||
}
|
||||
else
|
||||
m_addons_list.getData()[i].setIconReady();
|
||||
|
@ -39,8 +39,6 @@ private:
|
||||
Synchronised<std::vector<Addon> > m_addons_list;
|
||||
/** Full filename of the addons_installed.xml file. */
|
||||
std::string m_file_installed;
|
||||
std::string m_type;
|
||||
int m_download_state;
|
||||
|
||||
/** List of loaded icons. */
|
||||
std::vector<std::string> m_icon_list;
|
||||
@ -60,7 +58,8 @@ private:
|
||||
public:
|
||||
AddonsManager();
|
||||
~AddonsManager();
|
||||
void initOnline(const XMLNode *xml);
|
||||
void init(const XMLNode *xml, bool force_refresh);
|
||||
void initAddons(const XMLNode *xml);
|
||||
void checkInstalledAddons();
|
||||
const Addon* getAddon(const std::string &id) const;
|
||||
int getAddonIndex(const std::string &id) const;
|
||||
|
@ -256,102 +256,19 @@ NetworkHttp::~NetworkHttp()
|
||||
*/
|
||||
CURLcode NetworkHttp::init(bool forceRefresh)
|
||||
{
|
||||
news_manager->clearErrorMessage();
|
||||
core::stringw error_message("");
|
||||
// The news message must be updated if either it has never been updated,
|
||||
// or if the time of the last update was more than news_frequency ago.
|
||||
bool download = UserConfigParams::m_news_last_updated==0 ||
|
||||
UserConfigParams::m_news_last_updated
|
||||
+UserConfigParams::m_news_frequency
|
||||
< StkTime::getTimeSinceEpoch() || forceRefresh;
|
||||
|
||||
if(!download)
|
||||
{
|
||||
// If there is no old news message file, force a new download
|
||||
std::string xml_file = file_manager->getAddonsFile("news.xml");
|
||||
if(!file_manager->fileExists(xml_file))
|
||||
download=true;
|
||||
}
|
||||
|
||||
// Initialise the online portion of the addons manager.
|
||||
if(download && UserConfigParams::logAddons())
|
||||
Log::info("addons", "Downloading list.");
|
||||
|
||||
Request r(Request::HC_DOWNLOAD_FILE, 9999, false,
|
||||
"news.xml", "news.xml");
|
||||
CURLcode status = download ? downloadFileInternal(&r)
|
||||
: CURLE_OK;
|
||||
if(download &&
|
||||
status==CURLE_COULDNT_RESOLVE_HOST)
|
||||
{
|
||||
// Assume that the server address is wrong. And retry
|
||||
// with the default server address again (just in case
|
||||
// that a redirect went wrong, or a wrong/incorrect
|
||||
// address somehow made its way into the config file.
|
||||
UserConfigParams::m_server_addons.revertToDefaults();
|
||||
status = downloadFileInternal(&r);
|
||||
}
|
||||
|
||||
if(status==CURLE_OK)
|
||||
{
|
||||
std::string xml_file = file_manager->getAddonsFile("news.xml");
|
||||
if(download)
|
||||
UserConfigParams::m_news_last_updated = StkTime::getTimeSinceEpoch();
|
||||
const XMLNode *xml = new XMLNode(xml_file);
|
||||
|
||||
// A proper news file has at least a version number, mtime, and
|
||||
// frequency defined. If this is not the case, assume that
|
||||
// it's an invalid download. Try downloading again after
|
||||
// resetting the news server back to the default.
|
||||
int version=-1;
|
||||
if( !xml->get("version", &version) || version!=1 ||
|
||||
!xml->get("mtime", &version) ||
|
||||
!xml->get("frequency", &version) )
|
||||
{
|
||||
UserConfigParams::m_server_addons.revertToDefaults();
|
||||
status = downloadFileInternal(&r);
|
||||
if(status==CURLE_OK)
|
||||
UserConfigParams::m_news_last_updated =
|
||||
StkTime::getTimeSinceEpoch();
|
||||
delete xml;
|
||||
xml = new XMLNode(xml_file);
|
||||
}
|
||||
news_manager->init();
|
||||
#ifdef xx
|
||||
status = loadAddonsList(xml, xml_file, forceRefresh);
|
||||
delete xml;
|
||||
if(status==CURLE_OK)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This message must be translated dynamically in the main menu.
|
||||
// If it would be translated here, it wouldn't be translated
|
||||
// if the language is changed in the menu!
|
||||
error_message=
|
||||
N_("Can't download addons list, check terminal for details.");
|
||||
}
|
||||
// Now fall through to error handling.
|
||||
}
|
||||
else
|
||||
{
|
||||
// This message must be translated dynamically in the main menu.
|
||||
// If it would be translated here, it wouldn't be translated
|
||||
// if the language is changed in the menu!
|
||||
error_message=
|
||||
N_("Can't download news file, check terminal for details.");
|
||||
}
|
||||
|
||||
// Abort requested by stk -> display no error message and return
|
||||
// Abort requested by stk -> display no error message and return
|
||||
if(status==CURLE_ABORTED_BY_CALLBACK)
|
||||
return status;
|
||||
|
||||
addons_manager->setErrorState();
|
||||
news_manager->setErrorMessage(error_message);
|
||||
|
||||
if(UserConfigParams::logAddons())
|
||||
Log::error("addons", "Error raised in NetworkHttp::init : %s", core::stringc(error_message).c_str());
|
||||
return status;
|
||||
#endif
|
||||
return CURLE_OK;
|
||||
} // init
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@ -422,7 +339,7 @@ CURLcode NetworkHttp::loadAddonsList(const XMLNode *xml,
|
||||
if(addon_list_url.size()==0)
|
||||
{
|
||||
file_manager->removeFile(filename);
|
||||
news_manager->addNewsMessage(_("Can't access stkaddons server..."));
|
||||
NewsManager::get()->addNewsMessage(_("Can't access stkaddons server..."));
|
||||
// Use a curl error code here:
|
||||
return CURLE_COULDNT_CONNECT;
|
||||
}
|
||||
@ -451,7 +368,7 @@ CURLcode NetworkHttp::loadAddonsList(const XMLNode *xml,
|
||||
if(download)
|
||||
UserConfigParams::m_addons_last_updated=StkTime::getTimeSinceEpoch();
|
||||
const XMLNode *xml = new XMLNode(xml_file);
|
||||
addons_manager->initOnline(xml);
|
||||
// addons_manager->initOnline(xml);
|
||||
if(UserConfigParams::logAddons())
|
||||
Log::info("addons", "Addons manager list downloaded");
|
||||
return status;
|
||||
|
@ -66,9 +66,6 @@ private:
|
||||
|
||||
static void *mainLoop(void *obj);
|
||||
CURLcode init(bool forceRefresh);
|
||||
CURLcode loadAddonsList(const XMLNode *xml,
|
||||
const std::string &filename,
|
||||
bool forceRefresh);
|
||||
CURLcode downloadFileInternal(Request *request);
|
||||
static int progressDownload(void *clientp, double dltotal, double dlnow,
|
||||
double ultotal, double ulnow);
|
||||
@ -85,6 +82,9 @@ public:
|
||||
int priority = 1,
|
||||
bool manage_memory=true);
|
||||
void cancelAllDownloads();
|
||||
CURLcode loadAddonsList(const XMLNode *xml,
|
||||
const std::string &filename,
|
||||
bool forceRefresh);
|
||||
}; // NetworkHttp
|
||||
|
||||
#endif
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "config/user_config.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "online/http_request.hpp"
|
||||
#include "states_screens/addons_screen.hpp"
|
||||
#include "states_screens/main_menu_screen.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
@ -27,13 +28,14 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
NewsManager *news_manager=NULL;
|
||||
NewsManager *NewsManager::m_news_manager=NULL;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
NewsManager::NewsManager() : m_news(std::vector<NewsMessage>())
|
||||
{
|
||||
m_current_news_message = -1;
|
||||
m_error_message = "";
|
||||
m_error_message.setAtomic("");
|
||||
init(false);
|
||||
} // NewsManage
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@ -41,6 +43,149 @@ NewsManager::~NewsManager()
|
||||
{
|
||||
} // ~NewsManager
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** This function initialises the data for the news manager. If necessary,
|
||||
* it will use a separate thread to download the news.xml file.
|
||||
*/
|
||||
void NewsManager::init(bool force_refresh)
|
||||
{
|
||||
// The rest (which potentially involves downloading news.xml) is handled
|
||||
// in a separate thread, so that the GUI remains responsive.
|
||||
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
// Should be the default, but just in case:
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
||||
//pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
|
||||
|
||||
pthread_t thread_id;
|
||||
int error = pthread_create(&thread_id, &attr,
|
||||
&NewsManager::downloadNews, this);
|
||||
if(error)
|
||||
{
|
||||
Log::warn("news", "Could not create thread, error=%d", errno);
|
||||
// In this case just execute the downloading code with this thread
|
||||
downloadNews(this);
|
||||
}
|
||||
pthread_attr_destroy(&attr);
|
||||
|
||||
} //init
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** This function submits request which will download the news.xml file
|
||||
* if necessary. It is running in its own thread, so we can use blocking
|
||||
* download calls without blocking the GUI.
|
||||
* \param obj This is 'this' object, passed on during pthread creation.
|
||||
*/
|
||||
void* NewsManager::downloadNews(void *obj)
|
||||
{
|
||||
bool force_refresh = false;
|
||||
NewsManager *me = (NewsManager*)obj;
|
||||
me->clearErrorMessage();
|
||||
|
||||
std::string xml_file = file_manager->getAddonsFile("news.xml");
|
||||
bool news_exists = file_manager->fileExists(xml_file);
|
||||
|
||||
// The news message must be updated if either it has never been updated,
|
||||
// or if the time of the last update was more than news_frequency ago,
|
||||
// or because a 'refresh' was explicitly requested by the user, or no
|
||||
// news.xml file exists.
|
||||
bool download = UserConfigParams::m_news_last_updated==0 ||
|
||||
UserConfigParams::m_news_last_updated
|
||||
+UserConfigParams::m_news_frequency
|
||||
< StkTime::getTimeSinceEpoch() ||
|
||||
force_refresh ||
|
||||
!news_exists;
|
||||
|
||||
const XMLNode *xml = NULL;
|
||||
|
||||
if(!download)
|
||||
{
|
||||
// If (so far) we don't need to download, there should be an existing
|
||||
// file. Try to read this, and do some basic checks
|
||||
xml = new XMLNode(xml_file);
|
||||
// A proper news file has at least a version number, mtime, frequency
|
||||
// and an include node (which contains addon data) defined. If this is
|
||||
// not the case, assume that it is an invalid download, or a corrupt
|
||||
// local file. Try downloading again after resetting the news server
|
||||
// back to the default.
|
||||
int version=-1;
|
||||
if( !xml->get("version", &version) || version!=1 ||
|
||||
!xml->get("mtime", &version) ||
|
||||
!xml->getNode("include") ||
|
||||
!xml->get("frequency", &version) )
|
||||
{
|
||||
delete xml;
|
||||
xml = NULL;
|
||||
download = true;
|
||||
} // if xml not consistemt
|
||||
} // if !download
|
||||
|
||||
if(download)
|
||||
{
|
||||
core::stringw error_message("");
|
||||
|
||||
Online::HTTPRequest *download_req = new Online::HTTPRequest("news.xml");
|
||||
download_req->setAddonsURL("news.xml");
|
||||
// Initialise the online portion of the addons manager.
|
||||
if(UserConfigParams::logAddons())
|
||||
Log::info("addons", "Downloading news.");
|
||||
download_req->executeNow();
|
||||
|
||||
if(download_req->hadDownloadError())
|
||||
{
|
||||
// Assume that the server address is wrong. And retry
|
||||
// with the default server address again (just in case
|
||||
// that a redirect went wrong, or a wrong/incorrect
|
||||
// address somehow made its way into the config file.
|
||||
delete download_req;
|
||||
// We need a new object, since the state of the old
|
||||
// download request is now done.
|
||||
download_req = new Online::HTTPRequest("news.xml");
|
||||
UserConfigParams::m_server_addons.revertToDefaults();
|
||||
// make sure the new server address is actually used
|
||||
download_req->setAddonsURL("news.xml");
|
||||
download_req->executeNow();
|
||||
|
||||
if(download_req->hadDownloadError())
|
||||
{
|
||||
// This message must be translated dynamically in the main menu.
|
||||
// If it would be translated here, it wouldn't be translated
|
||||
// if the language is changed in the menu!
|
||||
error_message = N_("Error downloading news: '%s'.");
|
||||
const char *const curl_error = download_req->getDownloadErrorMessage();
|
||||
error_message = StringUtils::insertValues(error_message, curl_error);
|
||||
addons_manager->setErrorState();
|
||||
me->setErrorMessage(error_message);
|
||||
Log::error("news", core::stringc(error_message).c_str());
|
||||
} // hadDownloadError
|
||||
} // hadDownloadError
|
||||
|
||||
if(!download_req->hadDownloadError())
|
||||
UserConfigParams::m_news_last_updated = StkTime::getTimeSinceEpoch();
|
||||
delete download_req;
|
||||
|
||||
// No download error, update the last_updated time value, and delete
|
||||
// the potentially loaded xml file
|
||||
delete xml;
|
||||
xml = NULL;
|
||||
} // hadDownloadError
|
||||
|
||||
// Process new.xml now.
|
||||
if(file_manager->fileExists(xml_file))
|
||||
{
|
||||
xml = new XMLNode(xml_file);
|
||||
me->checkRedirect(xml);
|
||||
me->updateNews(xml, xml_file);
|
||||
addons_manager->init(xml, force_refresh);
|
||||
delete xml;
|
||||
}
|
||||
|
||||
pthread_exit(NULL);
|
||||
return 0; // prevent warning
|
||||
} // downloadNews
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Initialises the online part of the network manager. It downloads the
|
||||
* news.xml file from the server (if the frequency of downloads makes this
|
||||
@ -48,16 +193,6 @@ NewsManager::~NewsManager()
|
||||
* \return 0 if an error happened and no online connection will be available,
|
||||
* 1 otherwise.
|
||||
*/
|
||||
void NewsManager::init()
|
||||
{
|
||||
UserConfigParams::m_news_last_updated = StkTime::getTimeSinceEpoch();
|
||||
|
||||
std::string xml_file = file_manager->getAddonsFile("news.xml");
|
||||
const XMLNode *xml = new XMLNode(xml_file);
|
||||
checkRedirect(xml);
|
||||
updateNews(xml, xml_file);
|
||||
delete xml;
|
||||
} // init
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Checks if a redirect is received, causing a new server to be used for
|
||||
@ -210,8 +345,8 @@ const core::stringw NewsManager::getImportantMessage()
|
||||
const core::stringw NewsManager::getNextNewsMessage()
|
||||
{
|
||||
// Only display error message in case of a problem.
|
||||
if(m_error_message.size()>0)
|
||||
return _(m_error_message.c_str());
|
||||
if(m_error_message.getAtomic().size()>0)
|
||||
return _(m_error_message.getAtomic().c_str());
|
||||
|
||||
m_news.lock();
|
||||
if(m_all_news_messages.size()>0)
|
||||
|
@ -35,6 +35,8 @@ class XMLNode;
|
||||
class NewsManager
|
||||
{
|
||||
private:
|
||||
static NewsManager *m_news_manager;
|
||||
|
||||
// A wrapper class to store news message together with
|
||||
// a message id and a display count.
|
||||
class NewsMessage
|
||||
@ -87,28 +89,50 @@ private:
|
||||
|
||||
/** A high priority error message that is shown instead of
|
||||
* any news message (usually indicating connection problems). */
|
||||
core::stringw m_error_message;
|
||||
Synchronised<core::stringw> m_error_message;
|
||||
|
||||
void checkRedirect(const XMLNode *xml);
|
||||
void updateNews(const XMLNode *xml,
|
||||
const std::string &filename);
|
||||
bool conditionFulfilled(const std::string &cond);
|
||||
static void* downloadNews(void *obj);
|
||||
NewsManager();
|
||||
~NewsManager();
|
||||
|
||||
public:
|
||||
NewsManager();
|
||||
~NewsManager();
|
||||
/** Singleton: if necessary create and get the news managers */
|
||||
static NewsManager* get()
|
||||
{
|
||||
if(!m_news_manager)
|
||||
m_news_manager = new NewsManager();
|
||||
return m_news_manager;
|
||||
} //
|
||||
// ------------------------------------------------------------------------
|
||||
static void deallocate()
|
||||
{
|
||||
if(m_news_manager)
|
||||
{
|
||||
delete m_news_manager;
|
||||
m_news_manager = NULL;
|
||||
}
|
||||
} // deallocate
|
||||
// ------------------------------------------------------------------------
|
||||
const core::stringw
|
||||
getNextNewsMessage();
|
||||
const core::stringw
|
||||
getImportantMessage();
|
||||
void init();
|
||||
void init(bool force_refresh);
|
||||
void addNewsMessage(const core::stringw &s);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets an error message that is displayed instead of any news message. */
|
||||
void setErrorMessage(const core::stringw &s) { m_error_message=s;}
|
||||
void setErrorMessage(const core::stringw &s)
|
||||
{
|
||||
m_error_message.setAtomic(s);
|
||||
} // setErrorMessage
|
||||
// ------------------------------------------------------------------------
|
||||
/** Clears the error message. */
|
||||
void clearErrorMessage() {m_error_message=""; }
|
||||
void clearErrorMessage() {m_error_message.setAtomic(""); }
|
||||
// ------------------------------------------------------------------------
|
||||
}; // NewsManager
|
||||
|
||||
|
@ -1018,10 +1018,10 @@ void initRest()
|
||||
// This only initialises the non-network part of the addons manager. The
|
||||
// online section of the addons manager will be initialised from a
|
||||
// separate thread running in network http.
|
||||
news_manager = new NewsManager();
|
||||
addons_manager = new AddonsManager();
|
||||
|
||||
INetworkHttp::create();
|
||||
NewsManager::get(); // this will create the news manager
|
||||
|
||||
// Note that the network thread must be started after the assignment
|
||||
// to network_http (since the thread might use network_http, otherwise
|
||||
@ -1099,7 +1099,7 @@ static void cleanSuperTuxKart()
|
||||
if(ReplayPlay::get()) ReplayPlay::destroy();
|
||||
if(race_manager) delete race_manager;
|
||||
INetworkHttp::destroy();
|
||||
if(news_manager) delete news_manager;
|
||||
NewsManager::deallocate();
|
||||
if(addons_manager) delete addons_manager;
|
||||
NetworkManager::kill();
|
||||
|
||||
@ -1252,7 +1252,7 @@ int main(int argc, char *argv[] )
|
||||
std::string xml_file = file_manager->getAddonsFile("addons.xml");
|
||||
if (file_manager->fileExists(xml_file)) {
|
||||
const XMLNode *xml = new XMLNode (xml_file);
|
||||
addons_manager->initOnline(xml);
|
||||
addons_manager->initAddons(xml);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1354,7 +1354,7 @@ int main(int argc, char *argv[] )
|
||||
|
||||
// If an important news message exists it is shown in a popup dialog.
|
||||
const core::stringw important_message =
|
||||
news_manager->getImportantMessage();
|
||||
NewsManager::get()->getImportantMessage();
|
||||
if(important_message!="")
|
||||
{
|
||||
new MessageDialog(important_message,
|
||||
|
@ -30,32 +30,66 @@
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
namespace Online{
|
||||
|
||||
namespace Online
|
||||
{
|
||||
/** Creates a HTTP(S) request that will have a raw string as result. (Can
|
||||
* of course be used if the result doesn't matter.)
|
||||
* \param manage_memory whether or not the HTTPManager should take care of
|
||||
* \param manage_memory whether or not the RequestManager should take care of
|
||||
* deleting the object after all callbacks have been done.
|
||||
* \param priority by what priority should the HTTPManager take care of
|
||||
* \param priority by what priority should the RequestManager take care of
|
||||
* this request.
|
||||
*/
|
||||
HTTPRequest::HTTPRequest(bool manage_memory, int priority)
|
||||
: Request(manage_memory, priority, 0)
|
||||
{
|
||||
m_url = "";
|
||||
m_string_buffer = "";
|
||||
m_parameters = new Parameters();
|
||||
m_progress.setAtomic(0);
|
||||
init();
|
||||
} // HTTPRequest
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
HTTPRequest::~HTTPRequest()
|
||||
/** This constructor configures this request to save the data in a flie.
|
||||
* \param filename Name of the file to save the data to.
|
||||
* \param manage_memory whether or not the RequestManager should take care of
|
||||
* deleting the object after all callbacks have been done.
|
||||
* \param priority by what priority should the RequestManager take care of
|
||||
* this request.
|
||||
*/
|
||||
HTTPRequest::HTTPRequest(const std::string &filename, bool manage_memory,
|
||||
int priority)
|
||||
: Request(manage_memory, priority, 0)
|
||||
{
|
||||
delete m_parameters;
|
||||
} // ~HTTPRequest
|
||||
assert(filename.size()>0);
|
||||
init();
|
||||
m_filename = file_manager->getAddonsFile(filename);
|
||||
} // HTTPRequest(filename ...)
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** A handy shortcut that appends the given path to the URL of the server.
|
||||
/** Char * needs a separate constructor, otherwise it will be considered
|
||||
* to be the no-filename constructor (char* -> bool).
|
||||
*/
|
||||
HTTPRequest::HTTPRequest(const char* const filename, bool manage_memory,
|
||||
int priority)
|
||||
: Request(manage_memory, priority, 0)
|
||||
{
|
||||
init();
|
||||
m_filename = file_manager->getAddonsFile(filename);
|
||||
} // HTTPRequest(filename ...)
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Initialises all member variables.
|
||||
*/
|
||||
void HTTPRequest::init()
|
||||
{
|
||||
m_url = "";
|
||||
m_string_buffer = "";
|
||||
m_filename = "";
|
||||
m_parameters = "";
|
||||
m_curl_code = CURLE_OK;
|
||||
m_progress.setAtomic(0);
|
||||
} // init
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** A handy shortcut that appends the given path to the URL of the
|
||||
* mutiplayer server.
|
||||
* \param path The path to add to the server.
|
||||
*/
|
||||
void HTTPRequest::setServerURL(const std::string& path)
|
||||
@ -63,6 +97,16 @@ namespace Online{
|
||||
setURL((std::string)UserConfigParams::m_server_multiplayer+path);
|
||||
} // setServerURL
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** A handy shortcut that appends the given path to the URL of the addons
|
||||
* server.
|
||||
* \param path The path to add to the server.
|
||||
*/
|
||||
void HTTPRequest::setAddonsURL(const std::string& path)
|
||||
{
|
||||
setURL((std::string)UserConfigParams::m_server_addons
|
||||
+ "/" + path);
|
||||
} // set AddonsURL
|
||||
// ------------------------------------------------------------------------
|
||||
/** Checks the request if it has enough (correct) information to be
|
||||
* executed (and thus allowed to add to the queue).
|
||||
@ -84,10 +128,9 @@ namespace Online{
|
||||
"LibCurl session not initialized.");
|
||||
return;
|
||||
}
|
||||
|
||||
curl_easy_setopt(m_curl_session, CURLOPT_URL, m_url.c_str());
|
||||
curl_easy_setopt(m_curl_session, CURLOPT_FOLLOWLOCATION, 1);
|
||||
curl_easy_setopt(m_curl_session, CURLOPT_WRITEFUNCTION,
|
||||
&HTTPRequest::writeCallback);
|
||||
curl_easy_setopt(m_curl_session, CURLOPT_NOPROGRESS, 0);
|
||||
curl_easy_setopt(m_curl_session, CURLOPT_PROGRESSDATA, this);
|
||||
curl_easy_setopt(m_curl_session, CURLOPT_PROGRESSFUNCTION,
|
||||
@ -95,15 +138,17 @@ namespace Online{
|
||||
curl_easy_setopt(m_curl_session, CURLOPT_CONNECTTIMEOUT, 20);
|
||||
curl_easy_setopt(m_curl_session, CURLOPT_LOW_SPEED_LIMIT, 10);
|
||||
curl_easy_setopt(m_curl_session, CURLOPT_LOW_SPEED_TIME, 20);
|
||||
//https
|
||||
struct curl_slist *chunk = NULL;
|
||||
chunk = curl_slist_append(chunk, "Host: api.stkaddons.net");
|
||||
curl_easy_setopt(m_curl_session, CURLOPT_HTTPHEADER, chunk);
|
||||
curl_easy_setopt(m_curl_session, CURLOPT_CAINFO,
|
||||
(file_manager->getAsset("web.tuxfamily.org.pem")).c_str());
|
||||
curl_easy_setopt(m_curl_session, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||
//curl_easy_setopt(m_curl_session, CURLOPT_VERBOSE, 1L);
|
||||
curl_easy_setopt(m_curl_session, CURLOPT_WRITEDATA, &m_string_buffer);
|
||||
if(m_filename.size()==0)
|
||||
{
|
||||
//https
|
||||
struct curl_slist *chunk = NULL;
|
||||
chunk = curl_slist_append(chunk, "Host: api.stkaddons.net");
|
||||
curl_easy_setopt(m_curl_session, CURLOPT_HTTPHEADER, chunk);
|
||||
curl_easy_setopt(m_curl_session, CURLOPT_CAINFO,
|
||||
file_manager->getAsset("web.tuxfamily.org.pem").c_str());
|
||||
curl_easy_setopt(m_curl_session, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||
//curl_easy_setopt(m_curl_session, CURLOPT_VERBOSE, 1L);
|
||||
}
|
||||
} // prepareOperation
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
@ -113,28 +158,38 @@ namespace Online{
|
||||
{
|
||||
if(!m_curl_session)
|
||||
return;
|
||||
Parameters::iterator iter;
|
||||
std::string postString("");
|
||||
for (iter = m_parameters->begin(); iter != m_parameters->end(); ++iter)
|
||||
|
||||
FILE *fout = NULL;
|
||||
if(m_filename.size()>0)
|
||||
{
|
||||
if(iter != m_parameters->begin())
|
||||
postString.append("&");
|
||||
char* escaped = curl_easy_escape(m_curl_session ,
|
||||
iter->first.c_str(),
|
||||
iter->first.size());
|
||||
postString.append(escaped);
|
||||
curl_free(escaped);
|
||||
postString.append("=");
|
||||
escaped = curl_easy_escape(m_curl_session,
|
||||
iter->second.c_str(),
|
||||
iter->second.size());
|
||||
postString.append(escaped);
|
||||
curl_free(escaped);
|
||||
fout = fopen((m_filename+".part").c_str(), "wb");
|
||||
|
||||
if(!fout)
|
||||
{
|
||||
Log::error("HTTPRequest",
|
||||
"Can't open '%s' for writing, ignored.",
|
||||
(m_filename+".part").c_str());
|
||||
return;
|
||||
}
|
||||
curl_easy_setopt(m_curl_session, CURLOPT_WRITEDATA, fout );
|
||||
curl_easy_setopt(m_curl_session, CURLOPT_WRITEFUNCTION, fwrite);
|
||||
}
|
||||
Log::info("HTTPRequest::operation", "Sending : %s",
|
||||
postString.c_str());
|
||||
else
|
||||
{
|
||||
curl_easy_setopt(m_curl_session, CURLOPT_WRITEDATA,
|
||||
&m_string_buffer);
|
||||
curl_easy_setopt(m_curl_session, CURLOPT_WRITEFUNCTION,
|
||||
&HTTPRequest::writeCallback);
|
||||
}
|
||||
|
||||
// All parameters added have a '&' added
|
||||
if(m_parameters.size()>0)
|
||||
m_parameters.pop_back();
|
||||
|
||||
Log::info("HTTPRequest", "Sending %s to %s",
|
||||
m_parameters.c_str(), m_url.c_str());
|
||||
curl_easy_setopt(m_curl_session, CURLOPT_POSTFIELDS,
|
||||
postString.c_str());
|
||||
m_parameters.c_str());
|
||||
std::string uagent( std::string("SuperTuxKart/") + STK_VERSION );
|
||||
#ifdef WIN32
|
||||
uagent += (std::string)" (Windows)";
|
||||
@ -151,6 +206,28 @@ namespace Online{
|
||||
|
||||
m_curl_code = curl_easy_perform(m_curl_session);
|
||||
Request::operation();
|
||||
|
||||
if(fout)
|
||||
{
|
||||
fclose(fout);
|
||||
if(m_curl_code==CURLE_OK)
|
||||
{
|
||||
if(UserConfigParams::logAddons())
|
||||
Log::info("HTTPRequest", "Download successful.");
|
||||
// The behaviour of rename is unspecified if the target
|
||||
// file should already exist - so remove it.
|
||||
file_manager->removeFile(m_filename);
|
||||
int ret = rename((m_filename+".part").c_str(),
|
||||
m_filename.c_str() );
|
||||
// In case of an error, set the status to indicate this
|
||||
if(ret!=0)
|
||||
{
|
||||
if(UserConfigParams::logAddons())
|
||||
Log::error("addons", "Could not rename downloaded file!");
|
||||
m_curl_code = CURLE_WRITE_ERROR;
|
||||
}
|
||||
} // m_curl_code ==CURLE_OK
|
||||
} // if fout
|
||||
} // operation
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
@ -229,4 +306,5 @@ namespace Online{
|
||||
} // progressDownload
|
||||
|
||||
|
||||
|
||||
} // namespace Online
|
||||
|
@ -39,8 +39,6 @@ namespace Online
|
||||
class HTTPRequest : public Request
|
||||
{
|
||||
private:
|
||||
typedef std::map<std::string, std::string> Parameters;
|
||||
|
||||
/** The progress indicator. 0 untill it is started and the first
|
||||
* packet is downloaded. Guaranteed to be <1 while the download
|
||||
* is in progress, it will be set to either -1 (error) or 1
|
||||
@ -51,7 +49,11 @@ namespace Online
|
||||
std::string m_url;
|
||||
|
||||
/** The POST parameters that will be send with the request. */
|
||||
Parameters *m_parameters;
|
||||
std::string m_parameters;
|
||||
|
||||
/** Contains a filename if the data should be saved into a file
|
||||
* instead of being kept in in memory. Otherwise this is "". */
|
||||
std::string m_filename;
|
||||
|
||||
/** Pointer to the curl data structure for this request. */
|
||||
CURL *m_curl_session;
|
||||
@ -73,18 +75,35 @@ namespace Online
|
||||
|
||||
static size_t writeCallback(void *contents, size_t size,
|
||||
size_t nmemb, void *userp);
|
||||
|
||||
void init();
|
||||
|
||||
public :
|
||||
HTTPRequest(bool manage_memory = false,
|
||||
int priority = 1);
|
||||
virtual ~HTTPRequest();
|
||||
HTTPRequest(const std::string &filename,
|
||||
bool manage_memory = false,
|
||||
int priority = 1);
|
||||
HTTPRequest(const char * const filename,
|
||||
bool manage_memory = false,
|
||||
int priority = 1);
|
||||
virtual ~HTTPRequest() {};
|
||||
virtual bool isAllowedToAdd() OVERRIDE;
|
||||
void setServerURL(const std::string& url);
|
||||
void setAddonsURL(const std::string& path);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the curl error status of the request.
|
||||
/** Returns true if there was an error downloading the file.
|
||||
*/
|
||||
CURLcode getResult() const { return m_curl_code; }
|
||||
bool hadDownloadError() const { return m_curl_code!=CURLE_OK; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the curl error message if an error has occurred.
|
||||
* \pre m_curl_code!=CURLE_OK
|
||||
*/
|
||||
const char* getDownloadErrorMessage() const
|
||||
{
|
||||
assert(hadDownloadError());
|
||||
return curl_easy_strerror(m_curl_code);
|
||||
} // getDownloadErrorMessage
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the downloaded string.
|
||||
* \pre request has to be done
|
||||
@ -101,8 +120,8 @@ namespace Online
|
||||
*/
|
||||
void addParameter(const std::string & name, const std::string &value)
|
||||
{
|
||||
assert(isPreparing());
|
||||
(*m_parameters)[name] = value;
|
||||
// Call the template, so that the strings are escaped properly
|
||||
addParameter(name, value.c_str());
|
||||
}; // addParameter
|
||||
// --------------------------------------------------------------------
|
||||
/** Sets a parameter to 'value' (stringw).
|
||||
@ -110,16 +129,25 @@ namespace Online
|
||||
void addParameter(const std::string & name,
|
||||
const irr::core::stringw &value)
|
||||
{
|
||||
assert(isPreparing());
|
||||
(*m_parameters)[name] = irr::core::stringc(value.c_str()).c_str();
|
||||
core::stringc s = core::stringc(value.c_str());
|
||||
// Call the template to escape strings properly
|
||||
addParameter(name, s.c_str());
|
||||
} // addParameter
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/** Sets a parameter to 'value' (arbitrary types).
|
||||
*/
|
||||
template <typename T>
|
||||
void addParameter(const std::string & name, const T& value){
|
||||
void addParameter(const std::string & name, const T& value)
|
||||
{
|
||||
assert(isPreparing());
|
||||
(*m_parameters)[name] = StringUtils::toString(value);
|
||||
std::string s = StringUtils::toString(value);
|
||||
char *s1 = curl_easy_escape(m_curl_session, name.c_str(),
|
||||
name.size() );
|
||||
char *s2 = curl_easy_escape(m_curl_session, s.c_str(), s.size());
|
||||
m_parameters.append(std::string(s1)+"="+s2+"&");
|
||||
curl_free(s1);
|
||||
curl_free(s2);
|
||||
} // addParameter
|
||||
// --------------------------------------------------------------------
|
||||
/** Returns the current progress. */
|
||||
|
@ -46,6 +46,14 @@ namespace Online
|
||||
m_state.setAtomic(S_PREPARING);
|
||||
} // Request
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Inserts this request into the RequestManager's queue for executing.
|
||||
*/
|
||||
void Request::queue()
|
||||
{
|
||||
RequestManager::get()->addRequest(this);
|
||||
} // queue
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Executes the request. This calles prepareOperation, operation, and
|
||||
* afterOperation.
|
||||
|
@ -124,6 +124,7 @@ namespace Online
|
||||
virtual ~Request() {}
|
||||
void execute();
|
||||
void executeNow();
|
||||
void queue();
|
||||
// --------------------------------------------------------------------
|
||||
/** Executed when a request has finished. */
|
||||
virtual void callback() {}
|
||||
|
@ -1,8 +1,8 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2010 Lucas Baudin
|
||||
// 2011 Joerg Henrichs
|
||||
// 2013 Glenn De Jonghe
|
||||
// Copyright (C) 2010-2014 Lucas Baudin
|
||||
// 2011-201 Joerg Henrichs
|
||||
// 2013-2014 Glenn De Jonghe
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -61,10 +61,10 @@ namespace Online
|
||||
void XMLRequest::afterOperation()
|
||||
{
|
||||
m_xml_data = file_manager->createXMLTreeFromString(getData());
|
||||
if(getResult() != CURLE_OK)
|
||||
if(hadDownloadError())
|
||||
Log::error("XMLRequest::afterOperation",
|
||||
"curl_easy_perform() failed: %s",
|
||||
curl_easy_strerror(getResult()));
|
||||
getDownloadErrorMessage());
|
||||
m_success = false;
|
||||
std::string rec_success;
|
||||
if(m_xml_data->get("success", &rec_success))
|
||||
|
@ -112,7 +112,7 @@ void MainMenuScreen::init()
|
||||
|
||||
|
||||
LabelWidget* w = getWidget<LabelWidget>("info_addons");
|
||||
const core::stringw &news_text = news_manager->getNextNewsMessage();
|
||||
const core::stringw &news_text = NewsManager::get()->getNextNewsMessage();
|
||||
w->setText(news_text, true);
|
||||
w->update(0.01f);
|
||||
|
||||
@ -165,7 +165,7 @@ void MainMenuScreen::onUpdate(float delta, irr::video::IVideoDriver* driver)
|
||||
w->update(delta);
|
||||
if(w->scrolledOff())
|
||||
{
|
||||
const core::stringw &news_text = news_manager->getNextNewsMessage();
|
||||
const core::stringw &news_text = NewsManager::get()->getNextNewsMessage();
|
||||
w->setText(news_text, true);
|
||||
}
|
||||
} // onUpdate
|
||||
|
Loading…
x
Reference in New Issue
Block a user