-
-
Notifications
You must be signed in to change notification settings - Fork 52
Integrating SimplePatchTool
To add patching support to your apps, you can create an instance of SimplePatchTool (SimplePatchToolCore namespace), configure it and then execute it. SimplePatchTool runs in a separate thread in the background, so you will probably want to fetch its progress from time to time to update your UI accordingly.
public SimplePatchTool( string rootPath, string versionInfoURL )
: creates a new SimplePatchTool instance
-
rootPath: the path of the application directory (you may use
Path.GetDirectoryName(PatchUtils.GetCurrentExecutablePath())
, if your executable resides at the at the root of the application directory) - versionInfoURL: download URL of the VersionInfo.info (if you don't have a versionInfoURL yet, see Generating versionInfoURL)
SimplePatchTool UseRepairPatch( bool canRepairPatch )
: sets whether or not repair patch can be used to patch the application
SimplePatchTool UseIncrementalPatch( bool canIncrementalPatch )
: sets whether or not incremental patches can be used to patch the application
SimplePatchTool VerifyFilesOnServer( bool verifyFiles )
: if verifyFiles is set to true, files on the server will be verified
SimplePatchTool UseCustomDownloadHandler( DownloadHandlerFactory factoryFunction )
: instructs SimplePatchTool to use a custom download handler. By default, a WebClient based download handler is used but on some platforms (e.g. Unity), WebClient may not support https urls. In such cases, you may want to use a custom download handler implementation that supports https. DownloadHandlerFactory has the following signature: delegate IDownloadHandler DownloadHandlerFactory()
SimplePatchTool UseCustomFreeSpaceCalculator( FreeDiskSpaceCalculator freeSpaceCalculatorFunction )
: by default, SimplePatchTool uses the DriveInfo.AvailableFreeSpace property to determine the free space of a drive but on some platforms (e.g. Unity), it may not be supported. In such cases, you may want to use a custom function to calculate the free space of a drive correctly (or, you can use a function that returns long.MaxValue to skip free space check entirely). FreeDiskSpaceCalculator has the following signature: delegate long FreeDiskSpaceCalculator( string drive )
SimplePatchTool UseVersionInfoVerifier( XMLVerifier verifierFunction )
: instructs SimplePatchTool to verify the downloaded VersionInfo with the provided function. XMLVerifier has the following signature: delegate bool XMLVerifier( ref string xmlContents )
. This function must return true only if the downloaded VersionInfo (xmlContents) is genuine. If you use a custom layer of security that e.g. encrypts the contents of the VersionInfo, you should first decrypt xmlContents. A VersionInfo/PatchInfo verifier is not mandatory and should not be used if you don't sign/encrypt your VersionInfo and/or PatchInfo'es
SimplePatchTool UsePatchInfoVerifier( XMLVerifier verifierFunction )
: instructs SimplePatchTool to verify the downloaded PatchInfo'es with the provided function. For example, the following code uses the XMLSigner.VerifyXMLContents function to verify the VersionInfo and PatchInfo files that have been signed with the XMLSigner.SignXMLFile function (or with the Patcher sign_xml
console command):
patcher.UseVersionInfoVerifier( ( ref string xml ) => XMLSigner.VerifyXMLContents( xml, publicRSAKey ) )
.UsePatchInfoVerifier( ( ref string xml ) => XMLSigner.VerifyXMLContents( xml, publicRSAKey ) );
SimplePatchTool LogProgress( bool value )
: sets whether or not SimplePatchTool should log any IOperationProgress data. This interface has two properties: int Percentage { get; }
(between 0 and 100) and string ProgressInfo { get; }
(localized description for the progress). Currently, two operations provide progress info: DownloadProgress and FilePatchProgress
SimplePatchTool SilentMode( bool silent )
: sets whether or not SimplePatchTool should log anything (excluding IOperationProgress data)
SimplePatchTool LogToFile( bool value )
: sets whether or not SimplePatchTool should write logs to a file. This log file will be located inside the cache directory with name logs.dat. Note that this file gets deleted when the cache directory is cleared after a successful patch
bool CheckForUpdates( bool checkVersionOnly = true )
: asynchronously checks whether or not app is up-to-date in a separate thread. Returns false, if SimplePatchTool is already checking for updates or applying a patch. If checkVersionOnly is set to true, only the version code of the app (e.g. 1.0.0) is compared against the VersionInfo's version code. Otherwise, hashes and sizes of the files in the application directory are compared against VersionInfo (i.e. integrity check)
bool Run( bool selfPatching )
: starts patching the application directory (rootPath) asynchronously in a separate thread. It is not mandatory to check for updates beforehand because this function internally checks for updates, as well. You can perform self patching only if you have a self patcher executable that was distributed with your application. This function returns false, if SimplePatchTool is already running
string FetchLog()
: fetches the next log that SimplePatchTool has generated. Returns null, if there is no log in the queue
IOperationProgress FetchProgress()
: returns an IOperationProgress instance if patcher's progress has changed, null otherwise
bool IsRunning { get; }
: returns true if SimplePatchTool is currently checking for updates or applying a patch
void Cancel()
: cancels the current operation
PatchOperation Operation { get; }
: returns CheckingForUpdates, if last operation was/currently running is CheckForUpdates; Patching, if it was/is Run(false) and SelfPatching, if it was/is Run(true)
PatchStage PatchStage { get; }
: returns the current stage of the patcher (e.g. CheckingUpdates, DownloadingFiles, DeletingObsoleteFiles and so on)
PatchResult Result { get; }
: returns different values for different Operation's. Its value should be checked after IsRunning returns false:
- CheckingForUpdates: returns PatchResult.AlreadyUpToDate if app is up-to-date, PatchResult.Success if there is an update for the app, and PatchResult.Failed if there was an error while checking for updates
- Patching/SelfPatching: returns PatchResult.AlreadyUpToDate if app is already up-to-date, PatchResult.Success if app is updated successfully, and PatchResult.Failed if there was an error while updating the app. In self patching mode, a value of PatchResult.Success means that we are ready to terminate the app and launch the self patcher executable (see ApplySelfPatch function below)
PatchFailReason FailReason { get; }
: if Result is PatchResult.Failed, this property stores why the patcher has failed (e.g. Cancelled, InsufficientSpace, XmlDeserializeError and so on). You may want to execute special logic for the following cases:
- RequiresAdminPriviledges: we need admin permissions to update the files in the application directory
- FilesAreNotUpToDateAfterPatch: after applying the patch, app is somehow still not up-to-date
- UnderMaintenance_AbortApp: servers are currently under maintenance and users should not be allowed to launch the app
- UnderMaintenance_CanLaunchApp: servers are currently under maintenance but users can continue using the app
string FailDetails { get; }
: if Result is PatchResult.Failed, returns a localized string that briefly explains why the patcher has failed
bool ApplySelfPatch( string selfPatcherExecutable, string postSelfPatchExecutable = null )
: terminates the app and runs the self patcher executable. You must pass the path of the self patcher executable to the selfPatcherExecutable parameter. If you'd like to launch an executable after self patcher executes successfully (e.g. to restart the app after self patching is complete), pass the path of that executable to the postSelfPatchExecutable parameter. This function should only be called if Operation is SelfPatching and Result is Success. Returns false, if something goes wrong
Example code: SimplePatchToolConsoleApp.Program.CheckForUpdates and SimplePatchToolConsoleApp.Program.ApplyPatch
NOTE: it is possible for an application to self patch itself, which eliminates the need for a launcher; but it is not recommended for large applications because if user terminates the self patcher executable before it updates all the files in the application directory (which may take some time for large applications), then the application may become corrupt.