Linux multi-monitor fullscreen support
[ryzomcore.git] / ryzom / client / src / bg_downloader_access.cpp
blob338b86f9afcf2b019d797a06403199650c9bbb17
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) 2012-2020 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 "bg_downloader_access.h"
23 #ifdef RYZOM_BG_DOWNLOADER
25 #include "global.h"
26 #include "login_patch.h"
28 #include "nel/misc/shared_memory.h"
29 #include "nel/misc/i18n.h"
30 #include "nel/misc/win_thread.h"
31 #include "nel/misc/big_file.h"
33 #include "game_share/bg_downloader_msg.h"
36 #ifdef NL_OS_WINDOWS
38 #include "nel/misc/win_thread.h"
40 #ifdef DEBUG_NEW
41 #define new DEBUG_NEW
42 #endif
44 using namespace BGDownloader;
45 using namespace NLMISC;
47 extern HINSTANCE HInstance;
49 // exception used by the download coroutine to signal an error
50 class EDownloadException : public NLMISC::Exception
52 public:
53 EDownloadException(const std::string &reason) : Exception(reason) {}
56 class EDownloadTerminationRequested : public NLMISC::Exception
58 public:
59 EDownloadTerminationRequested() : Exception("Download termination requested") {}
62 class EWaitMessageTimeoutException : public NLMISC::Exception
64 public:
65 EWaitMessageTimeoutException() : Exception("Download timeout message") {}
68 //=====================================================
69 CBGDownloaderAccess::CBGDownloaderAccess()
71 _DownloadCoTask = new CDownloadCoTask;
72 _DownloadCoTask->Parent = this;
73 _State = State_Idle;
74 _TaskResult = BGDownloader::TaskResult_Unknown;
75 _AvailablePatchs = 0;
76 clearCurrentMessage();
77 _MustLaunchBatFile = false;
78 _ShowDownloader = false;
79 _DownloadThreadPriority = ThreadPriority_Low;
80 _FrozenUI = false;
81 _PatchCompletionFlag = false;
82 _RyzomInstPIDPtr = NULL;
83 _WaitBalloonDisplay = false;
84 _CurrentFileProgress = 0.f;
87 //=====================================================
88 void CBGDownloaderAccess::clearCurrentMessage()
90 _CurrentMessage = ucstring(); // OLD
91 _CurrentFilesToGet = 0;
92 _TotalFilesToGet = 0;
93 _PatchingSize = 0;
94 _TotalSize = 0;
95 _CurrentFileProgress = 0.f;
98 //=====================================================
99 CBGDownloaderAccess::~CBGDownloaderAccess()
101 delete _DownloadCoTask;
104 //=====================================================
105 void CBGDownloaderAccess::init()
107 release();
110 //=====================================================
111 void CBGDownloaderAccess::release()
113 _DownloaderMsgQueue.release();
114 if (_DownloadCoTask->isStarted())
116 _DownloadCoTask->requestTerminate();
117 while (_DownloadCoTask->isFinished())
121 _State = State_Idle;
122 if (_RyzomInstPIDPtr)
124 NLMISC::CSharedMemory::closeSharedMemory(_RyzomInstPIDPtr);
125 _RyzomInstPIDPtr = NULL;
130 //=====================================================
131 void CBGDownloaderAccess::update()
133 /*nlwarning("In msg queue = %d, out msg queue = %d",
134 (int) _DownloaderMsgQueue.getReceiveQueueSize(),
135 (int) _DownloaderMsgQueue.getSendQueueSize());*/
136 switch (_State)
138 case State_Idle:
139 nlassert(!_DownloadCoTask->isStarted());
140 break;
141 case State_Finished:
142 if (_WaitBalloonDisplay)
144 nlassert(_DownloadCoTask->isStarted());
145 _DownloadCoTask->resume();
147 else
149 if (_DownloadCoTask->isStarted())
151 resetDownloadTask();
154 break;
155 case State_Patching:
156 // Avoid task collision here : this may happen during the tp main loop, and
157 // would lead to a freeze
158 if (NLMISC::CCoTask::getCurrentTask() == NULL)
160 _DownloadCoTask->resume();
162 if (_State == State_Finished && !_WaitBalloonDisplay)
164 resetDownloadTask();
166 break;
167 default:
168 nlassert(0);
169 break;
173 //=====================================================
174 void CBGDownloaderAccess::resetDownloadTask()
176 delete _DownloadCoTask;
177 _DownloadCoTask = new CDownloadCoTask;
178 _DownloadCoTask->Parent = this;
179 nlassert(!_DownloadCoTask->isStarted());
182 //=====================================================
183 void CBGDownloaderAccess::startTask(const BGDownloader::CTaskDesc &taskDesc, const std::string &commandLine, bool showDownloader)
185 nlassert(_State != State_Patching); // patching already started
186 nlassert(!_DownloadCoTask->isStarted());
187 _CurrentFilesToGet = 0;
188 _TotalFilesToGet = 0;
189 _PatchingSize = 0;
190 _TotalSize = 0;
191 _CommandLine = commandLine;
192 _State = State_Patching;
193 _TaskResult = BGDownloader::TaskResult_Unknown;
194 _WantedTask = taskDesc;
195 _ErrorMsg.clear();
196 _ShowDownloader = showDownloader;
199 //=====================================================
200 bool CBGDownloaderAccess::isTaskEnded(BGDownloader::TTaskResult &result, ucstring &errorMsg) const // OLD
202 if (_State == State_Finished)
204 result = _TaskResult;
205 errorMsg = _ErrorMsg;
206 return true;
208 return false;
211 //=====================================================
212 void CBGDownloaderAccess::resumeBackgroundDownload()
214 nlassert(0); // not handled yet
215 //_DownloadCoTask->setDownloaderMode(DownloaderMode_Autonomous);
218 ////////////////////////
219 // DOWNLOAD COROUTINE //
220 ////////////////////////
223 //=====================================================
224 void CBGDownloaderAccess::CDownloadCoTask::run()
226 Parent->_ErrorMsg.clear();
229 // don't restart downloader before
230 if (Parent->_WantedTask.State == DLState_GetAndApplyPatch)
232 // this is a continuation of the check task, so ensure
233 // that the downloader is still running and in slave mode
234 if (!isDownloaderProcessRunning() && getDownloaderMode() != DownloaderMode_Slave)
236 throw EDownloadException(CI18N::get("uiBGD_DownloaderStopped"));
239 else
241 // should be executed only once for the check
242 restartDownloader();
244 setDownloaderVerbosity(true);
245 setDownloaderMode(DownloaderMode_Slave);
246 doTask(Parent->_WantedTask);
247 setDownloaderVerbosity(false);
248 // clear display info, else they would remain for a brief time when arriving on patch screen
249 Parent->clearCurrentMessage();
251 getTaskResult(Parent->_TaskResult, Parent->_AvailablePatchs, Parent->_MustLaunchBatFile, Parent->_ErrorMsg);
253 Parent->_PatchCompletionFlag = false;
254 if (Parent->_TaskResult == BGDownloader::TaskResult_Success)
256 if (Parent->_WantedTask == DLState_CheckPatch)
258 getDescFile();
260 if (!Parent->_AvailablePatchs)
262 Parent->_WaitBalloonDisplay = true;
263 Parent->_State = State_Finished;
264 // because the downloader may pop a notification balloon here, wait some more before shutting it down
266 sleep(2500); // at this time, may last longer because the client starts a loading phase
267 Parent->_WaitBalloonDisplay = false;
268 // no patch, just stop the downloader
269 shutdownDownloader();
272 bool rosPatch = (Parent->_AvailablePatchs & (1 << BGDownloader::DownloadID_RoS)) != 0;
273 bool mainlandPatch = (Parent->_AvailablePatchs & (1 << BGDownloader::DownloadID_MainLand)) != 0;
275 if (Parent->_MustLaunchBatFile && !rosPatch) // let be superstitious, should always be true ...
277 // no patch but must rebbot ? may happen only if some 'unpacked' file needed by RoS have been deleted
278 shutdownDownloader();
280 else
281 if (mainlandPatch)
283 // if mainland patch isn't completed yet, remove the searchpaths
284 // to the .bnp that are going to be patched
286 //sint64 startTime = NLMISC::CTime::getLocalTime();
287 const CBNPCategorySet &bnpCatSet = Parent->_DescFile.getCategories();
288 std::vector<std::string> bigFiles;
289 for (uint catIndex = 0; catIndex < bnpCatSet.categoryCount(); ++catIndex)
291 const CBNPCategory &cat = bnpCatSet.getCategory(catIndex);
292 if (cat.isOptional()) // NB : 'optional' flag meaning has changed : it now means 'Mainland Patch'
293 // until an enum is added
295 for (uint f = 0; f < cat.fileCount(); ++f)
297 bigFiles.push_back(cat.getFile(f));
301 NLMISC::CPath::removeBigFiles(bigFiles);
302 //sint64 endTime = NLMISC::CTime::getLocalTime();
303 //nlinfo("%.2f s to remove paths", (endTime - startTime) / 1000.f);
307 if (Parent->_WantedTask.State == DLState_GetAndApplyPatch)
309 Parent->_PatchCompletionFlag = true;
310 if (Parent->_WantedTask.DownloadBitfield & (1 << BGDownloader::DownloadID_RoS))
312 if (Parent->_MustLaunchBatFile) // let be superstitious, should always be true ...
314 Parent->_WaitBalloonDisplay = true;
315 Parent->_State = State_Finished;
316 // because the downloader may pop a notification balloon here, wait some more before shutting it down
318 sleep(5000);
319 Parent->_WaitBalloonDisplay = false;
320 // because a reboot is required, just stop now ...
321 shutdownDownloader();
324 else
325 if (Parent->_WantedTask.DownloadBitfield & (1 << BGDownloader::DownloadID_MainLand))
327 bool memoryCompressed = CPath::isMemoryCompressed();
328 if (memoryCompressed)
330 CPath::memoryUncompress();
332 // and redo 'addSearchPath' on data, because of the new bnp files that have just been added
333 NLMISC::CPath::addSearchPath("data/", true, false, NULL);
334 if (memoryCompressed)
336 CPath::memoryCompress();
338 Parent->_WaitBalloonDisplay = true;
339 Parent->_State = State_Finished;
340 // because the downloader may pop a notification balloon here, wait some more before shutting it down
341 sleep(5000);
342 Parent->_WaitBalloonDisplay = false;
343 // stop after the mainland download (hardcoded, but should suffice for now)
344 shutdownDownloader();
349 catch(const EDownloadException &e)
351 //shutdownDownloader();
352 Parent->_TaskResult = TaskResult_Error;
353 Parent->_ErrorMsg.fromUtf8(e.what());
354 Parent->_DownloadThreadPriority = ThreadPriority_DownloaderError;
356 catch(const EDownloadTerminationRequested &e)
358 shutdownDownloader();
359 Parent->_TaskResult = TaskResult_Error;
360 Parent->_ErrorMsg = ucstring(e.what()); // OLD
361 Parent->_DownloadThreadPriority = ThreadPriority_DownloaderError;
363 catch(const NLMISC::EStream &e)
365 shutdownDownloader();
366 Parent->_TaskResult = TaskResult_Error;
367 nlwarning("BG DOWNLOADER PROTOCOL ERROR ! Stream error");
368 Parent->_ErrorMsg = CI18N::get("uiBGD_ProtocolError") + ucstring(" : ") + ucstring(e.what()); // OLD
369 Parent->_DownloadThreadPriority = ThreadPriority_DownloaderError;
371 catch (const EWaitMessageTimeoutException &e)
373 shutdownDownloader();
374 Parent->_TaskResult = TaskResult_Error;
375 nlwarning("BG DOWNLOADER PROTOCOL ERROR ! Message timeout");
376 Parent->_ErrorMsg = CI18N::get("uiBGD_ProtocolError") + ucstring(" : ") + ucstring(e.what()); // OLD
377 Parent->_DownloadThreadPriority = ThreadPriority_DownloaderError;
379 Parent->_State = State_Finished;
382 //=====================================================
383 bool CBGDownloaderAccess::getPatchCompletionFlag(bool clearFlag)
385 bool flag = _PatchCompletionFlag;
386 if (clearFlag)
388 _PatchCompletionFlag = false;
390 return flag;
393 //=====================================================
394 bool CBGDownloaderAccess::CDownloadCoTask::isDownloaderProcessRunning()
396 // the downloader creates a system-wide mutex, so if present, assume that the downloader is running
398 HANDLE mutex = CreateMutexW (NULL, FALSE, BGDownloader::DownloaderMutexName);
399 if (mutex)
401 if (GetLastError() == ERROR_ALREADY_EXISTS)
403 CloseHandle(mutex);
404 return true;
406 CloseHandle(mutex);
408 return false;
411 // launch the process and wait until completion
412 #if defined (NL_DEBUG)
413 static const char *BGDownloaderName = "client_background_downloader_d.exe";
414 #elif defined (NL_RELEASE)
415 static const char *BGDownloaderName = "client_background_downloader_r.exe";
416 #else
417 # error "Unknown bg downloader exe name";
418 #endif
421 //=====================================================
422 void CBGDownloaderAccess::CDownloadCoTask::createDownloaderProcess()
424 bool manualLaunch = false;
425 CConfigFile::CVar *manualLaunchVar = ClientCfg.ConfigFile.getVarPtr("BackgroundDownloaderManualLaunch");
426 if (manualLaunchVar)
428 manualLaunch = (manualLaunchVar->asInt() != 0);
430 if (!manualLaunch)
432 BOOL ok = NLMISC::launchProgram(BGDownloaderName, Parent->_CommandLine);
433 if (!ok)
435 throw EDownloadException(CI18N::get("uiBGD_LaunchError"));
438 else
440 nlwarning(Parent->_CommandLine.c_str());
444 //=====================================================
445 void CBGDownloaderAccess::CDownloadCoTask::restartDownloader()
447 // if another ryzom client is running, try stopping it first
448 for (;;)
450 void *ryzomInstPIDPtr = NLMISC::CSharedMemory::accessSharedMemory(NLMISC::toSharedMemId(RYZOM_PID_SHM_ID));
451 if (!ryzomInstPIDPtr) break; // only instance running is us
452 // try to terminate the other instance
453 uint count = 0;
454 while (*(DWORD *) ryzomInstPIDPtr == 0)
456 // the other process didn't write its pid into shared mem yet (shared memory is initially filled with zero's)
457 // so wait a bit (very unlikely case !!)
458 sleep(100);
459 ++ count;
460 if (count == 50)
462 nlwarning("CBGDownloaderAccess::CDownloadCoTask : detected shared memory segment, with NULL pid");
463 // some problem here ...
464 throw EDownloadException(CI18N::get("uiBGD_MultipleRyzomInstance"));
467 bool ok = NLMISC::CWinProcess::terminateProcess(*(DWORD *) ryzomInstPIDPtr);
468 CSharedMemory::closeSharedMemory(ryzomInstPIDPtr);
469 if (!ok)
471 nlwarning("CBGDownloaderAccess::CDownloadCoTask : detected shared memory segment, with good pid, but couldn't stop the process");
472 // couldn't stop the other client ...
473 throw EDownloadException(CI18N::get("uiBGD_MultipleRyzomInstance"));
476 // write our pid into shared mem
477 Parent->_RyzomInstPIDPtr = CSharedMemory::createSharedMemory(NLMISC::toSharedMemId(RYZOM_PID_SHM_ID), sizeof(uint32));
478 if (!Parent->_RyzomInstPIDPtr)
480 // really, really bad luck ...
481 throw EDownloadException(CI18N::get("uiBGD_MultipleRyzomInstance"));
483 *(uint32 *) Parent->_RyzomInstPIDPtr = (uint32) GetCurrentProcessId();
485 HWND hWnd = Driver->getDisplay();
487 // for safety, stop any running downloader
488 if (isDownloaderProcessRunning())
490 Parent->_DownloaderMsgQueue.init(hWnd, BGDownloader::ClientWndID, BGDownloader::DownloaderWndID);
491 sleep(200);
492 shutdownDownloader();
493 Parent->_DownloaderMsgQueue.release();
494 sleep(200);
496 uint tryCounter = 1;
497 for (;;)
499 nlwarning("Launching downloader: try number %u", tryCounter++);
500 // now we can create the message queue because we are sure that it will reach the good app
501 Parent->_DownloaderMsgQueue.init(HInstance, BGDownloader::ClientWndID, BGDownloader::DownloaderWndID);
502 sleep(200);
504 Parent->_CurrentMessage = CI18N::get("uiBGD_Launching");
506 #ifndef BG_DOWNLOADER_MANUAL_LAUNCH
507 createDownloaderProcess();
508 #endif
509 while (!Parent->_DownloaderMsgQueue.connected())
511 yieldDownload();
513 // try probe/ack test for safety
514 bool ok = false;
515 int tryIndex = 1;
516 uint32 waitTime = 500;
517 const uint32 totalTries = 7;
518 while (waitTime <= 32000)
520 Parent->_CurrentMessage.fromUtf8(toString(CI18N::get("uiBGD_HandShaking").c_str(), tryIndex, totalTries));
522 sendSimpleMsg(CL_Probe);
523 NLMISC::CMemStream dummyMsg;
526 waitMsg(BGD_Ack, dummyMsg, waitTime /* max milliseconds */);
527 ok = true;
528 break;
530 catch (const EWaitMessageTimeoutException &)
532 // no-op, just continue the loop for another try
534 waitTime *= 2;
535 ++ tryIndex;
537 if (ok) break;
538 if (isDownloaderProcessRunning())
540 shutdownDownloader();
541 sleep(200);
543 Parent->_DownloaderMsgQueue.release();
544 sleep(200);
546 nlwarning("Downloader launched successfully");
547 if (Parent->_ShowDownloader)
549 Parent->showDownloader();
553 //=====================================================
554 void CBGDownloaderAccess::CDownloadCoTask::yieldDownload()
556 yield();
557 if (isTerminationRequested())
559 throw EDownloadTerminationRequested();
563 //=====================================================
564 void CBGDownloaderAccess::sendSimpleMsg(BGDownloader::TMsgType msgType)
566 CMemStream outMsg(false /* output stream */);
567 outMsg.serialEnum(msgType);
568 _DownloaderMsgQueue.sendMessage(outMsg);
571 //=====================================================
572 void CBGDownloaderAccess::showDownloader()
574 sendSimpleMsg(CL_Show);
577 //=====================================================
578 void CBGDownloaderAccess::hideDownloader()
580 sendSimpleMsg(CL_Hide);
584 //=====================================================
585 CTaskDesc CBGDownloaderAccess::CDownloadCoTask::getDownloaderState()
587 sendSimpleMsg(CL_GetState);
588 CMemStream inMsg(true /* input stream */);
589 waitMsg(BGD_State, inMsg);
590 CTaskDesc result;
591 inMsg.serial(result);
592 return result;
595 //=====================================================
596 void CBGDownloaderAccess::CDownloadCoTask::getDescFile()
598 sendSimpleMsg(CL_GetDescFile);
599 CMemStream inMsg(true /* input stream */);
600 waitMsg(BGD_DescFile, inMsg);
601 inMsg.serial(Parent->_DescFile);
605 //=====================================================
606 TDownloaderMode CBGDownloaderAccess::CDownloadCoTask::getDownloaderMode()
608 sendSimpleMsg(CL_GetMode);
609 CMemStream inMsg(true /* input stream */);
610 waitMsg(BGD_Mode, inMsg);
611 TDownloaderMode mode = DownloaderMode_Unknown;
612 inMsg.serialEnum(mode);
613 return mode;
616 //=====================================================
617 void CBGDownloaderAccess::CDownloadCoTask::getTaskResult(TTaskResult &result,
618 uint32 &availablePatchs,
619 bool &mustLaunchBatFile,
620 ucstring &errorMsg // OLD
623 sendSimpleMsg(CL_GetTaskResult);
624 CMemStream inMsg(true /* input stream */);
625 waitMsg(BGD_TaskResult, inMsg);
626 inMsg.serialEnum(result);
627 inMsg.serial(availablePatchs);
628 inMsg.serial(mustLaunchBatFile);
629 inMsg.serial(errorMsg); // OLD
632 //=====================================================
633 void CBGDownloaderAccess::CDownloadCoTask::doTask(const CTaskDesc &taskDesc)
635 CTaskDesc downloaderTask = getDownloaderState();
636 if (downloaderTask.State != DLState_Idle && downloaderTask != taskDesc)
638 // if not the wanted task, ask to stop current task, and wait until completion
639 stopTask();
640 startTask(taskDesc);
642 else
643 if (downloaderTask.State == DLState_Idle)
645 startTask(taskDesc);
647 // else, good task already started, just wait
648 waitIdle();
651 //=====================================================
652 void CBGDownloaderAccess::CDownloadCoTask::startTask(const CTaskDesc &taskDesc)
654 CMemStream outMsg(false /* output stream */);
655 TMsgType msgType = CL_StartTask;
656 outMsg.serialEnum(msgType);
657 CTaskDesc mutableTaskDesc = taskDesc;
658 outMsg.serial(mutableTaskDesc);
659 sendMsg(outMsg);
660 waitIdle();
663 //=====================================================
664 void CBGDownloaderAccess::CDownloadCoTask::stopTask()
666 sendSimpleMsg(CL_Stop);
667 waitIdle();
670 //=====================================================
671 void CBGDownloaderAccess::CDownloadCoTask::shutdownDownloader()
673 const uint32 SHUTDOWN_TIMEOUT = 6; // seconds until we consider the downloader is hung, and try to shut it down
674 sendSimpleMsg(CL_Shutdown);
675 uint32 startTime = NLMISC::CTime::getSecondsSince1970();
676 setDownloaderVerbosity(false);
677 while (isDownloaderProcessRunning())
679 Parent->_CurrentMessage = CI18N::get("uiBGD_ShuttingDown");
680 yield();
681 if ((NLMISC::CTime::getSecondsSince1970() - startTime) >= SHUTDOWN_TIMEOUT)
683 Parent->_CurrentMessage = CI18N::get("uiBGD_ForciblyShutdown");
684 yield();
685 if (!CWinProcess::terminateProcessFromModuleName(BGDownloaderName))
687 Parent->_CurrentMessage = CI18N::get("uiBGD_ShutdownFailed");
689 return;
692 CWinProcess::terminateProcessFromModuleName(BGDownloaderName); // for safety
693 Parent->_CurrentMessage = ucstring(); // OLD
696 //=====================================================
697 void CBGDownloaderAccess::CDownloadCoTask::setDownloaderMode(TDownloaderMode mode)
699 CMemStream outMsg(false /* output stream */);
700 TMsgType msgType = CL_SetMode;
701 outMsg.serialEnum(msgType);
702 outMsg.serialEnum(mode);
703 sendMsg(outMsg);
706 //=====================================================
707 void CBGDownloaderAccess::CDownloadCoTask::setDownloaderVerbosity(bool verbose)
709 CMemStream outMsg(false /* output stream */);
710 TMsgType msgType = CL_SetVerbose;
711 outMsg.serialEnum(msgType);
712 outMsg.serial(verbose);
713 sendMsg(outMsg);
716 //=====================================================
717 void CBGDownloaderAccess::CDownloadCoTask::waitIdle()
719 for (;;)
721 CTaskDesc downloaderTask = getDownloaderState();
722 if (downloaderTask.State == DLState_Idle) break;
726 //=====================================================
727 void CBGDownloaderAccess::CDownloadCoTask::waitMsg(BGDownloader::TMsgType wantedMsgType, NLMISC::CMemStream &msg, NLMISC::TTime timeOutInMs)
729 NLMISC::TTime startTime = NLMISC::CTime::getLocalTime();
730 BGDownloader::TMsgType msgType = (BGDownloader::TMsgType) ~0;
731 for (;;)
733 while (!Parent->_DownloaderMsgQueue.pumpMessage(msg))
735 #ifdef NL_DEBUG
736 CConfigFile::CVar *manualLaunchVar = ClientCfg.ConfigFile.getVarPtr("BackgroundDownloaderManualLaunch");
737 if (!manualLaunchVar || manualLaunchVar->asInt() == 0)
738 #endif
740 if (NLMISC::CTime::getLocalTime() - startTime > timeOutInMs)
742 nlwarning("Time out exceeded while waiting for message of type %d", (int) wantedMsgType);
743 #ifdef NL_DEBUG
744 //nlassert(0);
745 #endif
746 throw EWaitMessageTimeoutException();
749 checkDownloaderAlive();
750 yieldDownload();
752 nlassert (msg.isReading());
753 msg.serialEnum(msgType);
754 if (msgType == wantedMsgType) return;
755 if (!defaultMessageHandling(msgType, msg))
757 //nlwarning("##CLIENT RCV message of type : %s", toString(msg).c_str());
758 break;
761 if (msgType != wantedMsgType)
763 nlwarning("BG DOWNLOADER PROTOCOL ERROR ! Bad message type received. Expected type is '%d', received type is '%d'", (int) wantedMsgType, (int) msgType);
764 throw EDownloadException(CI18N::get("uiBGD_ProtocolError"));
769 //=====================================================
770 bool CBGDownloaderAccess::CDownloadCoTask::defaultMessageHandling(BGDownloader::TMsgType msgType, NLMISC::CMemStream &msg)
772 nlassert(msg.isReading());
773 switch(msgType)
775 case BGD_Priority:
777 BGDownloader::TThreadPriority tp;
778 msg.serialEnum(tp);
779 if (tp != Parent->_DownloadThreadPriority)
781 Parent->_DownloadThreadPriority = tp; // TMP, for debug
783 return true;
785 break;
786 case BGD_UpdateStatusString:
788 msg.serial(Parent->_CurrentMessage);
789 msg.serial(Parent->_CurrentFilesToGet);
790 msg.serial(Parent->_TotalFilesToGet);
791 msg.serial(Parent->_PatchingSize);
792 msg.serial(Parent->_TotalSize);
793 msg.serial(Parent->_CurrentFileProgress);
794 //nlinfo(Parent->_CurrentMessage.toString().c_str());
795 return true;
797 break;
798 case BGD_Error:
800 Parent->_TaskResult = TaskResult_Error;
801 ucstring errorMsg; // OLD
802 msg.serial(errorMsg);
803 throw EDownloadException(errorMsg.toUtf8());
805 break;
806 case BGD_Ack:
808 // NO-OP
809 return true;
811 break;
813 return false;
817 //=====================================================
818 void CBGDownloaderAccess::CDownloadCoTask::checkDownloaderAlive()
820 if (!Parent->_DownloaderMsgQueue.connected() || !isDownloaderProcessRunning())
822 throw EDownloadException(CI18N::get("uiBGD_DownloaderDisconnected"));
827 //=====================================================
828 void CBGDownloaderAccess::CDownloadCoTask::sendMsg(NLMISC::CMemStream &msg)
830 Parent->_DownloaderMsgQueue.sendMessage(msg);
833 //=====================================================
834 void CBGDownloaderAccess::CDownloadCoTask::sendSimpleMsg(BGDownloader::TMsgType msgType)
836 //nlwarning("##CLIENT SEND simple message of type : %s", toString(msgType).c_str());
837 Parent->sendSimpleMsg(msgType);
840 //=====================================================
841 void CBGDownloaderAccess::reboot()
843 CPatchManager *pm = CPatchManager::getInstance();
844 pm->createBatchFile(_DescFile);
845 pm->executeBatchFile();
848 //=====================================================
849 void CBGDownloaderAccess::requestDownloadThreadPriority(BGDownloader::TThreadPriority newPriority, bool freezeUI)
851 nlassert((uint) newPriority < BGDownloader::ThreadPriority_Count);
852 CMemStream outMsg(false /* output stream */);
853 TMsgType msgType = CL_SetPriority;
854 outMsg.serialEnum(msgType);
855 outMsg.serialEnum(newPriority);
856 outMsg.serial(freezeUI);
857 _DownloaderMsgQueue.sendMessage(outMsg);
858 _FrozenUI = freezeUI;
863 #else
865 //=====================================================
866 CBGDownloaderAccess::CBGDownloaderAccess()
868 // TODO for Linux
871 //=====================================================
872 CBGDownloaderAccess::~CBGDownloaderAccess()
874 // TODO for Linux
877 //=====================================================
878 bool CBGDownloaderAccess::getPatchCompletionFlag(bool clearFlag)
880 // TODO for Linux
881 return false;
884 //=====================================================
885 void CBGDownloaderAccess::startTask(const BGDownloader::CTaskDesc &taskDesc, const std::string &commandLine, bool showDownloader)
887 // TODO for Linux
890 //=====================================================
891 bool CBGDownloaderAccess::isTaskEnded(BGDownloader::TTaskResult &result, ucstring &errorMsg) const // OLD
893 // TODO for Linux
894 return false;
897 //=====================================================
898 void CBGDownloaderAccess::update()
900 // TODO for Linux
903 //=====================================================
904 void CBGDownloaderAccess::release()
906 // TODO for Linux
909 //=====================================================
910 void CBGDownloaderAccess::requestDownloadThreadPriority(BGDownloader::TThreadPriority newPriority, bool freezeUI)
912 // TODO for Linux
915 //=====================================================
916 void CBGDownloaderAccess::reboot()
920 // not supported on other os
921 //#error IMPLEMENT ME PLEASE !!
923 #endif
926 bool isBGDownloadEnabled()
928 return ClientCfg.BackgroundDownloader && !ClientCfg.Local && ClientCfg.PatchWanted;
932 static BGDownloader::TThreadPriority DownloaderPriorityBackup = BGDownloader::ThreadPriority_Low;
933 static bool DownloaderUIFrozen = false;
934 static bool DownloaderPaused = false;
937 // ------------------------------------------------------------------------------------------------
938 void pauseBGDownloader()
940 if (isBGDownloadEnabled() && !DownloaderPaused)
942 CBGDownloaderAccess &downloader = CBGDownloaderAccess::getInstance();
943 DownloaderPriorityBackup = downloader.getDownloadThreadPriority();
944 DownloaderUIFrozen = downloader.isDownloaderUIFrozen();
945 downloader.requestDownloadThreadPriority(BGDownloader::ThreadPriority_Paused, true);
946 DownloaderPaused = true;
950 // ------------------------------------------------------------------------------------------------
951 void unpauseBGDownloader()
953 if (isBGDownloadEnabled() && DownloaderPaused)
955 if (DownloaderPriorityBackup != BGDownloader::ThreadPriority_DownloaderError)
957 CBGDownloaderAccess::getInstance().requestDownloadThreadPriority(DownloaderPriorityBackup, DownloaderUIFrozen);
959 DownloaderPaused = false;
963 #endif