using Autofac; using FluentTerminal.App.Services; using FluentTerminal.App.Services.Adapters; using FluentTerminal.App.Services.Implementation; using FluentTerminal.SystemTray.Services; using GlobalHotKey; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Serialization; using System; using System.IO; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using System.Windows.Threading; using Windows.Storage; namespace FluentTerminal.SystemTray { public static class Program { private const string MutexName = "FluentTerminalMutex"; [STAThread] public static void Main(string[] args) { if (!Mutex.TryOpenExisting(MutexName, out _)) { using (new Mutex(false, MutexName)) { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); JsonConvert.DefaultSettings = () => { var settings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver(), }; settings.Converters.Add(new StringEnumConverter(typeof(CamelCaseNamingStrategy))); return settings; }; var applicationDataContainers = new ApplicationDataContainers { LocalSettings = new ApplicationDataContainerAdapter(ApplicationData.Current.LocalSettings), RoamingSettings = new ApplicationDataContainerAdapter(ApplicationData.Current.RoamingSettings), KeyBindings = new ApplicationDataContainerAdapter(ApplicationData.Current.RoamingSettings.CreateContainer(Constants.KeyBindingsContainerName, ApplicationDataCreateDisposition.Always)), ShellProfiles = new ApplicationDataContainerAdapter(ApplicationData.Current.LocalSettings.CreateContainer(Constants.ShellProfilesContainerName, ApplicationDataCreateDisposition.Always)), Themes = new ApplicationDataContainerAdapter(ApplicationData.Current.RoamingSettings.CreateContainer(Constants.ThemesContainerName, ApplicationDataCreateDisposition.Always)) }; var containerBuilder = new ContainerBuilder(); containerBuilder.RegisterInstance(applicationDataContainers); containerBuilder.RegisterType().As().InstancePerDependency(); containerBuilder.RegisterType().SingleInstance(); containerBuilder.RegisterType().SingleInstance(); containerBuilder.RegisterInstance(new HotKeyManager()).SingleInstance(); containerBuilder.RegisterType().SingleInstance(); containerBuilder.RegisterType().SingleInstance(); containerBuilder.RegisterType().As(); containerBuilder.RegisterType().As().SingleInstance(); containerBuilder.RegisterType().As().SingleInstance(); containerBuilder.RegisterInstance(Dispatcher.CurrentDispatcher).SingleInstance(); var container = containerBuilder.Build(); // TODO: It's maybe better to wait for logging to be configured before continuing? // ReSharper disable once AssignmentIsFullyDiscarded _ = ConfigureLoggingAsync(); var appCommunicationService = container.Resolve(); if (args.Length > 0 && args[2] == "appLaunched") { // ReSharper disable once AssignmentIsFullyDiscarded _ = appCommunicationService.StartAppServiceConnectionAsync(); } #if !STORE // ReSharper disable once AssignmentIsFullyDiscarded _ = Task.Factory.StartNew(() => container.Resolve().CheckForUpdateAsync()); #endif var settingsService = container.Resolve(); // ReSharper disable once AssignmentIsFullyDiscarded _ = Task.Factory.StartNew(() => Utilities.MuteTerminal(settingsService.GetApplicationSettings().MuteTerminalBeeps)); if (settingsService.GetApplicationSettings().EnableTrayIcon) { Application.Run(container.Resolve()); } else { Application.Run(); } } } else { var eventWaitHandle = EventWaitHandle.OpenExisting(AppCommunicationService.EventWaitHandleName, System.Security.AccessControl.EventWaitHandleRights.Modify); eventWaitHandle.Set(); } } private static async Task ConfigureLoggingAsync() { var logDirectory = await ApplicationData.Current.LocalCacheFolder.CreateFolderAsync("Logs", CreationCollisionOption.OpenIfExists).AsTask().ConfigureAwait(false); var logFile = Path.Combine(logDirectory.Path, "fluentterminal.systemtray.log"); var configFile = await logDirectory.CreateFileAsync("config.json", CreationCollisionOption.OpenIfExists).AsTask().ConfigureAwait(false); var configContent = await FileIO.ReadTextAsync(configFile).AsTask().ConfigureAwait(false); var config = JsonConvert.DeserializeObject(configContent) ?? new Logger.Configuration(); Logger.Instance.Initialize(logFile, config); AppDomain.CurrentDomain.UnhandledException += OnUnhandledException; TaskScheduler.UnobservedTaskException += (sender, e) => Logger.Instance.Error(e.Exception, "Unobserved Task Exception"); } private static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e) { Logger.Instance.Error((Exception)e.ExceptionObject, "Unhandled Exception"); } } }