Merge branch '164-crash-on-patching-and-possibly-right-after-login' into main/gingo...
[ryzomcore.git] / ryzom / client / src / login_patch.h
blob89c848f0c6a08bf6f3fd806e6ef9ec077fd5ef32
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) 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 #ifndef CL_PATCH_H
21 #define CL_PATCH_H
23 #include <string>
25 #include "nel/misc/types_nl.h"
26 #include "nel/misc/config_file.h"
27 #include "nel/misc/thread.h"
28 #include "nel/misc/progress_callback.h"
30 #include "game_share/bnp_patch.h"
32 #include "login_xdelta.h"
34 extern NLMISC::CConfigFile ConfigFile;
36 class CPatchThread;
37 class CCheckThread;
38 class CScanDataThread;
39 class CInstallThread;
40 class CDownloadThread;
43 // Useful for using an external downloader (BitTorrent) use of interface with CGameDownloader from client_background_rd.exe using as install program
44 // Forward all messages to CRyzomControl that will forward to CGameDownloader (The engine of the install software)
45 class IAsyncDownloader
47 public:
48 virtual ~IAsyncDownloader(){}
49 virtual void addToDownloadList(const std::string &/* patchName */, const std::string &/* sourceName */, uint32 /* timestamp */, const std::string& /* extractPath */, uint32 /* sevenZipSize */, uint32 /* size */){}
50 virtual void onFileInstall(const std::string& /* filename */, uint32 /* index */, uint32 /* filecount */){}
51 virtual void onFileInstallFinished(){}
52 virtual void onFileDownloading(const std::string& /* sourceName */, uint32 /* rate */, uint32 /* fileIndex */, uint32 /* fileCount */, uint64 /* fileSize */, uint64 /* fullSize */){}
53 virtual void onFileInstalling(const std::string& /* sourceName */, uint32 /* rate */, uint32 /* fileIndex */, uint32 /* fileCount */, uint64 /* fileSize */, uint64 /* fullSize */){}
54 virtual void onFileDownloadFinished(){}
55 virtual void fatalError(const std::string& /* errorId */, const std::string& /* param1 */, const std::string& /* param2 */){}
58 // To define alternate log
59 class IPatchManagerStateListener
61 public:
62 virtual void setState (bool /* bOutputToLog */, const std::string &/* ucsNewState */){}
65 // Get Info of file to install
66 class CInstallThreadEntry
68 public:
69 CInstallThreadEntry(){ Timestamp = 0; }
70 CInstallThreadEntry(const char* patchName, const char* sourceName, uint32 timestamp, const char* extractPath, uint32 size, uint32 sZipFileSize)
71 :PatchName(patchName), SourceName(sourceName), Timestamp(timestamp),Size(size),SZipFileSize(sZipFileSize),ExtractPath(extractPath) {}
72 std::string PatchName;
73 std::string SourceName;
74 uint32 Timestamp;
75 uint32 Size;
76 uint32 SZipFileSize;
77 std::string ExtractPath;
81 /**
82 * class managing the patch system
83 * \author Matthieu 'TrapII' Besson
84 * \author Vianney 'Ace' Lecroart
85 * \author Nevrax France
86 * \date July 2004
88 class CPatchManager
91 public:
93 struct SFileToPatch
95 std::string FileName; // Dest file for the patch
96 std::string SrcFileName; // Optional src file to which apply patch (empty unless some version of the file, possibly with
97 // all patchs applied, was found in the /unpack directory due to a download by the background downloader)
98 std::vector<uint32> Patches;
99 std::vector<uint32> PatcheSizes;
100 uint32 LastFileDate; // Used during patching to set the date of the file to the Date of the last patch
101 bool LocalFileToDelete; // Used during patching to know if we have to delete local file prior to apply patches
102 bool LocalFileExists;
103 bool Incremental; // Used during patching to know if we have to xdelta against a ref file
104 std::string ExtractPath; // Used during patching to extract a bnp file to a specific directory
105 uint32 FinalFileSize; // just for info, the final size after patch
106 uint32 SZFileSize; // Size of the SZ file
109 struct SPatchInfo
111 struct SCat
113 std::string Name;
114 uint32 Size; // Patch size for this category (all files to patch)
115 sint32 Req; // -1 or a value in Required cat (used only for optcat)
116 uint32 SZipSize; // SevenZipSize
117 uint32 FinalFileSize; // uncompressed SevenZipSize
118 SCat() { Size = 0; Req = -1; SZipSize = 0; FinalFileSize=0;}
121 std::vector<SCat> NonOptCat;
122 std::vector<SCat> ReqCat;
123 std::vector<SCat> OptCat;
126 void clear()
128 NonOptCat.clear();
129 ReqCat.clear();
130 OptCat.clear();
133 // return bitfield of available patchs, indexed by BGDownloader::TDownloadID
134 uint32 getAvailablePatchsBitfield() const;
137 public:
139 /// Singleton method : Get the unique patch manager instance
140 static CPatchManager* getInstance()
142 if (_Instance == NULL)
143 _Instance = new CPatchManager();
144 return _Instance;
147 // serverPath is the name where to find all patches, files description and so on
148 // serverVersion is a string describing the version of the description file
149 void init(const std::vector<std::string>& patchURIs, const std::string &serverPath, const std::string &serverVersion);
151 /// Get the version with the Description file (must be done after init)
152 std::string getClientVersion ();
154 bool isVerboseLog() { return VerboseLog; }
156 void setVerboseLog(bool b) { VerboseLog = b; }
158 // Get the string information about what the threads are doing
159 // Return true if the state has changed
160 bool getThreadState (std::string &state, std::vector<std::string> &stateLog);
162 /** Get the error message (filled after a patch of check)
163 * May be empty if the cause of error is unknown or unhandled
165 const std::string &getLastErrorMessage() { return _ErrorMessage; }
167 // ---------------------
168 // First Part : Checking
169 // ---------------------
171 // start the check of bnp (download description file DescFilename, look at the version of bnps)
172 // init must have been done
173 void startCheckThread(bool includeBackgroundPatch);
175 // if the checkThread ended and is ok then the getDesc* methods can be called
176 bool isCheckThreadEnded(bool &ok);
178 // Get all the optional categories to display for patching
179 void getInfoToDisp(SPatchInfo &piOut);
181 void forceStopCheckThread();
182 // Used by installation software
183 void startInstallThread(const std::vector<CInstallThreadEntry>& entries);
184 // Used by installation software
185 void startDownloadThread(const std::vector<CInstallThreadEntry>& entries);
186 // ----------------------------------------------
187 // Second Part : Downloading and Applying patches
188 // ----------------------------------------------
190 /** start to patch with a set of files
191 * \param commitPatch When true, the patched version of the file will replace the original file, else the patched version
192 * will be left in the /unpack directory and the previous version in /data will remain unchanged.
193 * The background downloader should set this to false.
196 void startPatchThread(const std::vector<std::string> &CategoriesSelected, bool commitPatch);
198 // Return true if patch has ended
199 // Ok is set to true if the patch is ended and the patch process is ok (if the patch is already ended ok is false)
200 bool isPatchThreadEnded (bool &ok);
203 void forceStopPatchThread();
205 bool mustLaunchBatFile() const { return MustLaunchBatFile; }
206 void createBatchFile(CProductDescriptionForClient &descFile, bool wantRyzomRestart = true, bool useBatchFile = true);
207 void executeBatchFile();
208 void deleteBatchFile();
209 void reboot();
211 // TODO : modify it for the second part ...
212 // Maybe we can't get patchs size ... currently, it only returns 1!
214 int getTotalFilesToGet();
215 int getCurrentFilesToGet();
216 int getPatchingSize();
218 // Return % of current file that has been downloaded/patched so far
219 float getCurrentFileProgress() const;
221 bool isDownloadInProgress() { return DownloadInProgress; }
223 // ----------------------------------------------
224 // ScanData Part : optional task which verify all data
225 // ----------------------------------------------
227 // start the full check of BNP
228 void startScanDataThread();
230 // if the scan data thread has ended
231 bool isScanDataThreadEnded(bool &ok);
233 // ask to stop the Scan Data thread. NB: for security, the thread will continue to the current scanned file,
234 // then stop. Hence, you must still wait isScanDataThreadEnded() return true
235 void askForStopScanDataThread();
237 // If the scan thread is not running, touch the files with error, and return the number of corrupted files
238 uint applyScanDataResult();
240 // get the current info Log for data Scan (true if some change from last get, else text is not filled)
241 bool getDataScanLog(std::string &text);
243 CProductDescriptionForClient &getDescFile() { return DescFile; }
245 NLMISC::IThread *getCurrThread() const { return Thread; }
246 // set an external state listener (enable to log) infos
247 void setStateListener(IPatchManagerStateListener* stateListener);
249 // set an external downloader (useful for installer using BitTorrent protocole)
250 void setAsyncDownloader(IAsyncDownloader* asyncDownloader);
251 // get the external downloader (useful for installer using BitTorrent protocole or NULL)
252 IAsyncDownloader* getAsyncDownloader() const;
254 // By default the name used is the name of the current executable.
255 // But for external torrent downloader we must set "client_ryzom_rd.exe"
256 void setRyzomFilename(const std::string& ryzomFilename) { RyzomFilename = ryzomFilename; }
258 // Used when client data is not located in current directory
259 void setClientRootPath(const std::string& clientRootPath);
261 // Used by installation software to download a file only if necessary
262 static bool download(const std::string& patchPath, const std::string& sourcePath,
263 const std::string& tmpDirectory, uint32 timestamp);
264 // Used by installation software to create install.bat file (not used)
265 static bool extract(const std::string& patchPath,
266 const std::vector<std::string>& sourceFilename,
267 const std::vector<std::string>& extractPath,
268 const std::string& updateBatchFilename,
269 const std::string& exectName,
270 void (*stopFun)() );
271 // Installation software must be able to indicate if ryzom must be stated at end of installation
272 void setStartRyzomAtEnd(bool startAtEnd){ _StartRyzomAtEnd = startAtEnd; }
273 // Forward message to installation software if needed
274 void fatalError(const std::string& errorId, const std::string& param1, const std::string& param2);
275 bool bnpUnpack(const std::string &srcBigfile, const std::string &dstPath, std::vector<std::string> &vFilenames);
277 const std::string & getServerVersion () { return ServerVersion; }
278 private:
280 // Methods used by patch & check threads
281 // -------------------------------------
283 friend class CCheckThread;
284 friend class CPatchThread;
285 friend class CScanDataThread;
286 friend class CInstallThread;
287 friend class CDownloadThread;
288 friend class CPatchThreadDownloadProgress;
290 // Set the thread state (called by threads to let us know what they are doing)
291 void setState (bool bOutputToLog, const std::string &ucsState);
292 void touchState();
294 /// Get the version of the server given during init()
297 /// Read the description file (throw exception if it doesn't exist)
298 void readDescFile(sint32 nVersion);
300 /// Read the description of the highest client version file found
301 void readClientVersionAndDescFile();
303 void setRWAccess (const std::string &filename, bool bThrowException=true);
305 std::string deleteFile (const std::string &filename, bool bThrowException=true, bool bWarning=true);
307 // Rename src to dst throw an exception if we cant
308 void renameFile (const std::string &src, const std::string &dst);
310 // Accessors used by the patch thread
311 const std::string &getDescFilename() { return DescFilename; }
312 const std::string &getUpdateBatchFilename() { return UpdateBatchFilename; }
313 const std::string &getRyzomFilename() { return RyzomFilename; }
315 CPatchThread *getPatchThread() { return PatchThread; }
317 // Get a file from the server and decompress it if zipped
318 void getServerFile (const std::string &name, bool bZipped = false, const std::string& destName="", NLMISC::IProgressCallback *progress = NULL);
319 void downloadFileWithCurl (const std::string &source, const std::string &dest, NLMISC::IProgressCallback *progress = NULL);
320 void downloadFile (const std::string &source, const std::string &dest, NLMISC::IProgressCallback *progress = NULL);
321 // Decompress zipped file override destination file
322 void decompressFile (const std::string &filename);
323 void applyDate (const std::string &sFilename, uint32 nDate);
325 void getPatchFromDesc(SFileToPatch &ftpOut, const CBNPFile &fIn, bool forceCheckSumTest);
327 // stop the threads (called when knowing the thread ended)
328 void stopCheckThread();
329 void stopPatchThread();
330 void stopScanDataThread();
332 // add a file to the scan data log
333 void addDataScanLogCorruptedFile(const SFileToPatch &ftp);
334 void clearDataScanLog();
335 static void getCorruptedFileInfo(const SFileToPatch &ftp, std::string &sTranslate);
337 static bool downloadAndUnpack(const std::string& patchPath, const std::string& sourceFilename, const std::string& extractPath, const std::string& tmpDirectory, uint32 timestamp);
338 // Forward message to Installation Software
339 void onFileInstallFinished();
340 void onFileDownloadFinished();
341 void onFileDownloading(const std::string& sourceName, uint32 rate, uint32 fileIndex, uint32 fileCount, uint64 fileSize, uint64 fullSize);
342 void onFileInstalling(const std::string& sourceName, uint32 rate, uint32 fileIndex, uint32 fileCount, uint64 fileSize, uint64 fullSize);
344 private:
346 static int downloadProgressFunc(void *foo, double t, double d, double ultotal, double ulnow);
347 static int validateProgress(void *foo, double t, double d, double ultotal, double ulnow);
349 class MyPatchingCB : public CXDeltaPatch::ICallBack
351 public:
352 std::string patchFilename;
353 std::string srcFilename;
355 virtual void progress(float f);
357 friend class CPatchManager::MyPatchingCB;
359 private:
361 /// Constructor
362 CPatchManager();
364 /// The singleton's instance
365 static CPatchManager* _Instance;
367 class CPatchServer
369 public:
371 CPatchServer(const std::string& serverPath)
373 ServerPath = serverPath;
374 Available = true;
376 if (!ServerPath.empty() && ServerPath[ServerPath.size()-1] != '/')
377 ServerPath += '/';
379 std::string::size_type pos = ServerPath.find ("@");
380 if (pos != std::string::npos)
381 DisplayedServerPath = "http://" + ServerPath.substr (pos+1);
382 else
383 DisplayedServerPath = ServerPath;
386 std::string ServerPath;
387 std::string DisplayedServerPath;
388 bool Available;
391 // Patch Servers
392 std::vector<CPatchServer> PatchServers;
393 sint UsedServer;
395 // Server desc
396 std::string ServerPath;
397 std::string DisplayedServerPath;
398 std::string ServerVersion;
400 bool DownloadInProgress;
402 /// Description file
403 std::string DescFilename;
404 bool ValidDescFile;
405 CProductDescriptionForClient DescFile;
406 std::vector<SFileToPatch> FilesToPatch;
407 std::vector<std::string> OptionalCat;
409 std::string _ErrorMessage;
411 // Threads
412 CPatchThread *PatchThread;
413 CCheckThread *CheckThread;
414 CScanDataThread *ScanDataThread;
415 CInstallThread *InstallThread;
416 CDownloadThread *DownloadThread;
417 NLMISC::IThread *Thread;
419 // State
420 struct CState
422 std::string State;
423 std::vector<std::string> StateLog;
424 bool StateChanged;
425 CState()
427 StateChanged= false;
430 NLMISC::CSynchronized<CState> State;
431 std::string LogSeparator;
432 std::string CurrentFile;
435 // Useful pathes and names
437 /// Now deprecated : the launcher is the client ryzom
438 std::string RyzomFilename;
439 std::string UpdateBatchFilename;
440 std::string UpgradeBatchFilename;
442 // Where the client get all delta and desc file
443 std::string ClientPatchPath; // Temporary path
444 std::string ReadableClientDataPath; // Where original data can be found
445 std::string WritableClientDataPath; // Where data can be written
447 /// Output useful information for debugging in the log file
448 bool VerboseLog;
450 bool MustLaunchBatFile; // And then relaunch ryzom
452 // For Data Scan, list of files with checksum error => should delete them
453 struct CDataScanState
455 std::vector<SFileToPatch> FilesWithScanDataError;
456 bool Changed;
457 CDataScanState()
459 Changed= false;
462 typedef NLMISC::CSynchronized<CDataScanState> TSyncDataScanState;
463 TSyncDataScanState DataScanState;
464 // The date to apply when file is buggy: use default of year 2001, just to have a coherent date
465 enum {DefaultResetDate= 31 * 366 * 24 * 3600};
466 // The file size of a an empty BNP
467 // If the BNP Header format change, please modify 'EmptyBnpFileSize' as needed
468 enum {EmptyBnpFileSize= 8};
469 // Use an external downloader: (BitTorrent)
470 IAsyncDownloader* _AsyncDownloader;
471 IPatchManagerStateListener* _StateListener;// Alternate log
472 bool _StartRyzomAtEnd;
473 public:
474 // used by threads to signal error at the end of execution
475 void setErrorMessage(const std::string &message);
480 * \author Matthieu 'TrapII' Besson
481 * \author Vianney 'Ace' Lecroart
482 * \author Nevrax France
483 * \date July 2004
485 class CCheckThread : public NLMISC::IRunnable
488 public:
490 CCheckThread(bool includeBackgroundPatch);
492 public:
494 bool Ended; // true if the thread have ended
495 bool CheckOk; // true if the check is good
496 bool StopAsked;
498 int TotalFileToCheck;
499 int CurrentFileChecked;
500 bool IncludeBackgroundPatch;
502 private:
504 void run();
509 * class managing the patch getting files from server and applying patches
510 * \author Matthieu 'TrapII' Besson
511 * \author Vianney 'Ace' Lecroart
512 * \author Nevrax France
513 * \date July 2004
515 class CPatchThread : public NLMISC::IRunnable
518 public:
520 bool Ended; // true if the thread have ended the patch
521 bool PatchOk; // true if the patch was good
522 bool StopAsked;
524 public:
526 CPatchThread(bool commitPatch);
528 // Clear the list of files to patch
529 void clear();
531 // Add files to be patched (avoid multiple time the same file)
532 void add(const CPatchManager::SFileToPatch &ftp);
534 int getNbFileToPatch() { return (int)AllFilesToPatch.size(); }
535 int getCurrentFilePatched() { return (int) floorf(CurrentFilePatched); }
536 int getPatchingSize() { return PatchSizeProgress; }
537 float getCurrentFileProgress() const { return fmodf(CurrentFilePatched, 1.f); }
539 private:
541 std::vector<CPatchManager::SFileToPatch> AllFilesToPatch;
542 float CurrentFilePatched;
543 int PatchSizeProgress;
544 bool _CommitPatch;
547 friend class CPatchThreadDownloadProgress;
548 private:
550 void run();
551 void processFile (CPatchManager::SFileToPatch &rFTP);
552 bool xDeltaPatch(const std::string &patch, const std::string &src, const std::string &out);
556 * This thread peforms the installation of file that have been downloaded via asynchrous download (BitTorrent)
557 * It unzip, delete obsolete file, extract file from bnp
561 class CInstallThread : public NLMISC::IRunnable
563 public:
564 CInstallThread(const std::vector<CInstallThreadEntry> entries):_Entries(entries){}
565 void run();
566 std::vector<CInstallThreadEntry> _Entries;
569 class CDownloadThread : public NLMISC::IRunnable
571 public:
572 CDownloadThread(const std::vector<CInstallThreadEntry> entries):_Entries(entries){}
573 void run();
574 std::vector<CInstallThreadEntry> _Entries;
578 * This thread perform a checksum check on all existing files registered in the local .idx
579 * \author Lionel Berenguier
580 * \author Nevrax France
581 * \date July 2004
583 class CScanDataThread : public NLMISC::IRunnable
586 public:
588 CScanDataThread();
590 public:
592 // Written by MainThread, read by thread
593 bool AskForCancel; // true if the main thread ask to cancel the task
595 // Written by thread, read by Main Thread
596 bool Ended; // true if the thread have ended
597 bool CheckOk; // true if the check is good
598 int TotalFileToScan;
599 int CurrentFileScanned;
601 private:
603 void run();
608 #endif // CL_PATCH_H
610 /* End of login_patch.h */