diff --git a/pokerth_game.pro b/pokerth_game.pro index 94f05ecb..4d08bda0 100644 --- a/pokerth_game.pro +++ b/pokerth_game.pro @@ -7,8 +7,8 @@ isEmpty( PREFIX ){ TEMPLATE = app CODECFORSRC = UTF-8 -CONFIG += qt thread embed_manifest_exe exceptions rtti stl warn_on release -#CONFIG += qt thread embed_manifest_exe exceptions rtti stl warn_on debug +#CONFIG += qt thread embed_manifest_exe exceptions rtti stl warn_on release +CONFIG += qt thread embed_manifest_exe exceptions rtti stl warn_on debug #####Uncomment this for RELEASE #QTPLUGIN += qjpeg qgif diff --git a/pokerth_lib.pro b/pokerth_lib.pro index 28cfe2dd..97c88aaa 100644 --- a/pokerth_lib.pro +++ b/pokerth_lib.pro @@ -3,8 +3,8 @@ TEMPLATE = lib CODECFORSRC = UTF-8 -CONFIG += staticlib thread exceptions rtti stl warn_on release -#CONFIG += staticlib thread exceptions rtti stl warn_on debug +#CONFIG += staticlib thread exceptions rtti stl warn_on release +CONFIG += staticlib thread exceptions rtti stl warn_on debug UI_DIR = uics TARGET = lib/pokerth_lib @@ -88,6 +88,8 @@ HEADERS += \ src/net/transferhelper.h \ src/net/uploaderthread.h \ src/net/uploadhelper.h \ + src/net/downloaderthread.h \ + src/net/downloadhelper.h \ src/third_party/tinyxml/tinystr.h \ src/third_party/tinyxml/tinyxml.h \ src/third_party/libircclient/include/libircclient.h \ @@ -159,6 +161,7 @@ SOURCES += \ src/net/common/clientstate.cpp \ src/net/common/clientthread.cpp \ src/net/common/downloadhelper.cpp \ + src/net/common/downloaderthread.cpp \ src/net/common/netpacket.cpp \ src/net/common/resolverthread.cpp \ src/net/common/senderinterface.cpp \ diff --git a/pokerth_server.pro b/pokerth_server.pro index 53a64cc2..a69abd62 100644 --- a/pokerth_server.pro +++ b/pokerth_server.pro @@ -7,8 +7,8 @@ isEmpty( PREFIX ){ TEMPLATE = app CODECFORSRC = UTF-8 -CONFIG += thread console embed_manifest_exe exceptions rtti stl warn_on release -#CONFIG += thread console embed_manifest_exe exceptions rtti stl warn_on debug +#CONFIG += thread console embed_manifest_exe exceptions rtti stl warn_on release +CONFIG += thread console embed_manifest_exe exceptions rtti stl warn_on debug UI_DIR = uics TARGET = bin/pokerth_server diff --git a/src/net/clientthread.h b/src/net/clientthread.h index f1d436d3..edda11cc 100644 --- a/src/net/clientthread.h +++ b/src/net/clientthread.h @@ -32,6 +32,7 @@ class ClientContext; class ClientState; class SenderThread; class ReceiverHelper; +class DownloaderThread; class ClientSenderCallback; class Game; class NetPacket; @@ -173,6 +174,8 @@ private: boost::shared_ptr m_receiver; + boost::shared_ptr m_avatarDownloader; + GameData m_gameData; StartData m_startData; PlayerDataList m_playerDataList; diff --git a/src/net/common/clientstate.cpp b/src/net/common/clientstate.cpp index 414b9b74..93a6fe8b 100644 --- a/src/net/common/clientstate.cpp +++ b/src/net/common/clientstate.cpp @@ -460,7 +460,7 @@ ClientStateReadingServerList::Process(ClientThread &client) const TiXmlNode *portNode = firstServer->FirstChild("Port"); // Currently, only IPv4 is supported for avatar servers. - const TiXmlNode *avatarNode = firstServer->FirstChild("AvatarServerIPv4Address"); + const TiXmlNode *avatarNode = firstServer->FirstChild("AvatarServerAddress"); if (!addrNode || !addrNode->ToElement() || !portNode || !portNode->ToElement()) throw ClientException(__FILE__, __LINE__, ERR_SOCK_INVALID_SERVERLIST_XML, 0); diff --git a/src/net/common/clientthread.cpp b/src/net/common/clientthread.cpp index 069207c5..d678fbc3 100644 --- a/src/net/common/clientthread.cpp +++ b/src/net/common/clientthread.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,8 @@ #include #include +#define TEMP_AVATAR_FILENAME "avatar.tmp" + using namespace std; @@ -331,6 +334,11 @@ ClientThread::GetAvatarManager() void ClientThread::Main() { + if (!GetContext().GetAvatarServerAddr().empty()) + { + m_avatarDownloader.reset(new DownloaderThread); + m_avatarDownloader->Run(); + } SetState(CLIENT_INITIAL_STATE::Instance()); try @@ -368,6 +376,12 @@ ClientThread::Main() { GetCallback().SignalNetClientError(e.GetErrorId(), e.GetOsErrorCode()); } + if (m_avatarDownloader) + { + m_avatarDownloader->SignalTermination(); + m_avatarDownloader->Join(DOWNLOADER_THREAD_TERMINATE_TIMEOUT); + m_avatarDownloader.reset(); + } } void @@ -520,13 +534,22 @@ ClientThread::RetrieveAvatarIfNeeded(unsigned id, const PlayerInfo &info) { m_avatarHasRequestedList.push_back(id); // Never remove from this list. Only request once. - // TODO: download from avatar server if applicable. - boost::shared_ptr retrieveAvatar(new NetPacketRetrieveAvatar); - NetPacketRetrieveAvatar::Data retrieveAvatarData; - retrieveAvatarData.requestId = id; - retrieveAvatarData.avatar = info.avatar; - static_cast(retrieveAvatar.get())->SetData(retrieveAvatarData); - GetContext().GetSessionData()->GetSender().Send(GetContext().GetSessionData(), retrieveAvatar); + // Download from avatar server if applicable. + string avatarServerAddress(GetContext().GetAvatarServerAddr()); + if (!avatarServerAddress.empty() && m_avatarDownloader) + { + string filename(TEMP_AVATAR_FILENAME); + m_avatarDownloader->QueueDownload(id, avatarServerAddress + filename, GetContext().GetCacheDir() + filename); + } + else + { + boost::shared_ptr retrieveAvatar(new NetPacketRetrieveAvatar); + NetPacketRetrieveAvatar::Data retrieveAvatarData; + retrieveAvatarData.requestId = id; + retrieveAvatarData.avatar = info.avatar; + static_cast(retrieveAvatar.get())->SetData(retrieveAvatarData); + GetContext().GetSessionData()->GetSender().Send(GetContext().GetSessionData(), retrieveAvatar); + } } } } diff --git a/src/net/common/downloaderthread.cpp b/src/net/common/downloaderthread.cpp new file mode 100644 index 00000000..e2d1aba5 --- /dev/null +++ b/src/net/common/downloaderthread.cpp @@ -0,0 +1,124 @@ +/*************************************************************************** + * Copyright (C) 2009 by Lothar May * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include +#include +#include +#include +#include + +#include + +#define DOWNLOAD_DELAY_MSEC 10 + +using namespace std; +using namespace boost::filesystem; + + +DownloaderThread::DownloaderThread() +: m_downloadInProgress(false) +{ + m_downloadHelper.reset(new DownloadHelper()); +} + +DownloaderThread::~DownloaderThread() +{ +} + +void +DownloaderThread::QueueDownload(unsigned downloadId, const std::string &url, const std::string &filename) +{ + boost::mutex::scoped_lock lock(m_downloadQueueMutex); + m_downloadQueue.push(DownloadData(downloadId, url, filename)); +} + +bool +DownloaderThread::PollDownloadResult(unsigned &downloadId, std::vector &filedata) +{ + bool result = false; + boost::mutex::scoped_lock lock(m_downloadDoneQueueMutex); + if (!m_downloadDoneQueue.empty()) + { + const ResultData &d = m_downloadDoneQueue.front(); + downloadId = d.id; + filedata = d.data; + m_downloadDoneQueue.pop(); + result = true; + } + return result; +} + +void +DownloaderThread::Main() +{ + while (!ShouldTerminate()) + { + try + { + if (m_downloadInProgress) + { + m_downloadInProgress = !m_downloadHelper->Process(); + } + + if (!m_downloadInProgress) + { + // Previous download was finished. + if (m_curDownloadData) + { + path filepath(m_curDownloadData->filename); + ifstream instream(filepath.file_string().c_str(), ios_base::in | ios_base::binary); + vector fileData; + copy(istream_iterator(instream), istream_iterator(), back_inserter(fileData)); + instream.close(); + remove(filepath); + + { + boost::mutex::scoped_lock lock(m_downloadDoneQueueMutex); + m_downloadDoneQueue.push(ResultData(m_curDownloadData->id, fileData)); + } + m_curDownloadData.reset(); + } + + // Take a break. + Msleep(DOWNLOAD_DELAY_MSEC); + + // Start next download. + { + boost::mutex::scoped_lock lock(m_downloadQueueMutex); + if (!m_downloadQueue.empty()) + { + m_curDownloadData.reset(new DownloadData(m_downloadQueue.front())); + m_downloadQueue.pop(); + } + } + if (m_curDownloadData && !m_curDownloadData->filename.empty()) + { + path filepath(m_curDownloadData->filename); + m_downloadHelper->Init(m_curDownloadData->address, filepath.file_string().c_str()); + m_downloadInProgress = true; + } + } + } + catch (const NetException &e) + { + LOG_ERROR(e.what()); + } + } +} + diff --git a/src/net/downloaderthread.h b/src/net/downloaderthread.h new file mode 100644 index 00000000..c26b753e --- /dev/null +++ b/src/net/downloaderthread.h @@ -0,0 +1,85 @@ +/*************************************************************************** + * Copyright (C) 2009 by Lothar May * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +/* Network file download thread. */ + +#ifndef _DOWNLOADERTHREAD_H_ +#define _DOWNLOADERTHREAD_H_ + +#include + +#include +#include +#include + +#define DOWNLOADER_THREAD_TERMINATE_TIMEOUT THREAD_WAIT_INFINITE +class DownloadHelper; + +class DownloaderThread : public Thread +{ +public: + + DownloaderThread(); + virtual ~DownloaderThread(); + + void QueueDownload(unsigned downloadId, const std::string &url, const std::string &filename); + bool PollDownloadResult(unsigned &downloadId, std::vector &filedata); + +protected: + struct DownloadData + { + DownloadData() : id(0) {} + DownloadData(unsigned i, const std::string &a, const std::string &f) + : id(i), address(a), filename(f) {} + + unsigned id; + std::string address; + std::string filename; + }; + struct ResultData + { + ResultData() : id(0) {} + ResultData(unsigned i, const std::vector &d) + : id(i), data(d) {} + + unsigned id; + std::vector data; + }; + + typedef std::queue DownloadDataQueue; + typedef std::queue DownloadDoneQueue; + + // Main function of the thread. + virtual void Main(); + +private: + + DownloadDataQueue m_downloadQueue; + mutable boost::mutex m_downloadQueueMutex; + + DownloadDoneQueue m_downloadDoneQueue; + mutable boost::mutex m_downloadDoneQueueMutex; + + boost::shared_ptr m_downloadHelper; + bool m_downloadInProgress; + + boost::shared_ptr m_curDownloadData; +}; + +#endif + diff --git a/src/session.cpp b/src/session.cpp index 4f7aff83..77270d06 100755 --- a/src/session.cpp +++ b/src/session.cpp @@ -32,7 +32,7 @@ #include -#define NET_CLIENT_TERMINATE_TIMEOUT_MSEC 1000 +#define NET_CLIENT_TERMINATE_TIMEOUT_MSEC 2000 #define NET_IRC_TERMINATE_TIMEOUT_MSEC 2000 #define NET_DEFAULT_GAME "default"