1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2016 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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/>.
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
)
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
;
49 if (total
>= 1024.0*1024.0*1024.0)
51 total
/= 1024.0*1024*1024;
54 else if (total
>= 1024*1024.0)
59 else if (total
>= 1024.0)
61 total
= int(total
/1024.0);
68 static char buffer
[256];
71 sprintf(buffer
, "%0.0f", (double)total
);
73 else if (total
> 10.0)
75 sprintf(buffer
, "%0.1f", (double)total
);
79 sprintf(buffer
, "%0.2f", (double)total
);
81 std::string
ret(buffer
);
87 //===========================================================================================
88 static std::string
getVideoInfoDeviceName()
92 bool ok
= CSystemInfo::getVideoInfo(ret
, version
);
100 //===========================================================================================
101 static uint64
getVideoDriverVersion()
103 static std::string ret
;
106 bool ok
= CSystemInfo::getVideoInfo(ret
, version
);
114 //===========================================================================================
115 static std::string
extractToken(const std::string
& res
, const std::string
& token
)
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
));
133 /////////////////////////
134 // login progress task //
135 /////////////////////////
138 typedef std::deque
<CLoginStep
> TStepQueue
;
140 class CLoginProgressTask
: public NLMISC::IRunnable
143 std::string StartupHost
;
144 std::string StartupPage
;
145 CSynchronized
<TStepQueue
> StepQueue
;
148 //============================================================================================
149 CLoginProgressTask() : StepQueue("")
154 //============================================================================================
157 CSynchronized
<TStepQueue
>::CAccessor
access(&StepQueue
);
158 access
.value().clear();
161 //============================================================================================
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");
176 res
= sendMsg(std::string("init") + "&install_id=" + productInstallId
+ buildSysInfoString());
177 userId
= extractToken(res
, "user_id");
181 throw NLMISC::Exception("Couldn't retrieve user id");
183 // from now, wait each step from the client
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();
198 if (loginStep
.Step
== (uint
)LoginStep_Stop
)
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;
223 if (StopWanted
) break;
226 catch (const std::exception
&e
)
237 //============================================================================================
238 std::string
sendMsg(const std::string
&msg
)
240 CHttpClient httpClient
;
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();
259 //============================================================================================
260 std::string
buildSysInfoString()
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());
271 sis += "&memory=1024";
272 sis += "&video_card=ati";
273 sis += "&driver_version=1";
279 //===========================================================================================
280 CLoginProgressPostThread::CLoginProgressPostThread()
287 //===========================================================================================
288 CLoginProgressPostThread::~CLoginProgressPostThread()
293 //===========================================================================================
294 void CLoginProgressPostThread::init(const std::string
&startupHost
, const std::string
&startupPage
)
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
;
302 _Thread
= IThread::create(lpt
);
311 //===========================================================================================
312 void CLoginProgressPostThread::release()
316 safe_cast
<CLoginProgressTask
*>(_Task
)->StopWanted
= true;
318 if (_Thread
&& _Thread
->isRunning()) _Thread
->wait();
325 //===========================================================================================
326 void CLoginProgressPostThread::step(const CLoginStep
&ls
)
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
);
363 // nlwarning("Error the InstallStatsUrl is not in the client_default.cfg.");