2017-11-18 17:27:06 +01:00
// _ _ _ ____ _ _____
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
//
2018-07-27 04:52:14 +02:00
// Copyright 2015-2018 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
2017-11-18 17:27:06 +01:00
//
2018-07-27 04:52:14 +02:00
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
2017-11-18 17:27:06 +01:00
//
2018-07-27 04:52:14 +02:00
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2016-08-02 06:04:44 +02:00
using System ;
2016-10-07 01:36:02 +02:00
using System.Collections.Concurrent ;
2016-08-02 06:04:44 +02:00
using System.IO ;
2017-07-01 04:06:33 +02:00
using System.IO.Compression ;
2016-08-02 06:04:44 +02:00
using System.Linq ;
using System.Threading ;
using System.Threading.Tasks ;
2017-01-06 13:20:36 +01:00
using ArchiSteamFarm.Localization ;
2018-09-08 01:03:55 +02:00
using ArchiSteamFarm.NLog ;
2016-08-02 06:04:44 +02:00
namespace ArchiSteamFarm {
internal static class ASF {
2017-01-31 01:10:01 +01:00
internal static readonly ArchiLogger ArchiLogger = new ArchiLogger ( SharedInfo . ASF ) ;
2018-10-16 02:30:16 +02:00
private static readonly ConcurrentDictionary < string , object > LastWriteEvents = new ConcurrentDictionary < string , object > ( ) ;
2018-09-17 00:42:24 +02:00
private static readonly SemaphoreSlim UpdateSemaphore = new SemaphoreSlim ( 1 , 1 ) ;
2016-10-07 01:36:02 +02:00
2016-08-02 06:04:44 +02:00
private static Timer AutoUpdatesTimer ;
2016-10-07 01:36:02 +02:00
private static FileSystemWatcher FileSystemWatcher ;
2016-08-02 06:04:44 +02:00
2016-12-24 19:27:36 +01:00
internal static async Task InitBots ( ) {
2016-11-13 15:51:35 +01:00
if ( Bot . Bots . Count ! = 0 ) {
return ;
}
2017-07-21 02:13:03 +02:00
// Before attempting to connect, initialize our configuration
2017-07-21 14:25:25 +02:00
await Bot . InitializeSteamConfiguration ( Program . GlobalConfig . SteamProtocols , Program . GlobalDatabase . CellID , Program . GlobalDatabase . ServerListProvider ) . ConfigureAwait ( false ) ;
2016-11-13 15:51:35 +01:00
2018-05-13 19:19:27 +02:00
try {
2018-09-19 18:25:17 +02:00
await Utilities . InParallel ( Directory . EnumerateFiles ( SharedInfo . ConfigDirectory , "*" + SharedInfo . ConfigExtension ) . Select ( Path . GetFileNameWithoutExtension ) . Where ( botName = > ! string . IsNullOrEmpty ( botName ) & & IsValidBotName ( botName ) ) . OrderBy ( botName = > botName ) . Select ( Bot . RegisterBot ) ) . ConfigureAwait ( false ) ;
2018-05-13 19:19:27 +02:00
} catch ( Exception e ) {
ArchiLogger . LogGenericException ( e ) ;
return ;
2016-11-13 15:51:35 +01:00
}
if ( Bot . Bots . Count = = 0 ) {
2017-01-31 01:10:01 +01:00
ArchiLogger . LogGenericWarning ( Strings . ErrorNoBotsDefined ) ;
2016-11-13 15:51:35 +01:00
}
}
2017-02-13 20:53:06 +01:00
internal static void InitEvents ( ) {
2016-10-07 01:36:02 +02:00
if ( FileSystemWatcher ! = null ) {
return ;
}
2018-02-17 19:29:33 +01:00
FileSystemWatcher = new FileSystemWatcher ( SharedInfo . ConfigDirectory ) { NotifyFilter = NotifyFilters . FileName | NotifyFilters . LastWrite } ;
2016-10-07 01:36:02 +02:00
FileSystemWatcher . Changed + = OnChanged ;
FileSystemWatcher . Created + = OnCreated ;
FileSystemWatcher . Deleted + = OnDeleted ;
FileSystemWatcher . Renamed + = OnRenamed ;
FileSystemWatcher . EnableRaisingEvents = true ;
}
2018-09-15 22:34:32 +02:00
internal static bool IsOwner ( ulong steamID ) {
if ( steamID = = 0 ) {
ArchiLogger . LogNullError ( nameof ( steamID ) ) ;
return false ;
}
return ( steamID = = Program . GlobalConfig . SteamOwnerID ) | | ( Debugging . IsDebugBuild & & ( steamID = = SharedInfo . ArchiSteamID ) ) ;
}
2018-09-17 00:42:24 +02:00
internal static async Task RestartOrExit ( ) {
if ( Program . RestartAllowed & & Program . GlobalConfig . AutoRestart ) {
ArchiLogger . LogGenericInfo ( Strings . Restarting ) ;
await Task . Delay ( 5000 ) . ConfigureAwait ( false ) ;
await Program . Restart ( ) . ConfigureAwait ( false ) ;
} else {
ArchiLogger . LogGenericInfo ( Strings . Exiting ) ;
await Task . Delay ( 5000 ) . ConfigureAwait ( false ) ;
await Program . Exit ( ) . ConfigureAwait ( false ) ;
}
}
internal static async Task < Version > Update ( bool updateOverride = false ) {
if ( ! SharedInfo . BuildInfo . CanUpdate | | ( Program . GlobalConfig . UpdateChannel = = GlobalConfig . EUpdateChannel . None ) ) {
return null ;
}
await UpdateSemaphore . WaitAsync ( ) . ConfigureAwait ( false ) ;
try {
ArchiLogger . LogGenericInfo ( Strings . UpdateCheckingNewVersion ) ;
// Cleanup from previous update - update directory for old in-use runtime files
string backupDirectory = Path . Combine ( SharedInfo . HomeDirectory , SharedInfo . UpdateDirectory ) ;
if ( Directory . Exists ( backupDirectory ) ) {
// It's entirely possible that old process is still running, wait a short moment for eventual cleanup
await Task . Delay ( 5000 ) . ConfigureAwait ( false ) ;
try {
Directory . Delete ( backupDirectory , true ) ;
} catch ( Exception e ) {
ArchiLogger . LogGenericException ( e ) ;
return null ;
}
}
// Cleanup from previous update - old non-runtime in-use files
try {
foreach ( string file in Directory . EnumerateFiles ( SharedInfo . HomeDirectory , "*.old" , SearchOption . AllDirectories ) ) {
File . Delete ( file ) ;
}
} catch ( Exception e ) {
ArchiLogger . LogGenericException ( e ) ;
return null ;
}
2018-09-22 01:17:24 +02:00
GitHub . ReleaseResponse releaseResponse = await GitHub . GetLatestRelease ( Program . GlobalConfig . UpdateChannel = = GlobalConfig . EUpdateChannel . Stable ) . ConfigureAwait ( false ) ;
if ( releaseResponse = = null ) {
ArchiLogger . LogGenericWarning ( Strings . ErrorUpdateCheckFailed ) ;
return null ;
2018-09-17 00:42:24 +02:00
}
if ( string . IsNullOrEmpty ( releaseResponse . Tag ) ) {
ArchiLogger . LogGenericWarning ( Strings . ErrorUpdateCheckFailed ) ;
return null ;
}
Version newVersion = new Version ( releaseResponse . Tag ) ;
ArchiLogger . LogGenericInfo ( string . Format ( Strings . UpdateVersionInfo , SharedInfo . Version , newVersion ) ) ;
if ( SharedInfo . Version = = newVersion ) {
return SharedInfo . Version ;
}
if ( SharedInfo . Version > newVersion ) {
ArchiLogger . LogGenericWarning ( Strings . WarningPreReleaseVersion ) ;
await Task . Delay ( 15 * 1000 ) . ConfigureAwait ( false ) ;
return SharedInfo . Version ;
}
if ( ! updateOverride & & ( Program . GlobalConfig . UpdatePeriod = = 0 ) ) {
ArchiLogger . LogGenericInfo ( Strings . UpdateNewVersionAvailable ) ;
await Task . Delay ( 5000 ) . ConfigureAwait ( false ) ;
return null ;
}
// Auto update logic starts here
if ( releaseResponse . Assets = = null ) {
ArchiLogger . LogGenericWarning ( Strings . ErrorUpdateNoAssets ) ;
return null ;
}
string targetFile = SharedInfo . ASF + "-" + SharedInfo . BuildInfo . Variant + ".zip" ;
GitHub . ReleaseResponse . Asset binaryAsset = releaseResponse . Assets . FirstOrDefault ( asset = > asset . Name . Equals ( targetFile , StringComparison . OrdinalIgnoreCase ) ) ;
if ( binaryAsset = = null ) {
ArchiLogger . LogGenericWarning ( Strings . ErrorUpdateNoAssetForThisVersion ) ;
return null ;
}
if ( string . IsNullOrEmpty ( binaryAsset . DownloadURL ) ) {
ArchiLogger . LogNullError ( nameof ( binaryAsset . DownloadURL ) ) ;
return null ;
}
2018-09-22 01:17:24 +02:00
if ( ! string . IsNullOrEmpty ( releaseResponse . ChangelogPlainText ) ) {
2018-09-23 02:31:03 +02:00
ArchiLogger . LogGenericInfo ( releaseResponse . ChangelogPlainText ) ;
2018-09-21 03:29:54 +02:00
}
2018-09-17 00:42:24 +02:00
ArchiLogger . LogGenericInfo ( string . Format ( Strings . UpdateDownloadingNewVersion , newVersion , binaryAsset . Size / 1024 / 1024 ) ) ;
WebBrowser . BinaryResponse response = await Program . WebBrowser . UrlGetToBinaryWithProgress ( binaryAsset . DownloadURL ) . ConfigureAwait ( false ) ;
if ( response ? . Content = = null ) {
return null ;
}
try {
using ( ZipArchive zipArchive = new ZipArchive ( new MemoryStream ( response . Content ) ) ) {
if ( ! UpdateFromArchive ( zipArchive , SharedInfo . HomeDirectory ) ) {
ArchiLogger . LogGenericError ( Strings . WarningFailed ) ;
}
}
} catch ( Exception e ) {
ArchiLogger . LogGenericException ( e ) ;
return null ;
}
if ( OS . IsUnix ) {
string executable = Path . Combine ( SharedInfo . HomeDirectory , SharedInfo . AssemblyName ) ;
if ( File . Exists ( executable ) ) {
OS . UnixSetFileAccessExecutable ( executable ) ;
}
}
ArchiLogger . LogGenericInfo ( Strings . UpdateFinished ) ;
return newVersion ;
} finally {
UpdateSemaphore . Release ( ) ;
}
}
internal static async Task UpdateAndRestart ( ) {
if ( ! SharedInfo . BuildInfo . CanUpdate | | ( Program . GlobalConfig . UpdateChannel = = GlobalConfig . EUpdateChannel . None ) ) {
return ;
}
if ( ( AutoUpdatesTimer = = null ) & & ( Program . GlobalConfig . UpdatePeriod > 0 ) ) {
TimeSpan autoUpdatePeriod = TimeSpan . FromHours ( Program . GlobalConfig . UpdatePeriod ) ;
AutoUpdatesTimer = new Timer (
async e = > await UpdateAndRestart ( ) . ConfigureAwait ( false ) ,
null ,
autoUpdatePeriod , // Delay
autoUpdatePeriod // Period
) ;
ArchiLogger . LogGenericInfo ( string . Format ( Strings . AutoUpdateCheckInfo , autoUpdatePeriod . ToHumanReadable ( ) ) ) ;
}
Version newVersion = await Update ( ) . ConfigureAwait ( false ) ;
if ( ( newVersion = = null ) | | ( newVersion < = SharedInfo . Version ) ) {
return ;
}
await RestartOrExit ( ) . ConfigureAwait ( false ) ;
}
2018-10-16 02:30:16 +02:00
private static async Task < bool > CanHandleWriteEvent ( string name ) {
// Save our event in dictionary
object currentWriteEvent = new object ( ) ;
LastWriteEvents [ name ] = currentWriteEvent ;
// Wait a second for eventual other events to arrive
await Task . Delay ( 1000 ) . ConfigureAwait ( false ) ;
// We're allowed to handle this event if the one that is saved after full second is our event and we succeed in clearing it (we don't care what we're clearing anymore, it doesn't have to be atomic operation)
return LastWriteEvents . TryGetValue ( name , out object savedWriteEvent ) & & ( currentWriteEvent = = savedWriteEvent ) & & LastWriteEvents . TryRemove ( name , out _ ) ;
}
2017-07-07 07:02:06 +02:00
private static bool IsValidBotName ( string botName ) {
if ( string . IsNullOrEmpty ( botName ) ) {
ArchiLogger . LogNullError ( nameof ( botName ) ) ;
return false ;
}
if ( botName [ 0 ] = = '.' ) {
return false ;
}
switch ( botName ) {
case SharedInfo . ASF :
return false ;
default :
return true ;
}
}
2016-10-07 01:36:02 +02:00
private static async void OnChanged ( object sender , FileSystemEventArgs e ) {
if ( ( sender = = null ) | | ( e = = null ) ) {
2017-01-31 01:10:01 +01:00
ArchiLogger . LogNullError ( nameof ( sender ) + " || " + nameof ( e ) ) ;
2016-10-07 01:36:02 +02:00
return ;
}
2018-02-17 19:29:33 +01:00
await OnChangedFile ( e . Name , e . FullPath ) . ConfigureAwait ( false ) ;
}
private static async Task OnChangedConfigFile ( string name , string fullPath ) {
if ( string . IsNullOrEmpty ( name ) | | string . IsNullOrEmpty ( fullPath ) ) {
ArchiLogger . LogNullError ( nameof ( name ) + " || " + nameof ( fullPath ) ) ;
return ;
}
2018-02-17 20:42:47 +01:00
await OnCreatedConfigFile ( name , fullPath ) . ConfigureAwait ( false ) ;
2018-02-17 19:29:33 +01:00
}
private static async Task OnChangedFile ( string name , string fullPath ) {
string extension = Path . GetExtension ( name ) ;
switch ( extension ) {
case SharedInfo . ConfigExtension :
await OnChangedConfigFile ( name , fullPath ) . ConfigureAwait ( false ) ;
break ;
case SharedInfo . KeysExtension :
await OnChangedKeysFile ( name , fullPath ) . ConfigureAwait ( false ) ;
break ;
}
}
private static async Task OnChangedKeysFile ( string name , string fullPath ) {
if ( string . IsNullOrEmpty ( name ) | | string . IsNullOrEmpty ( fullPath ) ) {
ArchiLogger . LogNullError ( nameof ( name ) + " || " + nameof ( fullPath ) ) ;
return ;
}
await OnCreatedKeysFile ( name , fullPath ) . ConfigureAwait ( false ) ;
2016-10-07 01:36:02 +02:00
}
2017-04-01 16:41:01 +02:00
private static async void OnCreated ( object sender , FileSystemEventArgs e ) {
2016-10-07 01:36:02 +02:00
if ( ( sender = = null ) | | ( e = = null ) ) {
2017-01-31 01:10:01 +01:00
ArchiLogger . LogNullError ( nameof ( sender ) + " || " + nameof ( e ) ) ;
2016-10-07 01:36:02 +02:00
return ;
}
2017-09-04 11:34:50 +02:00
await OnCreatedFile ( e . Name , e . FullPath ) . ConfigureAwait ( false ) ;
}
2018-02-17 19:29:33 +01:00
private static async Task OnCreatedConfigFile ( string name , string fullPath ) {
2017-09-04 11:34:50 +02:00
if ( string . IsNullOrEmpty ( name ) | | string . IsNullOrEmpty ( fullPath ) ) {
ArchiLogger . LogNullError ( nameof ( name ) + " || " + nameof ( fullPath ) ) ;
2018-02-17 19:29:33 +01:00
return ;
2017-09-04 11:34:50 +02:00
}
string botName = Path . GetFileNameWithoutExtension ( name ) ;
2017-05-17 02:09:42 +02:00
if ( string . IsNullOrEmpty ( botName ) | | ( botName [ 0 ] = = '.' ) ) {
2018-02-17 19:29:33 +01:00
return ;
2016-10-07 01:36:02 +02:00
}
2018-10-16 02:30:16 +02:00
if ( ! await CanHandleWriteEvent ( name ) . ConfigureAwait ( false ) ) {
return ;
2017-09-13 04:51:49 +02:00
}
2017-04-01 16:41:01 +02:00
if ( botName . Equals ( SharedInfo . ASF ) ) {
ArchiLogger . LogGenericInfo ( Strings . GlobalConfigChanged ) ;
await RestartOrExit ( ) . ConfigureAwait ( false ) ;
2018-02-17 19:29:33 +01:00
return ;
2017-09-04 11:34:50 +02:00
}
if ( ! IsValidBotName ( botName ) ) {
2018-02-17 19:29:33 +01:00
return ;
2017-04-01 16:41:01 +02:00
}
2018-02-17 20:42:47 +01:00
if ( Bot . Bots . TryGetValue ( botName , out Bot bot ) ) {
await bot . OnConfigChanged ( false ) . ConfigureAwait ( false ) ;
} else {
await Bot . RegisterBot ( botName ) . ConfigureAwait ( false ) ;
}
2018-02-17 19:29:33 +01:00
}
private static async Task OnCreatedFile ( string name , string fullPath ) {
if ( string . IsNullOrEmpty ( name ) | | string . IsNullOrEmpty ( fullPath ) ) {
ArchiLogger . LogNullError ( nameof ( name ) + " || " + nameof ( fullPath ) ) ;
return ;
}
string extension = Path . GetExtension ( name ) ;
switch ( extension ) {
case SharedInfo . ConfigExtension :
await OnCreatedConfigFile ( name , fullPath ) . ConfigureAwait ( false ) ;
break ;
case SharedInfo . KeysExtension :
await OnCreatedKeysFile ( name , fullPath ) . ConfigureAwait ( false ) ;
break ;
}
}
private static async Task OnCreatedKeysFile ( string name , string fullPath ) {
if ( string . IsNullOrEmpty ( name ) | | string . IsNullOrEmpty ( fullPath ) ) {
ArchiLogger . LogNullError ( nameof ( name ) + " || " + nameof ( fullPath ) ) ;
return ;
}
string botName = Path . GetFileNameWithoutExtension ( name ) ;
if ( string . IsNullOrEmpty ( botName ) | | ( botName [ 0 ] = = '.' ) ) {
return ;
}
2018-10-16 02:30:16 +02:00
if ( ! await CanHandleWriteEvent ( name ) . ConfigureAwait ( false ) ) {
return ;
2018-02-17 19:29:33 +01:00
}
if ( ! Bot . Bots . TryGetValue ( botName , out Bot bot ) ) {
return ;
}
await bot . ImportKeysToRedeem ( fullPath ) . ConfigureAwait ( false ) ;
2016-10-07 01:36:02 +02:00
}
2017-02-01 00:44:52 +01:00
private static async void OnDeleted ( object sender , FileSystemEventArgs e ) {
2016-10-07 01:36:02 +02:00
if ( ( sender = = null ) | | ( e = = null ) ) {
2017-01-31 01:10:01 +01:00
ArchiLogger . LogNullError ( nameof ( sender ) + " || " + nameof ( e ) ) ;
2016-10-07 01:36:02 +02:00
return ;
}
2017-09-04 11:34:50 +02:00
await OnDeletedFile ( e . Name , e . FullPath ) . ConfigureAwait ( false ) ;
}
2018-02-17 19:29:33 +01:00
private static async Task OnDeletedConfigFile ( string name , string fullPath ) {
2017-09-04 11:34:50 +02:00
if ( string . IsNullOrEmpty ( name ) | | string . IsNullOrEmpty ( fullPath ) ) {
ArchiLogger . LogNullError ( nameof ( name ) + " || " + nameof ( fullPath ) ) ;
2018-02-17 19:29:33 +01:00
return ;
2017-09-04 11:34:50 +02:00
}
string botName = Path . GetFileNameWithoutExtension ( name ) ;
2016-10-14 20:22:28 +02:00
if ( string . IsNullOrEmpty ( botName ) ) {
2018-02-17 19:29:33 +01:00
return ;
2016-10-14 20:22:28 +02:00
}
2018-10-16 02:30:16 +02:00
if ( ! await CanHandleWriteEvent ( name ) . ConfigureAwait ( false ) ) {
return ;
2017-09-13 04:51:49 +02:00
}
2016-10-14 20:22:28 +02:00
if ( botName . Equals ( SharedInfo . ASF ) ) {
2017-09-04 11:34:50 +02:00
if ( File . Exists ( fullPath ) ) {
2018-02-17 19:29:33 +01:00
return ;
2017-09-04 11:34:50 +02:00
}
2017-04-01 16:41:01 +02:00
// Some editors might decide to delete file and re-create it in order to modify it
// If that's the case, we wait for maximum of 5 seconds before shutting down
await Task . Delay ( 5000 ) . ConfigureAwait ( false ) ;
2017-09-04 11:34:50 +02:00
if ( File . Exists ( fullPath ) ) {
2018-02-17 19:29:33 +01:00
return ;
2017-04-01 16:41:01 +02:00
}
2017-01-31 01:10:01 +01:00
ArchiLogger . LogGenericError ( Strings . ErrorGlobalConfigRemoved ) ;
2017-02-01 00:44:52 +01:00
await Program . Exit ( 1 ) . ConfigureAwait ( false ) ;
2018-02-17 19:29:33 +01:00
return ;
2016-10-14 20:22:28 +02:00
}
2018-02-17 20:42:47 +01:00
if ( ! IsValidBotName ( botName ) ) {
return ;
}
2017-03-14 08:41:33 -03:00
if ( Bot . Bots . TryGetValue ( botName , out Bot bot ) ) {
2018-02-17 20:42:47 +01:00
await bot . OnConfigChanged ( true ) . ConfigureAwait ( false ) ;
2016-10-14 20:22:28 +02:00
}
2016-10-07 01:36:02 +02:00
}
2018-02-17 19:29:33 +01:00
private static async Task OnDeletedFile ( string name , string fullPath ) {
if ( string . IsNullOrEmpty ( name ) | | string . IsNullOrEmpty ( fullPath ) ) {
ArchiLogger . LogNullError ( nameof ( name ) + " || " + nameof ( fullPath ) ) ;
2016-10-07 01:36:02 +02:00
return ;
}
2018-02-17 19:29:33 +01:00
string extension = Path . GetExtension ( name ) ;
2016-10-14 20:22:28 +02:00
2018-02-17 19:29:33 +01:00
switch ( extension ) {
case SharedInfo . ConfigExtension :
await OnDeletedConfigFile ( name , fullPath ) . ConfigureAwait ( false ) ;
break ;
2016-10-14 20:22:28 +02:00
}
2018-02-17 19:29:33 +01:00
}
2016-10-14 20:22:28 +02:00
2018-02-17 19:29:33 +01:00
private static async void OnRenamed ( object sender , RenamedEventArgs e ) {
if ( ( sender = = null ) | | ( e = = null ) ) {
ArchiLogger . LogNullError ( nameof ( sender ) + " || " + nameof ( e ) ) ;
return ;
2016-10-14 20:22:28 +02:00
}
2018-02-17 19:29:33 +01:00
await OnDeletedFile ( e . OldName , e . OldFullPath ) . ConfigureAwait ( false ) ;
await OnCreatedFile ( e . Name , e . FullPath ) . ConfigureAwait ( false ) ;
2016-10-07 01:36:02 +02:00
}
2016-11-24 07:32:16 +01:00
2018-06-11 01:24:54 +02:00
private static bool UpdateFromArchive ( ZipArchive archive , string targetDirectory ) {
2017-07-05 04:27:42 +02:00
if ( ( archive = = null ) | | string . IsNullOrEmpty ( targetDirectory ) ) {
ArchiLogger . LogNullError ( nameof ( archive ) + " || " + nameof ( targetDirectory ) ) ;
2018-06-11 01:24:54 +02:00
return false ;
2017-07-01 04:06:33 +02:00
}
2017-07-05 04:25:48 +02:00
string backupDirectory = Path . Combine ( targetDirectory , SharedInfo . UpdateDirectory ) ;
2017-07-01 06:10:15 +02:00
Directory . CreateDirectory ( backupDirectory ) ;
2017-07-01 04:06:33 +02:00
2017-07-01 06:10:15 +02:00
// Move top-level runtime in-use files to other directory
// We must do it in order to not crash at later stage - all libraries/executables must keep original names
2017-07-07 06:54:54 +02:00
foreach ( string file in Directory . EnumerateFiles ( targetDirectory ) ) {
2017-08-05 15:13:06 +02:00
string fileName = Path . GetFileName ( file ) ;
switch ( fileName ) {
// Files that we want to keep in original directory
case "NLog.config" :
continue ;
2018-06-11 01:24:54 +02:00
case null :
ArchiLogger . LogNullError ( nameof ( fileName ) ) ;
return false ;
2017-08-05 15:13:06 +02:00
}
string target = Path . Combine ( backupDirectory , fileName ) ;
2017-07-01 06:10:15 +02:00
File . Move ( file , target ) ;
}
2017-07-05 04:11:03 +02:00
// In generic ASF variant there can also be "runtimes" directory in need of same approach
2017-07-05 04:25:48 +02:00
string runtimesDirectory = Path . Combine ( targetDirectory , "runtimes" ) ;
2017-07-05 04:11:03 +02:00
if ( Directory . Exists ( runtimesDirectory ) ) {
2017-07-07 06:54:54 +02:00
foreach ( string file in Directory . EnumerateFiles ( runtimesDirectory , "*" , SearchOption . AllDirectories ) ) {
2018-06-11 01:24:54 +02:00
string directoryName = Path . GetDirectoryName ( RuntimeCompatibility . Path . GetRelativePath ( targetDirectory , file ) ) ;
if ( string . IsNullOrEmpty ( directoryName ) ) {
ArchiLogger . LogNullError ( nameof ( directoryName ) ) ;
return false ;
}
string directory = Path . Combine ( backupDirectory , directoryName ) ;
2017-07-05 04:25:48 +02:00
Directory . CreateDirectory ( directory ) ;
2017-07-05 04:11:03 +02:00
2018-06-11 01:24:54 +02:00
string fileName = Path . GetFileName ( file ) ;
if ( string . IsNullOrEmpty ( fileName ) ) {
ArchiLogger . LogNullError ( nameof ( fileName ) ) ;
return false ;
}
string target = Path . Combine ( directory , fileName ) ;
2017-07-05 04:11:03 +02:00
File . Move ( file , target ) ;
}
}
2017-07-01 06:10:15 +02:00
foreach ( ZipArchiveEntry zipFile in archive . Entries ) {
2017-07-05 04:25:48 +02:00
string file = Path . Combine ( targetDirectory , zipFile . FullName ) ;
2017-07-01 06:10:15 +02:00
string directory = Path . GetDirectoryName ( file ) ;
2017-07-01 04:06:33 +02:00
2018-06-11 01:24:54 +02:00
if ( string . IsNullOrEmpty ( directory ) ) {
ArchiLogger . LogNullError ( nameof ( directory ) ) ;
return false ;
}
2017-07-01 04:06:33 +02:00
if ( ! Directory . Exists ( directory ) ) {
Directory . CreateDirectory ( directory ) ;
}
2018-10-07 03:21:32 +02:00
if ( string . IsNullOrEmpty ( zipFile . Name ) ) {
2017-07-01 04:06:33 +02:00
continue ;
}
2017-07-01 06:10:15 +02:00
string backupFile = file + ".old" ;
if ( File . Exists ( file ) ) {
// This is non-runtime file to be replaced, probably in use, move it away
File . Move ( file , backupFile ) ;
}
zipFile . ExtractToFile ( file ) ;
try {
File . Delete ( backupFile ) ;
} catch {
// Ignored - that file is indeed in use, it will be deleted after restart
}
2017-07-01 04:06:33 +02:00
}
2018-06-11 01:24:54 +02:00
return true ;
2017-07-01 04:06:33 +02:00
}
2016-11-24 07:32:16 +01:00
internal enum EUserInputType : byte {
Unknown ,
DeviceID ,
Login ,
Password ,
SteamGuard ,
2018-09-22 15:50:11 +02:00
SteamParentalCode ,
2017-06-26 08:42:00 +02:00
TwoFactorAuthentication
2016-11-24 07:32:16 +01:00
}
2016-08-02 06:04:44 +02:00
}
2018-07-27 04:52:14 +02:00
}