Linux multi-monitor fullscreen support
[ryzomcore.git] / ryzom / client / src / login_progress_post_thread.cpp
blob8673f77a6d5da2de4688174503305923e3d473b2
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2016 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "stdpch.h"
21 #include "login_progress_post_thread.h"
22 #include "game_share/login_registry.h"
23 #include "nel/misc/system_info.h"
26 using namespace NLMISC;
31 ///////////////////////
32 // Utility functions //
33 ///////////////////////
36 //===========================================================================================
37 static std::string uint64ToHex(uint64 size)
39 char data[256];
40 sprintf(data, "%" NL_I64 "X", size);
41 return std::string(data);
44 //===========================================================================================
45 static std::string sizeToHumanStd(uint64 size)
47 double total = (double) size;
48 std::string unit;
49 if (total >= 1024.0*1024.0*1024.0)
51 total /= 1024.0*1024*1024;
52 unit = "GB";
54 else if (total >= 1024*1024.0)
56 total /= 1024.0*1024;
57 unit = "MB";
59 else if (total >= 1024.0)
61 total = int(total/1024.0);
62 unit = "KB";
64 else
66 unit = "B";
68 static char buffer[256];
69 if ( total > 100.0)
71 sprintf(buffer, "%0.0f", (double)total);
73 else if (total > 10.0)
75 sprintf(buffer, "%0.1f", (double)total);
77 else
79 sprintf(buffer, "%0.2f", (double)total);
81 std::string ret(buffer);
82 ret+=unit;
84 return ret;
87 //===========================================================================================
88 static std::string getVideoInfoDeviceName()
90 uint64 version;
91 std::string ret;
92 bool ok = CSystemInfo::getVideoInfo(ret, version);
93 if (ok)
95 return ret.c_str();
97 return "";
100 //===========================================================================================
101 static uint64 getVideoDriverVersion()
103 static std::string ret;
104 uint64 version=0;
105 ret.clear();
106 bool ok = CSystemInfo::getVideoInfo(ret, version);
107 if (ok)
109 return version;
111 return 0;
114 //===========================================================================================
115 static std::string extractToken(const std::string& res, const std::string& token)
117 std::string ret("");
118 std::string tokenBegin = std::string("<") + token + ">";
119 std::string::size_type tokenBeginLen = tokenBegin.size();
120 std::string tokenEnd = std::string("</") + token + ">";
121 std::string::size_type tokenEndLen = tokenBegin.size();
123 std::string::size_type begin = res.find(tokenBegin);
124 std::string::size_type end = begin != std::string::npos && res.size() > tokenBeginLen + tokenEndLen ? res.find(tokenEnd, begin+tokenBeginLen) : std::string::npos;
125 if (begin != std::string::npos && end != std::string::npos)
127 ret = res.substr(begin+tokenBeginLen, end - (begin+tokenBeginLen));
129 return ret;
133 /////////////////////////
134 // login progress task //
135 /////////////////////////
138 typedef std::deque<CLoginStep> TStepQueue;
140 class CLoginProgressTask : public NLMISC::IRunnable
142 public:
143 std::string StartupHost;
144 std::string StartupPage;
145 CSynchronized<TStepQueue> StepQueue;
146 bool StopWanted;
147 public:
148 //============================================================================================
149 CLoginProgressTask() : StepQueue("")
151 StopWanted = false;
154 //============================================================================================
155 void clearQueue()
157 CSynchronized<TStepQueue>::CAccessor access(&StepQueue);
158 access.value().clear();
161 //============================================================================================
162 virtual void run()
166 // init and send hardware info if first time
167 std::string productInstallId = CLoginRegistry::getProductInstallId();
168 if (productInstallId.empty())
170 throw NLMISC::Exception("Couldn't retrieve product install id");
172 std::string res = sendMsg(std::string("login") + "&install_id=" + productInstallId);
173 std::string userId = extractToken(res, "user_id");
174 if (userId.empty())
176 res = sendMsg(std::string("init") + "&install_id=" + productInstallId + buildSysInfoString());
177 userId = extractToken(res, "user_id");
179 if (userId.empty())
181 throw NLMISC::Exception("Couldn't retrieve user id");
183 // from now, wait each step from the client
184 for (;;)
186 CLoginStep loginStep;
187 bool newStep = false;
189 CSynchronized<TStepQueue>::CAccessor access(&StepQueue);
190 if (!access.value().empty())
192 loginStep = access.value().front();
193 access.value().pop_front();
194 newStep = true;
196 if (newStep)
198 if (loginStep.Step == (uint)LoginStep_Stop)
200 break;
202 uint currentStep = CLoginRegistry::getLoginStep();
203 // during install program some messages can be launch multiple times (eg "install_update&percent=17" that indicates that 17 percent of the installation is already done)
204 bool isInInstallation = InstallStep_StartDownload <= loginStep.Step && loginStep.Step <= InstallStep_StopInstall;
205 bool hasBeenInstalled = currentStep > InstallStep_StopInstall;
206 if ((isInInstallation&&!hasBeenInstalled) || (loginStep.Step > CLoginRegistry::getLoginStep()) )
208 std::string ret= sendMsg(loginStep.PostString + "&user_id=" + userId);
209 // If we reached this point, server has correctly received the step -> commit current progress in registry
210 // Only send msg for player that have never installed the software
211 CLoginRegistry::setLoginStep(loginStep.Step);
212 // Async Ret enable the player to Know via pulling the return of the sendMsg
213 if (loginStep.AsyncRet && loginStep.AsyncSent)
215 (*loginStep.AsyncRet) = ret;
216 (*loginStep.AsyncSent) = true;
222 nlSleep(1000);
223 if (StopWanted) break;
226 catch (const std::exception &e)
228 nlwarning(e.what());
230 catch(...)
232 clearQueue();
233 throw;
235 clearQueue();
237 //============================================================================================
238 std::string sendMsg(const std::string &msg)
240 CHttpClient httpClient;
241 std::string ret;
242 if (!httpClient.connect("http://" + StartupHost))
244 throw NLMISC::Exception("Can't connect to http server");
246 //std::string postString = "http://" + StartupHost + StartupPage + "?cmd=log&msg=" + msg;
247 //nlwarning("POST STRING = %s", postString.c_str());
248 if (!httpClient.sendPost("http://" + StartupHost + StartupPage, "cmd=log&msg=" + msg))
250 throw NLMISC::Exception("Post failed");
252 if (!httpClient.receive(ret))
254 throw NLMISC::Exception("Receive failed");
256 httpClient.disconnect();
257 return ret;
259 //============================================================================================
260 std::string buildSysInfoString()
262 std::string sis;
263 sis = "&os=" + CSystemInfo::getOS();
264 sis += "&proc=" + CSystemInfo::getProc();
265 sis += "&memory=" + sizeToHumanStd(CSystemInfo::totalPhysicalMemory());
266 sis += "&video_card=" + getVideoInfoDeviceName();
267 sis += "&driver_version=" + uint64ToHex(getVideoDriverVersion());
269 sis = "&os=win2k";
270 sis += "&proc=p4";
271 sis += "&memory=1024";
272 sis += "&video_card=ati";
273 sis += "&driver_version=1";
275 return sis;
279 //===========================================================================================
280 CLoginProgressPostThread::CLoginProgressPostThread()
282 // Construct
283 _Thread = NULL;
284 _Task = NULL;
287 //===========================================================================================
288 CLoginProgressPostThread::~CLoginProgressPostThread()
290 release();
293 //===========================================================================================
294 void CLoginProgressPostThread::init(const std::string &startupHost, const std::string &startupPage)
296 nlassert(!_Thread);
297 CLoginProgressTask *lpt = new CLoginProgressTask;
298 // Its not the real Startup Host this values comes from the InstallStatsUrl value of the config file
299 lpt->StartupHost = startupHost;
300 lpt->StartupPage = startupPage;
301 _Task = lpt;
302 _Thread = IThread::create(lpt);
303 if (!_Thread)
305 release();
306 return;
308 _Thread->start();
311 //===========================================================================================
312 void CLoginProgressPostThread::release()
314 if (_Task)
316 safe_cast<CLoginProgressTask *>(_Task)->StopWanted = true;
318 if (_Thread && _Thread->isRunning()) _Thread->wait();
319 delete _Task;
320 delete _Thread;
321 _Task = NULL;
322 _Thread = NULL;
325 //===========================================================================================
326 void CLoginProgressPostThread::step(const CLoginStep &ls)
328 if (!_Task) return;
329 if (!_Thread->isRunning()) return;
330 CLoginProgressTask *lpt = safe_cast<CLoginProgressTask *>(_Task);
332 CSynchronized<TStepQueue>::CAccessor access(&lpt->StepQueue);
333 access.value().push_back(ls);
337 //===========================================================================================
338 void CLoginProgressPostThread::init(NLMISC::CConfigFile &configFile)
340 std::string installStartupPage;
341 std::string installStartupHost;
342 static std::string httpStr = "http://";
344 if (configFile.getVarPtr("InstallStatsUrl") )
347 static std::string httpStr = "http://";
348 static std::string::size_type httpStrSize = httpStr.size();
349 std::string tmp = configFile.getVarPtr("InstallStatsUrl")->asString(0);
350 std::string::size_type it= tmp.find(httpStr);
351 if (it == std::string::npos) return;
353 std::string::size_type hostPageSeparator = tmp.find("/", httpStrSize);
354 if (hostPageSeparator == std::string::npos) return;
356 installStartupPage = tmp.substr(hostPageSeparator); //keep the leading slash
357 installStartupHost = tmp.substr(httpStrSize, hostPageSeparator - httpStrSize); // dont keep the last slah
359 init(installStartupHost, installStartupPage);
361 else
363 // nlwarning("Error the InstallStatsUrl is not in the client_default.cfg.");