From c887dc102e6dd117d9161f934a93cd7e7e7c0c72 Mon Sep 17 00:00:00 2001 From: JustArchi Date: Sun, 5 Feb 2017 14:32:38 +0100 Subject: [PATCH] Unify ASF/GUI startup --- .gitignore | 15 +++- ArchiSteamFarm/Program.cs | 67 ++++++++------- GUI/BotStatusForm.cs | 4 +- GUI/Logging.cs | 47 ++++------- GUI/MainForm.cs | 51 ++++-------- GUI/Program.cs | 167 +++++++++++++++++++++++++------------- 6 files changed, 192 insertions(+), 159 deletions(-) diff --git a/.gitignore b/.gitignore index 5db8c130f..2f3041e69 100644 --- a/.gitignore +++ b/.gitignore @@ -2,15 +2,22 @@ ## ArchiSteamFarm ################# -# Ignore all config files, apart from ones we want to include -ArchiSteamFarm/config/* +# Ignore all config files +ArchiSteamFarm/config +GUI/config + +# Include default config files !ArchiSteamFarm/config/ASF.json !ArchiSteamFarm/config/example.json !ArchiSteamFarm/config/minimal.json -# Ignore local debugging +# Ignore local log ArchiSteamFarm/log.txt -ArchiSteamFarm/debug/* +GUI/log.txt + +# Ignore local debugging +ArchiSteamFarm/debug +GUI/debug # Ignore out out/ diff --git a/ArchiSteamFarm/Program.cs b/ArchiSteamFarm/Program.cs index 4e1a7a186..2739ae2ce 100644 --- a/ArchiSteamFarm/Program.cs +++ b/ArchiSteamFarm/Program.cs @@ -130,42 +130,17 @@ namespace ArchiSteamFarm { } private static async Task Init(string[] args) { - // We must register our logging target as soon as possible - Target.Register("Steam"); - await InitCore(args).ConfigureAwait(false); - } - - private static async Task InitCore(string[] args) { AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler; TaskScheduler.UnobservedTaskException += UnobservedTaskExceptionHandler; - string homeDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); - if (!string.IsNullOrEmpty(homeDirectory)) { - Directory.SetCurrentDirectory(homeDirectory); + // We must register our logging target as soon as possible + Target.Register("Steam"); - // Allow loading configs from source tree if it's a debug build - if (Debugging.IsDebugBuild) { - // Common structure is bin/(x64/)Debug/ArchiSteamFarm.exe, so we allow up to 4 directories up - for (byte i = 0; i < 4; i++) { - Directory.SetCurrentDirectory(".."); - if (Directory.Exists(SharedInfo.ConfigDirectory)) { - break; - } - } + InitCore(args); + await InitASF(args).ConfigureAwait(false); + } - // If config directory doesn't exist after our adjustment, abort all of that - if (!Directory.Exists(SharedInfo.ConfigDirectory)) { - Directory.SetCurrentDirectory(homeDirectory); - } - } - } - - // Parse pre-init args - if (args != null) { - ParsePreInitArgs(args); - } - - Logging.InitLoggers(); + private static async Task InitASF(string[] args) { ASF.ArchiLogger.LogGenericInfo("ASF V" + SharedInfo.Version); await InitGlobalConfigAndLanguage().ConfigureAwait(false); @@ -209,6 +184,36 @@ namespace ArchiSteamFarm { ASF.InitFileWatcher(); } + private static void InitCore(string[] args) { + string homeDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); + if (!string.IsNullOrEmpty(homeDirectory)) { + Directory.SetCurrentDirectory(homeDirectory); + + // Allow loading configs from source tree if it's a debug build + if (Debugging.IsDebugBuild) { + // Common structure is bin/(x64/)Debug/ArchiSteamFarm.exe, so we allow up to 4 directories up + for (byte i = 0; i < 4; i++) { + Directory.SetCurrentDirectory(".."); + if (Directory.Exists(SharedInfo.ConfigDirectory)) { + break; + } + } + + // If config directory doesn't exist after our adjustment, abort all of that + if (!Directory.Exists(SharedInfo.ConfigDirectory)) { + Directory.SetCurrentDirectory(homeDirectory); + } + } + } + + // Parse pre-init args + if (args != null) { + ParsePreInitArgs(args); + } + + Logging.InitLoggers(); + } + private static async Task InitGlobalConfigAndLanguage() { string globalConfigFile = Path.Combine(SharedInfo.ConfigDirectory, SharedInfo.GlobalConfigFileName); diff --git a/GUI/BotStatusForm.cs b/GUI/BotStatusForm.cs index 1266f2770..a33fd1e79 100644 --- a/GUI/BotStatusForm.cs +++ b/GUI/BotStatusForm.cs @@ -44,8 +44,6 @@ namespace ArchiSteamFarm { AvatarPictureBox.LoadAsync(); } - private void AvatarPictureBox_LoadCompleted(object sender, AsyncCompletedEventArgs e) { - MainForm.UpdateBotAvatar(Bot.BotName, AvatarPictureBox.Image); - } + private void AvatarPictureBox_LoadCompleted(object sender, AsyncCompletedEventArgs e) => MainForm.UpdateBotAvatar(Bot.BotName, AvatarPictureBox.Image); } } \ No newline at end of file diff --git a/GUI/Logging.cs b/GUI/Logging.cs index 46eabd8be..3f90ed6b4 100644 --- a/GUI/Logging.cs +++ b/GUI/Logging.cs @@ -22,7 +22,6 @@ */ -using System.Linq; using NLog; using NLog.Config; using NLog.Targets; @@ -30,46 +29,34 @@ using NLog.Windows.Forms; namespace ArchiSteamFarm { internal static class Logging { - private const string GeneralLayout = @"${date:format=yyyy-MM-dd HH\:mm\:ss} | ${level:uppercase=true} | ${logger} | ${message}${onexception:inner= | ${exception:format=toString,Data}}"; + private const string GeneralLayout = @"${date:format=yyyy-MM-dd HH\:mm\:ss}|${processname}-${processid}|${level:uppercase=true}|${logger}|${message}${onexception:inner= ${exception:format=toString,Data}}"; - private static bool IsUsingCustomConfiguration; - - internal static void InitCoreLoggers() { - if (LogManager.Configuration == null) { - LogManager.Configuration = new LoggingConfiguration(); - } else { - // User provided custom NLog config, but we still need to define our own logger - IsUsingCustomConfiguration = true; - if (LogManager.Configuration.AllTargets.Any(target => target is MessageBoxTarget)) { - return; - } - } - - MessageBoxTarget messageBoxTarget = new MessageBoxTarget { - Name = "MessageBox", - Layout = GeneralLayout - }; - - LogManager.Configuration.AddTarget(messageBoxTarget); - LogManager.Configuration.LoggingRules.Add(new LoggingRule("*", LogLevel.Fatal, messageBoxTarget)); - LogManager.ReconfigExistingLoggers(); - } - - internal static void InitEnhancedLoggers() { - if (IsUsingCustomConfiguration) { + internal static void InitLoggers() { + if (LogManager.Configuration != null) { + // User provided custom NLog config, or we have it set already, so don't override it return; } + LoggingConfiguration config = new LoggingConfiguration(); + FileTarget fileTarget = new FileTarget("File") { DeleteOldFileOnStartup = true, FileName = SharedInfo.LogFile, Layout = GeneralLayout }; - LogManager.Configuration.AddTarget(fileTarget); - LogManager.Configuration.LoggingRules.Add(new LoggingRule("*", LogLevel.Debug, fileTarget)); + config.AddTarget(fileTarget); + config.LoggingRules.Add(new LoggingRule("*", LogLevel.Debug, fileTarget)); - LogManager.ReconfigExistingLoggers(); + MessageBoxTarget messageBoxTarget = new MessageBoxTarget { + Name = "MessageBox", + Layout = GeneralLayout + }; + + config.AddTarget(messageBoxTarget); + config.LoggingRules.Add(new LoggingRule("*", LogLevel.Fatal, messageBoxTarget)); + + LogManager.Configuration = config; } internal static void InitFormLogger() { diff --git a/GUI/MainForm.cs b/GUI/MainForm.cs index e83a4538f..9898eae6f 100644 --- a/GUI/MainForm.cs +++ b/GUI/MainForm.cs @@ -1,11 +1,9 @@ using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; -using System.IO; -using System.Linq; -using System.Threading.Tasks; using System.Windows.Forms; namespace ArchiSteamFarm { @@ -62,55 +60,36 @@ namespace ArchiSteamFarm { private async void MainForm_FormClosed(object sender, FormClosedEventArgs e) => await Program.InitShutdownSequence().ConfigureAwait(false); private async void MainForm_Load(object sender, EventArgs e) { - Logging.InitFormLogger(); - BotListView.LargeImageList = BotListView.SmallImageList = AvatarImageList; - await Task.Run(async () => { - Program.ArchiLogger.LogGenericInfo("ASF V" + SharedInfo.Version); + Program.InitCore(); + Logging.InitFormLogger(); + await Program.InitASF(); // No ConfigureAwait, we need GUI thread - if (!Directory.Exists(SharedInfo.ConfigDirectory)) { - Program.ArchiLogger.LogGenericError("Config directory could not be found!"); - Environment.Exit(1); - } + foreach (KeyValuePair bot in Bot.Bots) { + BotStatusForm botStatusForm = new BotStatusForm(bot.Value); - await ASF.CheckForUpdate().ConfigureAwait(false); + BotIndexes[bot.Key] = AvatarImageList.Images.Count; - // Before attempting to connect, initialize our list of CMs - await Bot.InitializeCMs(Program.GlobalDatabase.CellID, Program.GlobalDatabase.ServerListProvider).ConfigureAwait(false); - }); - - foreach (string botName in Directory.EnumerateFiles(SharedInfo.ConfigDirectory, "*.json").Select(Path.GetFileNameWithoutExtension)) { - switch (botName) { - case SharedInfo.ASF: - case "example": - case "minimal": - continue; - } - - Bot bot = new Bot(botName); - - BotStatusForm botStatusForm = new BotStatusForm(bot); - - BotIndexes[botName] = AvatarImageList.Images.Count; - - AvatarImageList.Images.Add(botName, botStatusForm.AvatarPictureBox.Image); + AvatarImageList.Images.Add(bot.Key, botStatusForm.AvatarPictureBox.Image); botStatusForm.TopLevel = false; BotStatusPanel.Controls.Add(botStatusForm); ListViewItem botListViewItem = new ListViewItem { - ImageIndex = BotIndexes[botName], - Text = botName + ImageIndex = BotIndexes[bot.Key], + Text = bot.Key }; BotListView.Items.Add(botListViewItem); } - if (BotListView.Items.Count > 0) { - BotListView.Items[0].Selected = true; - BotListView.Select(); + if (BotListView.Items.Count <= 0) { + return; } + + BotListView.Items[0].Selected = true; + BotListView.Select(); } private void MainForm_Resize(object sender, EventArgs e) { diff --git a/GUI/Program.cs b/GUI/Program.cs index d906a23fb..c8a98cccf 100644 --- a/GUI/Program.cs +++ b/GUI/Program.cs @@ -1,12 +1,14 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using System.Reflection; -using System.Threading; +using System.Resources; using System.Threading.Tasks; using System.Windows.Forms; using ArchiSteamFarm.Localization; +using NLog.Targets; using SteamKit2; namespace ArchiSteamFarm { @@ -25,11 +27,68 @@ namespace ArchiSteamFarm { } await Shutdown().ConfigureAwait(false); - Environment.Exit(exitCode); + Application.Exit(); } - internal static string GetUserInput(ASF.EUserInputType userInputType, string botName = SharedInfo.ASF, string extraInformation = null) { - return null; // TODO + internal static string GetUserInput(ASF.EUserInputType userInputType, string botName = SharedInfo.ASF, string extraInformation = null) => null; // TODO + + internal static async Task InitASF() { + ASF.ArchiLogger.LogGenericInfo("ASF V" + SharedInfo.Version); + + await InitGlobalConfigAndLanguage().ConfigureAwait(false); + + if (!Runtime.IsRuntimeSupported) { + ASF.ArchiLogger.LogGenericError(Strings.WarningRuntimeUnsupported); + await Task.Delay(60 * 1000).ConfigureAwait(false); + } + + await InitGlobalDatabaseAndServices().ConfigureAwait(false); + + // If debugging is on, we prepare debug directory prior to running + if (GlobalConfig.Debug) { + if (Directory.Exists(SharedInfo.DebugDirectory)) { + try { + Directory.Delete(SharedInfo.DebugDirectory, true); + await Task.Delay(1000).ConfigureAwait(false); // Dirty workaround giving Windows some time to sync + } catch (IOException e) { + ASF.ArchiLogger.LogGenericException(e); + } + } + + Directory.CreateDirectory(SharedInfo.DebugDirectory); + + DebugLog.AddListener(new Debugging.DebugListener()); + DebugLog.Enabled = true; + } + + await ASF.CheckForUpdate().ConfigureAwait(false); + await ASF.InitBots().ConfigureAwait(false); + ASF.InitFileWatcher(); + } + + internal static void InitCore() { + string homeDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); + if (!string.IsNullOrEmpty(homeDirectory)) { + Directory.SetCurrentDirectory(homeDirectory); + + // Allow loading configs from source tree if it's a debug build + if (Debugging.IsDebugBuild) { + // Common structure is bin/(x64/)Debug/ArchiSteamFarm.exe, so we allow up to 4 directories up + for (byte i = 0; i < 4; i++) { + Directory.SetCurrentDirectory(".."); + if (Directory.Exists(SharedInfo.ConfigDirectory)) { + break; + } + } + + // If config directory doesn't exist after our adjustment, abort all of that + if (!Directory.Exists(SharedInfo.ConfigDirectory)) { + Directory.SetCurrentDirectory(homeDirectory); + } + } + } + + Logging.InitLoggers(); } internal static async Task InitShutdownSequence() { @@ -53,79 +112,77 @@ namespace ArchiSteamFarm { Application.Restart(); } - private static async Task Init() { + private static void Init() { AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler; TaskScheduler.UnobservedTaskException += UnobservedTaskExceptionHandler; - Logging.InitCoreLoggers(); + // We must register our logging target as soon as possible + Target.Register("Steam"); - if (!Runtime.IsRuntimeSupported) { - ArchiLogger.LogGenericError("ASF detected unsupported runtime version, program might NOT run correctly in current environment. You're running it at your own risk!"); - } - - string homeDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); - if (!string.IsNullOrEmpty(homeDirectory)) { - Directory.SetCurrentDirectory(homeDirectory); - - // Allow loading configs from source tree if it's a debug build - if (Debugging.IsDebugBuild) { - // Common structure is bin/(x64/)Debug/ArchiSteamFarm.exe, so we allow up to 4 directories up - for (byte i = 0; i < 4; i++) { - Directory.SetCurrentDirectory(".."); - if (!Directory.Exists(SharedInfo.ASFDirectory)) { - continue; - } - - Directory.SetCurrentDirectory(SharedInfo.ASFDirectory); - break; - } - - // If config directory doesn't exist after our adjustment, abort all of that - if (!Directory.Exists(SharedInfo.ConfigDirectory)) { - Directory.SetCurrentDirectory(homeDirectory); - } - } - } - - await InitServices().ConfigureAwait(false); - - // If debugging is on, we prepare debug directory prior to running - if (GlobalConfig.Debug) { - if (Directory.Exists(SharedInfo.DebugDirectory)) { - Directory.Delete(SharedInfo.DebugDirectory, true); - Thread.Sleep(1000); // Dirty workaround giving Windows some time to sync - } - - Directory.CreateDirectory(SharedInfo.DebugDirectory); - - DebugLog.AddListener(new Debugging.DebugListener()); - DebugLog.Enabled = true; - } - - Logging.InitEnhancedLoggers(); + // The rest of ASF is initialized from MainForm.cs } - private static async Task InitServices() { + private static async Task InitGlobalConfigAndLanguage() { string globalConfigFile = Path.Combine(SharedInfo.ConfigDirectory, SharedInfo.GlobalConfigFileName); GlobalConfig = GlobalConfig.Load(globalConfigFile); if (GlobalConfig == null) { - ArchiLogger.LogGenericError("Global config could not be loaded, please make sure that " + globalConfigFile + " exists and is valid!"); + ASF.ArchiLogger.LogGenericError(string.Format(Strings.ErrorGlobalConfigNotLoaded, globalConfigFile)); + await Task.Delay(5 * 1000).ConfigureAwait(false); await Exit(1).ConfigureAwait(false); + return; } + if (!string.IsNullOrEmpty(GlobalConfig.CurrentCulture)) { + try { + // GetCultureInfo() would be better but we can't use it for specifying neutral cultures such as "en" + CultureInfo culture = CultureInfo.CreateSpecificCulture(GlobalConfig.CurrentCulture); + CultureInfo.DefaultThreadCurrentCulture = CultureInfo.DefaultThreadCurrentUICulture = culture; + } catch (CultureNotFoundException) { + ASF.ArchiLogger.LogGenericError(Strings.ErrorInvalidCurrentCulture); + } + } + + int defaultResourceSetCount = 0; + ResourceSet defaultResourceSet = Strings.ResourceManager.GetResourceSet(CultureInfo.GetCultureInfo("en-US"), true, true); + if (defaultResourceSet != null) { + defaultResourceSetCount = defaultResourceSet.Cast().Count(); + } + + int currentResourceSetCount = 0; + ResourceSet currentResourceSet = Strings.ResourceManager.GetResourceSet(CultureInfo.CurrentCulture, true, false); + if (currentResourceSet != null) { + currentResourceSetCount = currentResourceSet.Cast().Count(); + } + + if (currentResourceSetCount < defaultResourceSetCount) { + float translationCompleteness = currentResourceSetCount / (float) defaultResourceSetCount; + ASF.ArchiLogger.LogGenericInfo(string.Format(Strings.TranslationIncomplete, CultureInfo.CurrentCulture.Name, translationCompleteness.ToString("P1"))); + } + } + + private static async Task InitGlobalDatabaseAndServices() { string globalDatabaseFile = Path.Combine(SharedInfo.ConfigDirectory, SharedInfo.GlobalDatabaseFileName); + if (!File.Exists(globalDatabaseFile)) { + ASF.ArchiLogger.LogGenericInfo(Strings.Welcome); + ASF.ArchiLogger.LogGenericWarning(Strings.WarningPrivacyPolicy); + await Task.Delay(15 * 1000).ConfigureAwait(false); + } + GlobalDatabase = GlobalDatabase.Load(globalDatabaseFile); if (GlobalDatabase == null) { - ArchiLogger.LogGenericError("Global database could not be loaded, if issue persists, please remove " + globalDatabaseFile + " in order to recreate database!"); + ASF.ArchiLogger.LogGenericError(string.Format(Strings.ErrorDatabaseInvalid, globalDatabaseFile)); + await Task.Delay(5 * 1000).ConfigureAwait(false); await Exit(1).ConfigureAwait(false); + return; } ArchiWebHandler.Init(); + OS.Init(); WebBrowser.Init(); - WebBrowser = new WebBrowser(ArchiLogger); + WebBrowser = new WebBrowser(ASF.ArchiLogger); } /// @@ -133,7 +190,7 @@ namespace ArchiSteamFarm { /// [STAThread] private static void Main() { - Init().Wait(); + Init(); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new MainForm());