From cbfc7d0e424e2faf58f26623c074d87a09b19d85 Mon Sep 17 00:00:00 2001 From: JustArchi Date: Sun, 13 May 2018 19:19:27 +0200 Subject: [PATCH] Accelerate initial bots startup Files can be read in parallel after all --- ArchiSteamFarm/ASF.cs | 19 +++++++- ArchiSteamFarm/Bot.cs | 75 ++++++++++++++++++++------------ ArchiSteamFarm/BotConfig.cs | 4 +- ArchiSteamFarm/BotDatabase.cs | 4 +- ArchiSteamFarm/GlobalConfig.cs | 4 +- ArchiSteamFarm/GlobalDatabase.cs | 4 +- ArchiSteamFarm/Program.cs | 6 +-- 7 files changed, 75 insertions(+), 41 deletions(-) diff --git a/ArchiSteamFarm/ASF.cs b/ArchiSteamFarm/ASF.cs index 5a02684d3..83dda9804 100644 --- a/ArchiSteamFarm/ASF.cs +++ b/ArchiSteamFarm/ASF.cs @@ -188,8 +188,23 @@ namespace ArchiSteamFarm { // Before attempting to connect, initialize our configuration await Bot.InitializeSteamConfiguration(Program.GlobalConfig.SteamProtocols, Program.GlobalDatabase.CellID, Program.GlobalDatabase.ServerListProvider).ConfigureAwait(false); - foreach (string botName in Directory.EnumerateFiles(SharedInfo.ConfigDirectory, "*" + SharedInfo.ConfigExtension).Select(Path.GetFileNameWithoutExtension).Where(botName => !string.IsNullOrEmpty(botName) && IsValidBotName(botName)).OrderBy(botName => botName)) { - await Bot.RegisterBot(botName).ConfigureAwait(false); + try { + IEnumerable tasks = Directory.EnumerateFiles(SharedInfo.ConfigDirectory, "*" + SharedInfo.ConfigExtension).Select(Path.GetFileNameWithoutExtension).Where(botName => !string.IsNullOrEmpty(botName) && IsValidBotName(botName)).OrderBy(botName => botName).Select(Bot.RegisterBot); + + switch (Program.GlobalConfig.OptimizationMode) { + case GlobalConfig.EOptimizationMode.MinMemoryUsage: + foreach (Task task in tasks) { + await task.ConfigureAwait(false); + } + + break; + default: + await Task.WhenAll(tasks).ConfigureAwait(false); + break; + } + } catch (Exception e) { + ArchiLogger.LogGenericException(e); + return; } if (Bot.Bots.Count == 0) { diff --git a/ArchiSteamFarm/Bot.cs b/ArchiSteamFarm/Bot.cs index 30cf9bcb7..b989688b3 100755 --- a/ArchiSteamFarm/Bot.cs +++ b/ArchiSteamFarm/Bot.cs @@ -154,9 +154,9 @@ namespace ArchiSteamFarm { private string TwoFactorCode; private byte TwoFactorCodeFailures; - private Bot(string botName) { - if (string.IsNullOrEmpty(botName)) { - throw new ArgumentNullException(nameof(botName)); + private Bot(string botName, BotConfig botConfig, BotDatabase botDatabase) { + if (string.IsNullOrEmpty(botName) || (botConfig == null) || (botDatabase == null)) { + throw new ArgumentNullException(nameof(botName) + " || " + nameof(botConfig) + " || " + nameof(botDatabase)); } if (Bots.ContainsKey(botName)) { @@ -164,24 +164,11 @@ namespace ArchiSteamFarm { } BotName = botName; + BotConfig = botConfig; + BotDatabase = botDatabase; + ArchiLogger = new ArchiLogger(botName); - BotConfig = BotConfig.Load(ConfigFilePath); - if (BotConfig == null) { - ArchiLogger.LogGenericError(string.Format(Strings.ErrorBotConfigInvalid, ConfigFilePath)); - return; - } - - if (Debugging.IsUserDebugging) { - ArchiLogger.LogGenericDebug(nameof(BotConfig) + ": " + JsonConvert.SerializeObject(BotConfig, Formatting.Indented)); - } - - BotDatabase = BotDatabase.Load(DatabaseFilePath); - if (BotDatabase == null) { - ArchiLogger.LogGenericError(string.Format(Strings.ErrorDatabaseInvalid, DatabaseFilePath)); - return; - } - // Register bot as available for ASF if (!Bots.TryAdd(botName, this)) { throw new ArgumentException(string.Format(Strings.ErrorIsInvalid, nameof(botName))); @@ -785,7 +772,7 @@ namespace ArchiSteamFarm { return; } - BotConfig botConfig = BotConfig.Load(ConfigFilePath); + BotConfig botConfig = await BotConfig.Load(ConfigFilePath).ConfigureAwait(false); if (botConfig == null) { Destroy(); @@ -877,6 +864,28 @@ namespace ArchiSteamFarm { return; } + string botPath = Path.Combine(SharedInfo.ConfigDirectory, botName); + string configFilePath = botPath + SharedInfo.ConfigExtension; + + BotConfig botConfig = await BotConfig.Load(botPath + SharedInfo.ConfigExtension).ConfigureAwait(false); + if (botConfig == null) { + ASF.ArchiLogger.LogGenericError(string.Format(Strings.ErrorBotConfigInvalid, configFilePath)); + return; + } + + if (Debugging.IsUserDebugging) { + ASF.ArchiLogger.LogGenericDebug(botName + ": " + JsonConvert.SerializeObject(botConfig, Formatting.Indented)); + } + + string databaseFilePath = botPath + SharedInfo.DatabaseExtension; + + BotDatabase botDatabase = await BotDatabase.Load(databaseFilePath).ConfigureAwait(false); + if (botDatabase == null) { + ASF.ArchiLogger.LogGenericError(string.Format(Strings.ErrorDatabaseInvalid, databaseFilePath)); + return; + } + + Bot bot; await BotsSemaphore.WaitAsync().ConfigureAwait(false); try { @@ -884,11 +893,12 @@ namespace ArchiSteamFarm { return; } - Bot bot = new Bot(botName); - bot.InitStart(); + bot = new Bot(botName, botConfig, botDatabase); } finally { BotsSemaphore.Release(); } + + bot.InitStart(); } internal void RequestPersonaStateUpdate() { @@ -1391,7 +1401,7 @@ namespace ArchiSteamFarm { ArchiLogger.LogGenericInfo(Strings.BotAuthenticatorConverting); try { - MobileAuthenticator authenticator = JsonConvert.DeserializeObject(File.ReadAllText(maFilePath)); + MobileAuthenticator authenticator = JsonConvert.DeserializeObject(await File.ReadAllTextAsync(maFilePath).ConfigureAwait(false)); await BotDatabase.SetMobileAuthenticator(authenticator).ConfigureAwait(false); File.Delete(maFilePath); } catch (Exception e) { @@ -1509,10 +1519,6 @@ namespace ArchiSteamFarm { } private void InitStart() { - if ((BotConfig == null) || (BotDatabase == null)) { - return; - } - if (!BotConfig.Enabled) { ArchiLogger.LogGenericInfo(Strings.BotInstanceNotStartingBecauseDisabled); return; @@ -1697,10 +1703,16 @@ namespace ArchiSteamFarm { if (File.Exists(SentryFilePath)) { try { - byte[] sentryFileContent = File.ReadAllBytes(SentryFilePath); + byte[] sentryFileContent = await File.ReadAllBytesAsync(SentryFilePath).ConfigureAwait(false); sentryFileHash = SteamKit2.CryptoHelper.SHAHash(sentryFileContent); } catch (Exception e) { ArchiLogger.LogGenericException(e); + + try { + File.Delete(SentryFilePath); + } catch { + // Ignored, we can only try to delete faulted file at best + } } } @@ -2216,6 +2228,13 @@ namespace ArchiSteamFarm { } } catch (Exception e) { ArchiLogger.LogGenericException(e); + + try { + File.Delete(SentryFilePath); + } catch { + // Ignored, we can only try to delete faulted file at best + } + return; } diff --git a/ArchiSteamFarm/BotConfig.cs b/ArchiSteamFarm/BotConfig.cs index be35d0835..36b1e23ca 100644 --- a/ArchiSteamFarm/BotConfig.cs +++ b/ArchiSteamFarm/BotConfig.cs @@ -162,7 +162,7 @@ namespace ArchiSteamFarm { public bool ShouldSerializeSteamParentalPIN() => ShouldSerializeSensitiveDetails; public bool ShouldSerializeSteamPassword() => ShouldSerializeSensitiveDetails; - internal static BotConfig Load(string filePath) { + internal static async Task Load(string filePath) { if (string.IsNullOrEmpty(filePath)) { ASF.ArchiLogger.LogNullError(nameof(filePath)); return null; @@ -175,7 +175,7 @@ namespace ArchiSteamFarm { BotConfig botConfig; try { - botConfig = JsonConvert.DeserializeObject(File.ReadAllText(filePath)); + botConfig = JsonConvert.DeserializeObject(await File.ReadAllTextAsync(filePath).ConfigureAwait(false)); } catch (Exception e) { ASF.ArchiLogger.LogGenericException(e); return null; diff --git a/ArchiSteamFarm/BotDatabase.cs b/ArchiSteamFarm/BotDatabase.cs index 9909bb1bf..fb97d1ef0 100644 --- a/ArchiSteamFarm/BotDatabase.cs +++ b/ArchiSteamFarm/BotDatabase.cs @@ -185,7 +185,7 @@ namespace ArchiSteamFarm { return IdlingPriorityAppIDs.Contains(appID); } - internal static BotDatabase Load(string filePath) { + internal static async Task Load(string filePath) { if (string.IsNullOrEmpty(filePath)) { ASF.ArchiLogger.LogNullError(nameof(filePath)); return null; @@ -198,7 +198,7 @@ namespace ArchiSteamFarm { BotDatabase botDatabase; try { - botDatabase = JsonConvert.DeserializeObject(File.ReadAllText(filePath)); + botDatabase = JsonConvert.DeserializeObject(await File.ReadAllTextAsync(filePath).ConfigureAwait(false)); } catch (Exception e) { ASF.ArchiLogger.LogGenericException(e); return null; diff --git a/ArchiSteamFarm/GlobalConfig.cs b/ArchiSteamFarm/GlobalConfig.cs index 24ccf4685..8593bed89 100644 --- a/ArchiSteamFarm/GlobalConfig.cs +++ b/ArchiSteamFarm/GlobalConfig.cs @@ -244,7 +244,7 @@ namespace ArchiSteamFarm { public bool ShouldSerializeWebProxyPassword() => ShouldSerializeSensitiveDetails; - internal static GlobalConfig Load(string filePath) { + internal static async Task Load(string filePath) { if (string.IsNullOrEmpty(filePath)) { ASF.ArchiLogger.LogNullError(nameof(filePath)); return null; @@ -257,7 +257,7 @@ namespace ArchiSteamFarm { GlobalConfig globalConfig; try { - globalConfig = JsonConvert.DeserializeObject(File.ReadAllText(filePath)); + globalConfig = JsonConvert.DeserializeObject(await File.ReadAllTextAsync(filePath).ConfigureAwait(false)); } catch (Exception e) { ASF.ArchiLogger.LogGenericException(e); return null; diff --git a/ArchiSteamFarm/GlobalDatabase.cs b/ArchiSteamFarm/GlobalDatabase.cs index 92b2a7cab..2ba57a4fd 100644 --- a/ArchiSteamFarm/GlobalDatabase.cs +++ b/ArchiSteamFarm/GlobalDatabase.cs @@ -77,7 +77,7 @@ namespace ArchiSteamFarm { return new HashSet(PackagesData.Where(package => package.Value.AppIDs?.Contains(appID) == true).Select(package => package.Key)); } - internal static GlobalDatabase Load(string filePath) { + internal static async Task Load(string filePath) { if (string.IsNullOrEmpty(filePath)) { ASF.ArchiLogger.LogNullError(nameof(filePath)); return null; @@ -90,7 +90,7 @@ namespace ArchiSteamFarm { GlobalDatabase globalDatabase; try { - globalDatabase = JsonConvert.DeserializeObject(File.ReadAllText(filePath)); + globalDatabase = JsonConvert.DeserializeObject(await File.ReadAllTextAsync(filePath).ConfigureAwait(false)); } catch (Exception e) { ASF.ArchiLogger.LogGenericException(e); return null; diff --git a/ArchiSteamFarm/Program.cs b/ArchiSteamFarm/Program.cs index 5b98d0984..05f48f693 100644 --- a/ArchiSteamFarm/Program.cs +++ b/ArchiSteamFarm/Program.cs @@ -241,7 +241,7 @@ namespace ArchiSteamFarm { private static async Task InitGlobalConfigAndLanguage() { string globalConfigFile = Path.Combine(SharedInfo.ConfigDirectory, SharedInfo.GlobalConfigFileName); - GlobalConfig = GlobalConfig.Load(globalConfigFile); + GlobalConfig = await GlobalConfig.Load(globalConfigFile).ConfigureAwait(false); if (GlobalConfig == null) { ASF.ArchiLogger.LogGenericError(string.Format(Strings.ErrorGlobalConfigNotLoaded, globalConfigFile)); await Task.Delay(5 * 1000).ConfigureAwait(false); @@ -250,7 +250,7 @@ namespace ArchiSteamFarm { } if (Debugging.IsUserDebugging) { - ASF.ArchiLogger.LogGenericDebug(nameof(GlobalConfig) + ": " + JsonConvert.SerializeObject(GlobalConfig, Formatting.Indented)); + ASF.ArchiLogger.LogGenericDebug(SharedInfo.ASF + ": " + JsonConvert.SerializeObject(GlobalConfig, Formatting.Indented)); } if (GlobalConfig.BackgroundGCPeriod > 0) { @@ -318,7 +318,7 @@ namespace ArchiSteamFarm { await Task.Delay(5 * 1000).ConfigureAwait(false); } - GlobalDatabase = GlobalDatabase.Load(globalDatabaseFile); + GlobalDatabase = await GlobalDatabase.Load(globalDatabaseFile).ConfigureAwait(false); if (GlobalDatabase == null) { ASF.ArchiLogger.LogGenericError(string.Format(Strings.ErrorDatabaseInvalid, globalDatabaseFile)); await Task.Delay(5 * 1000).ConfigureAwait(false);