From 28e15320647b7efb5d0c99dc8740034424dd53b3 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 27 Jan 2021 20:52:51 +0100 Subject: [PATCH] Web server - Added web server service UI - Added remote management for bringing to foreground, restarting and shutting down UI - Simplified services namespaces --- src/Artemis.Core/Artemis.Core.csproj | 1 + .../Artemis.Core.csproj.DotSettings | 2 + .../Profile/LayerProperties/ILayerProperty.cs | 2 +- .../WebServer/Interfaces/IWebServerService.cs | 34 +++++ .../Services/WebServer/PluginsModule.cs | 25 ++++ .../WebServer/WebApiControllerRegistration.cs | 28 +++++ .../Services/WebServer/WebServerService.cs | 117 ++++++++++++++++++ src/Artemis.Core/packages.lock.json | 14 +++ .../Services/Message/MessageService.cs | 8 +- .../Services/Window/WindowService.cs | 6 +- src/Artemis.UI.Shared/packages.lock.json | 14 +++ src/Artemis.UI/Artemis.UI.csproj.DotSettings | 5 +- src/Artemis.UI/Bootstrapper.cs | 1 + src/Artemis.UI/Ninject/UiModule.cs | 2 +- .../Dialogs/ProfileImportViewModel.cs | 2 - .../Visualization/ProfileLayerViewModel.cs | 2 +- .../Visualization/Tools/EditToolViewModel.cs | 2 +- src/Artemis.UI/Screens/RootViewModel.cs | 1 - .../General/GeneralSettingsTabViewModel.cs | 1 - src/Artemis.UI/Screens/TrayViewModel.cs | 60 ++++----- src/Artemis.UI/Services/DebugService.cs | 1 - .../Services/Interfaces/IArtemisUIService.cs | 2 +- .../Services/Interfaces/IDebugService.cs | 2 +- .../Interfaces/ILayerEditorService.cs | 2 +- src/Artemis.UI/Services/LayerEditorService.cs | 1 - .../Services/RegistrationService.cs | 1 - .../Interfaces/IRemoteManagementService.cs | 6 + .../RemoteManagement/RemoteController.cs | 39 ++++++ .../RemoteManagementService.cs | 12 ++ src/Artemis.UI/Services/UpdateService.cs | 3 +- src/Artemis.UI/packages.lock.json | 14 +++ 31 files changed, 351 insertions(+), 59 deletions(-) create mode 100644 src/Artemis.Core/Services/WebServer/Interfaces/IWebServerService.cs create mode 100644 src/Artemis.Core/Services/WebServer/PluginsModule.cs create mode 100644 src/Artemis.Core/Services/WebServer/WebApiControllerRegistration.cs create mode 100644 src/Artemis.Core/Services/WebServer/WebServerService.cs create mode 100644 src/Artemis.UI/Services/RemoteManagement/Interfaces/IRemoteManagementService.cs create mode 100644 src/Artemis.UI/Services/RemoteManagement/RemoteController.cs create mode 100644 src/Artemis.UI/Services/RemoteManagement/RemoteManagementService.cs diff --git a/src/Artemis.Core/Artemis.Core.csproj b/src/Artemis.Core/Artemis.Core.csproj index c00b5950c..bd0e5eb30 100644 --- a/src/Artemis.Core/Artemis.Core.csproj +++ b/src/Artemis.Core/Artemis.Core.csproj @@ -39,6 +39,7 @@ + diff --git a/src/Artemis.Core/Artemis.Core.csproj.DotSettings b/src/Artemis.Core/Artemis.Core.csproj.DotSettings index 0ff3e797c..8aa37a05c 100644 --- a/src/Artemis.Core/Artemis.Core.csproj.DotSettings +++ b/src/Artemis.Core/Artemis.Core.csproj.DotSettings @@ -64,6 +64,8 @@ True True True + True + True True True True \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/ILayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/ILayerProperty.cs index d726d4b2e..33153f4ef 100644 --- a/src/Artemis.Core/Models/Profile/LayerProperties/ILayerProperty.cs +++ b/src/Artemis.Core/Models/Profile/LayerProperties/ILayerProperty.cs @@ -78,7 +78,7 @@ namespace Artemis.Core public event EventHandler? CurrentValueSet; /// - /// Occurs when the value of the layer property was updated + /// Occurs when the visibility value of the layer property was updated /// public event EventHandler? VisibilityChanged; diff --git a/src/Artemis.Core/Services/WebServer/Interfaces/IWebServerService.cs b/src/Artemis.Core/Services/WebServer/Interfaces/IWebServerService.cs new file mode 100644 index 000000000..b70ed629d --- /dev/null +++ b/src/Artemis.Core/Services/WebServer/Interfaces/IWebServerService.cs @@ -0,0 +1,34 @@ +using System; +using EmbedIO; +using EmbedIO.WebApi; + +namespace Artemis.Core.Services +{ + /// + /// A service that provides access to the local Artemis web server + /// + public interface IWebServerService : IArtemisService + { + /// + /// Gets the currently active instance of the web server + /// + WebServer? Server { get; } + + /// + /// Adds a new Web API controller and restarts the web server + /// + /// The type of Web API controller to remove + void AddController() where T : WebApiController; + + /// + /// Removes an existing Web API controller and restarts the web server + /// + /// The type of Web API controller to remove + void RemoveController() where T : WebApiController; + + /// + /// Occurs when a new instance of the web server was been created + /// + event EventHandler? WebServerCreated; + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Services/WebServer/PluginsModule.cs b/src/Artemis.Core/Services/WebServer/PluginsModule.cs new file mode 100644 index 000000000..b3e635153 --- /dev/null +++ b/src/Artemis.Core/Services/WebServer/PluginsModule.cs @@ -0,0 +1,25 @@ +using System.Threading.Tasks; +using EmbedIO; + +namespace Artemis.Core.Services +{ + internal class PluginsModule : WebModuleBase + { + /// + public PluginsModule(string baseRoute) : base(baseRoute) + { + } + + #region Overrides of WebModuleBase + + /// + protected override async Task OnRequestAsync(IHttpContext context) + { + } + + /// + public override bool IsFinalHandler => true; + + #endregion + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Services/WebServer/WebApiControllerRegistration.cs b/src/Artemis.Core/Services/WebServer/WebApiControllerRegistration.cs new file mode 100644 index 000000000..ad5fb30dc --- /dev/null +++ b/src/Artemis.Core/Services/WebServer/WebApiControllerRegistration.cs @@ -0,0 +1,28 @@ +using System; +using EmbedIO.WebApi; +using Ninject; + +namespace Artemis.Core.Services +{ + internal class WebApiControllerRegistration : WebApiControllerRegistration where T : WebApiController + { + public WebApiControllerRegistration(IKernel kernel) : base(typeof(T)) + { + Factory = () => kernel.Get(); + } + + public Func Factory { get; set; } + public override object UntypedFactory => Factory; + } + + internal abstract class WebApiControllerRegistration + { + protected WebApiControllerRegistration(Type controllerType) + { + ControllerType = controllerType; + } + + public abstract object UntypedFactory { get; } + public Type ControllerType { get; set; } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Services/WebServer/WebServerService.cs b/src/Artemis.Core/Services/WebServer/WebServerService.cs new file mode 100644 index 000000000..64af5c2ef --- /dev/null +++ b/src/Artemis.Core/Services/WebServer/WebServerService.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.IO; +using EmbedIO; +using EmbedIO.Actions; +using EmbedIO.WebApi; +using Ninject; +using Serilog; + +namespace Artemis.Core.Services +{ + internal class WebServerService : IWebServerService, IDisposable + { + private readonly IKernel _kernel; + private readonly ILogger _logger; + private readonly PluginsModule _pluginModule; + private readonly PluginSetting _webServerPortSetting; + private readonly List _controllers; + + public WebServerService(IKernel kernel, ILogger logger, ISettingsService settingsService) + { + _kernel = kernel; + _logger = logger; + _controllers = new List(); + + _webServerPortSetting = settingsService.GetSetting("WebServer.Port", 9696); + _webServerPortSetting.SettingChanged += WebServerPortSettingOnSettingChanged; + + _pluginModule = new PluginsModule("/plugin"); + Server = CreateWebServer(); + Server.Start(); + } + + public WebServer? Server { get; private set; } + + #region Web server managament + + private WebServer CreateWebServer() + { + Server?.Dispose(); + Server = null; + + string url = $"http://localhost:{_webServerPortSetting.Value}/"; + WebApiModule apiModule = new("/api/"); + WebServer server = new WebServer(o => o.WithUrlPrefix(url).WithMode(HttpListenerMode.EmbedIO)) + .WithLocalSessionManager() + .WithModule(apiModule) + .WithModule(_pluginModule) + .WithModule(new ActionModule("/", HttpVerbs.Any, ctx => ctx.SendDataAsync(new {Message = "Error"}))); + + // Add controllers to the API module + foreach (WebApiControllerRegistration registration in _controllers) + apiModule.RegisterController(registration.ControllerType, (Func) registration.UntypedFactory); + + // Listen for state changes. + server.StateChanged += (s, e) => _logger.Verbose("WebServer new state - {state}", e.NewState); + + // Store the URL in a webserver.txt file so that remote applications can find it + File.WriteAllText(Path.Combine(Constants.DataFolder, "webserver.txt"), url); + OnWebServerCreated(); + + return server; + } + + #endregion + + #region Event handlers + + private void WebServerPortSettingOnSettingChanged(object? sender, EventArgs e) + { + Server = CreateWebServer(); + Server.Start(); + } + + #endregion + + #region IDisposable + + /// + public void Dispose() + { + Server?.Dispose(); + _webServerPortSetting.SettingChanged -= WebServerPortSettingOnSettingChanged; + } + + #endregion + + #region Controller management + + public void AddController() where T : WebApiController + { + _controllers.Add(new WebApiControllerRegistration(_kernel)); + Server = CreateWebServer(); + Server.Start(); + } + + public void RemoveController() where T : WebApiController + { + _controllers.RemoveAll(r => r.ControllerType == typeof(T)); + Server = CreateWebServer(); + Server.Start(); + } + + #endregion + + #region Events + + public event EventHandler? WebServerCreated; + + protected virtual void OnWebServerCreated() + { + WebServerCreated?.Invoke(this, EventArgs.Empty); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Artemis.Core/packages.lock.json b/src/Artemis.Core/packages.lock.json index 03a69fcd6..c422d273d 100644 --- a/src/Artemis.Core/packages.lock.json +++ b/src/Artemis.Core/packages.lock.json @@ -12,6 +12,15 @@ "System.Threading.Tasks.Extensions": "4.5.3" } }, + "EmbedIO": { + "type": "Direct", + "requested": "[3.4.3, )", + "resolved": "3.4.3", + "contentHash": "YM6hpZNAfvbbixfG9T4lWDGfF0D/TqutbTROL4ogVcHKwPF1hp+xS3ABwd3cxxTxvDFkj/zZl57QgWuFA8Igxw==", + "dependencies": { + "Unosquare.Swan.Lite": "3.0.0" + } + }, "HidSharp": { "type": "Direct", "requested": "[2.1.0, )", @@ -1226,6 +1235,11 @@ "System.Xml.ReaderWriter": "4.3.0" } }, + "Unosquare.Swan.Lite": { + "type": "Transitive", + "resolved": "3.0.0", + "contentHash": "noPwJJl1Q9uparXy1ogtkmyAPGNfSGb0BLT1292nFH1jdMKje6o2kvvrQUvF9Xklj+IoiAI0UzF6Aqxlvo10lw==" + }, "artemis.storage": { "type": "Project", "dependencies": { diff --git a/src/Artemis.UI.Shared/Services/Message/MessageService.cs b/src/Artemis.UI.Shared/Services/Message/MessageService.cs index aef6ffc7e..45bd0e447 100644 --- a/src/Artemis.UI.Shared/Services/Message/MessageService.cs +++ b/src/Artemis.UI.Shared/Services/Message/MessageService.cs @@ -5,7 +5,7 @@ namespace Artemis.UI.Shared.Services { internal class MessageService : IMessageService { - private INotificationProvider _notificationProvider; + private INotificationProvider? _notificationProvider; public ISnackbarMessageQueue MainMessageQueue { get; } public MessageService(ISnackbarMessageQueue mainMessageQueue) @@ -74,20 +74,20 @@ namespace Artemis.UI.Shared.Services /// public void ShowNotification(string title, string message) { - _notificationProvider.ShowNotification(title, message, PackIconKind.None); + _notificationProvider?.ShowNotification(title, message, PackIconKind.None); } /// public void ShowNotification(string title, string message, PackIconKind icon) { - _notificationProvider.ShowNotification(title, message, icon); + _notificationProvider?.ShowNotification(title, message, icon); } /// public void ShowNotification(string title, string message, string icon) { Enum.TryParse(typeof(PackIconKind), icon, true, out object? iconKind); - _notificationProvider.ShowNotification(title, message, (PackIconKind) (iconKind ?? PackIconKind.None)); + _notificationProvider?.ShowNotification(title, message, (PackIconKind) (iconKind ?? PackIconKind.None)); } } } \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Services/Window/WindowService.cs b/src/Artemis.UI.Shared/Services/Window/WindowService.cs index c8b2a0ced..e0ce8bd1b 100644 --- a/src/Artemis.UI.Shared/Services/Window/WindowService.cs +++ b/src/Artemis.UI.Shared/Services/Window/WindowService.cs @@ -66,14 +66,12 @@ namespace Artemis.UI.Shared.Services public void OpenMainWindow() { - IsMainWindowOpen = true; - OnMainWindowOpened(); + _mainWindowManager?.OpenMainWindow(); } public void CloseMainWindow() { - IsMainWindowOpen = false; - OnMainWindowClosed(); + _mainWindowManager?.CloseMainWindow(); } public event EventHandler? MainWindowOpened; diff --git a/src/Artemis.UI.Shared/packages.lock.json b/src/Artemis.UI.Shared/packages.lock.json index db871839a..7c48f91d0 100644 --- a/src/Artemis.UI.Shared/packages.lock.json +++ b/src/Artemis.UI.Shared/packages.lock.json @@ -142,6 +142,14 @@ "System.Xml.XmlDocument": "4.3.0" } }, + "EmbedIO": { + "type": "Transitive", + "resolved": "3.4.3", + "contentHash": "YM6hpZNAfvbbixfG9T4lWDGfF0D/TqutbTROL4ogVcHKwPF1hp+xS3ABwd3cxxTxvDFkj/zZl57QgWuFA8Igxw==", + "dependencies": { + "Unosquare.Swan.Lite": "3.0.0" + } + }, "HidSharp": { "type": "Transitive", "resolved": "2.1.0", @@ -1305,11 +1313,17 @@ "System.Xml.ReaderWriter": "4.3.0" } }, + "Unosquare.Swan.Lite": { + "type": "Transitive", + "resolved": "3.0.0", + "contentHash": "noPwJJl1Q9uparXy1ogtkmyAPGNfSGb0BLT1292nFH1jdMKje6o2kvvrQUvF9Xklj+IoiAI0UzF6Aqxlvo10lw==" + }, "artemis.core": { "type": "Project", "dependencies": { "Artemis.Storage": "1.0.0", "Ben.Demystifier": "0.1.6", + "EmbedIO": "3.4.3", "HidSharp": "2.1.0", "Humanizer.Core": "2.8.26", "LiteDB": "5.0.9", diff --git a/src/Artemis.UI/Artemis.UI.csproj.DotSettings b/src/Artemis.UI/Artemis.UI.csproj.DotSettings index 7c2d2de36..8bd53f68f 100644 --- a/src/Artemis.UI/Artemis.UI.csproj.DotSettings +++ b/src/Artemis.UI/Artemis.UI.csproj.DotSettings @@ -1,2 +1,5 @@  - True \ No newline at end of file + True + True + True + True \ No newline at end of file diff --git a/src/Artemis.UI/Bootstrapper.cs b/src/Artemis.UI/Bootstrapper.cs index c9c24459a..0e66fd085 100644 --- a/src/Artemis.UI/Bootstrapper.cs +++ b/src/Artemis.UI/Bootstrapper.cs @@ -89,6 +89,7 @@ namespace Artemis.UI }); Kernel.Get().RegisterInputProvider(); + Kernel.Get(); } protected override void ConfigureIoC(IKernel kernel) diff --git a/src/Artemis.UI/Ninject/UiModule.cs b/src/Artemis.UI/Ninject/UiModule.cs index 13ead7e67..627334b0a 100644 --- a/src/Artemis.UI/Ninject/UiModule.cs +++ b/src/Artemis.UI/Ninject/UiModule.cs @@ -4,7 +4,7 @@ using Artemis.UI.Ninject.InstanceProviders; using Artemis.UI.Screens; using Artemis.UI.Screens.ProfileEditor; using Artemis.UI.Screens.Splash; -using Artemis.UI.Services.Interfaces; +using Artemis.UI.Services; using Artemis.UI.Shared.Services; using Artemis.UI.Stylet; using FluentValidation; diff --git a/src/Artemis.UI/Screens/ProfileEditor/Dialogs/ProfileImportViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Dialogs/ProfileImportViewModel.cs index ef89cef72..92c454c3c 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Dialogs/ProfileImportViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Dialogs/ProfileImportViewModel.cs @@ -3,13 +3,11 @@ using Artemis.Core.Modules; using Artemis.Core.Services; using Artemis.UI.Shared.Services; using ICSharpCode.AvalonEdit.Document; -using MaterialDesignThemes.Wpf; namespace Artemis.UI.Screens.ProfileEditor.Dialogs { public class ProfileImportViewModel : DialogViewModelBase { - private readonly ISnackbarMessageQueue _mainMessageQueue; private readonly IProfileService _profileService; private readonly IMessageService _messageService; private string _profileJson; diff --git a/src/Artemis.UI/Screens/ProfileEditor/Visualization/ProfileLayerViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Visualization/ProfileLayerViewModel.cs index 7aea3591f..afc9c6c54 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Visualization/ProfileLayerViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Visualization/ProfileLayerViewModel.cs @@ -6,7 +6,7 @@ using System.Windows.Media; using Artemis.Core; using Artemis.UI.Extensions; using Artemis.UI.Screens.Shared; -using Artemis.UI.Services.Interfaces; +using Artemis.UI.Services; using Artemis.UI.Shared.Services; namespace Artemis.UI.Screens.ProfileEditor.Visualization diff --git a/src/Artemis.UI/Screens/ProfileEditor/Visualization/Tools/EditToolViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Visualization/Tools/EditToolViewModel.cs index 8c49f86c4..40adf63e4 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Visualization/Tools/EditToolViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Visualization/Tools/EditToolViewModel.cs @@ -5,7 +5,7 @@ using System.Windows.Media; using Artemis.Core; using Artemis.UI.Events; using Artemis.UI.Screens.Shared; -using Artemis.UI.Services.Interfaces; +using Artemis.UI.Services; using Artemis.UI.Shared.Services; using SkiaSharp; using SkiaSharp.Views.WPF; diff --git a/src/Artemis.UI/Screens/RootViewModel.cs b/src/Artemis.UI/Screens/RootViewModel.cs index 35c55db05..e99e5127e 100644 --- a/src/Artemis.UI/Screens/RootViewModel.cs +++ b/src/Artemis.UI/Screens/RootViewModel.cs @@ -14,7 +14,6 @@ using Artemis.UI.Screens.Settings.Tabs.General; using Artemis.UI.Screens.Sidebar; using Artemis.UI.Screens.StartupWizard; using Artemis.UI.Services; -using Artemis.UI.Services.Interfaces; using Artemis.UI.Shared.Services; using Artemis.UI.Utilities; using MaterialDesignExtensions.Controls; diff --git a/src/Artemis.UI/Screens/Settings/Tabs/General/GeneralSettingsTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/General/GeneralSettingsTabViewModel.cs index 3a41acea1..4a304194b 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/General/GeneralSettingsTabViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/General/GeneralSettingsTabViewModel.cs @@ -14,7 +14,6 @@ using Artemis.Core.Services; using Artemis.UI.Properties; using Artemis.UI.Screens.StartupWizard; using Artemis.UI.Services; -using Artemis.UI.Services.Interfaces; using Artemis.UI.Shared; using Artemis.UI.Shared.Services; using MaterialDesignThemes.Wpf; diff --git a/src/Artemis.UI/Screens/TrayViewModel.cs b/src/Artemis.UI/Screens/TrayViewModel.cs index 666c8cd59..c17ab70ae 100644 --- a/src/Artemis.UI/Screens/TrayViewModel.cs +++ b/src/Artemis.UI/Screens/TrayViewModel.cs @@ -9,7 +9,6 @@ using Artemis.Core.Services; using Artemis.UI.Events; using Artemis.UI.Screens.Splash; using Artemis.UI.Services; -using Artemis.UI.Services.Interfaces; using Artemis.UI.Shared.Services; using Hardcodet.Wpf.TaskbarNotification; using MaterialDesignThemes.Wpf; @@ -25,7 +24,6 @@ namespace Artemis.UI.Screens private readonly IEventAggregator _eventAggregator; private readonly IKernel _kernel; private readonly IWindowManager _windowManager; - private bool _canShowRootViewModel; private RootViewModel _rootViewModel; private SplashViewModel _splashViewModel; private TaskbarIcon _taskBarIcon; @@ -44,7 +42,6 @@ namespace Artemis.UI.Screens _windowManager = windowManager; _eventAggregator = eventAggregator; _debugService = debugService; - CanShowRootViewModel = true; Core.Utilities.ShutdownRequested += UtilitiesOnShutdownRequested; Core.Utilities.RestartRequested += UtilitiesOnShutdownRequested; @@ -64,23 +61,19 @@ namespace Artemis.UI.Screens } } - public bool CanShowRootViewModel - { - get => _canShowRootViewModel; - set => SetAndNotify(ref _canShowRootViewModel, value); - } - public void TrayBringToForeground() { - if (!CanShowRootViewModel) + if (IsMainWindowOpen) + { + Execute.PostToUIThread(FocusMainWindow); return; + } // Initialize the shared UI when first showing the window if (!UI.Shared.Bootstrapper.Initialized) UI.Shared.Bootstrapper.Initialize(_kernel); - CanShowRootViewModel = false; - Execute.OnUIThread(() => + Execute.OnUIThreadSync(() => { _splashViewModel?.RequestClose(); _splashViewModel = null; @@ -115,24 +108,25 @@ namespace Artemis.UI.Screens public void OnTrayBalloonTipClicked(object sender, EventArgs e) { - if (CanShowRootViewModel) - { + if (!IsMainWindowOpen) TrayBringToForeground(); - } else - { - // Wrestle the main window to the front - Window mainWindow = (Window) _rootViewModel.View; - if (mainWindow.WindowState == WindowState.Minimized) - mainWindow.WindowState = WindowState.Normal; - mainWindow.Activate(); - mainWindow.Topmost = true; - mainWindow.Topmost = false; - mainWindow.Focus(); - } + FocusMainWindow(); } - private void UtilitiesOnShutdownRequested(object? sender, EventArgs e) + private void FocusMainWindow() + { + // Wrestle the main window to the front + Window mainWindow = (Window) _rootViewModel.View; + if (mainWindow.WindowState == WindowState.Minimized) + mainWindow.WindowState = WindowState.Normal; + mainWindow.Activate(); + mainWindow.Topmost = true; + mainWindow.Topmost = false; + mainWindow.Focus(); + } + + private void UtilitiesOnShutdownRequested(object sender, EventArgs e) { Execute.OnUIThread(() => _taskBarIcon?.Dispose()); } @@ -150,8 +144,6 @@ namespace Artemis.UI.Screens { _rootViewModel.Closed -= RootViewModelOnClosed; _rootViewModel = null; - - CanShowRootViewModel = true; OnMainWindowClosed(); } @@ -198,16 +190,16 @@ namespace Artemis.UI.Screens public bool OpenMainWindow() { - if (CanShowRootViewModel) - return false; - - TrayBringToForeground(); - return true; + if (IsMainWindowOpen) + Execute.OnUIThread(FocusMainWindow); + else + TrayBringToForeground(); + return _rootViewModel.ScreenState == ScreenState.Active; } public bool CloseMainWindow() { - _rootViewModel.RequestClose(); + Execute.OnUIThread(() => _rootViewModel.RequestClose()); return _rootViewModel.ScreenState == ScreenState.Closed; } diff --git a/src/Artemis.UI/Services/DebugService.cs b/src/Artemis.UI/Services/DebugService.cs index 158457079..060790479 100644 --- a/src/Artemis.UI/Services/DebugService.cs +++ b/src/Artemis.UI/Services/DebugService.cs @@ -1,6 +1,5 @@ using System.Windows; using Artemis.UI.Screens.Settings.Debug; -using Artemis.UI.Services.Interfaces; using MaterialDesignExtensions.Controls; using Ninject; using Stylet; diff --git a/src/Artemis.UI/Services/Interfaces/IArtemisUIService.cs b/src/Artemis.UI/Services/Interfaces/IArtemisUIService.cs index d29486dce..3e2b425b8 100644 --- a/src/Artemis.UI/Services/Interfaces/IArtemisUIService.cs +++ b/src/Artemis.UI/Services/Interfaces/IArtemisUIService.cs @@ -1,4 +1,4 @@ -namespace Artemis.UI.Services.Interfaces +namespace Artemis.UI.Services { // ReSharper disable once InconsistentNaming public interface IArtemisUIService diff --git a/src/Artemis.UI/Services/Interfaces/IDebugService.cs b/src/Artemis.UI/Services/Interfaces/IDebugService.cs index fd349ebba..331687677 100644 --- a/src/Artemis.UI/Services/Interfaces/IDebugService.cs +++ b/src/Artemis.UI/Services/Interfaces/IDebugService.cs @@ -1,4 +1,4 @@ -namespace Artemis.UI.Services.Interfaces +namespace Artemis.UI.Services { public interface IDebugService : IArtemisUIService { diff --git a/src/Artemis.UI/Services/Interfaces/ILayerEditorService.cs b/src/Artemis.UI/Services/Interfaces/ILayerEditorService.cs index 79799d183..1b2c687c7 100644 --- a/src/Artemis.UI/Services/Interfaces/ILayerEditorService.cs +++ b/src/Artemis.UI/Services/Interfaces/ILayerEditorService.cs @@ -3,7 +3,7 @@ using System.Windows.Media; using Artemis.Core; using SkiaSharp; -namespace Artemis.UI.Services.Interfaces +namespace Artemis.UI.Services { public interface ILayerEditorService : IArtemisUIService { diff --git a/src/Artemis.UI/Services/LayerEditorService.cs b/src/Artemis.UI/Services/LayerEditorService.cs index fcaa1143d..4ecde9cd8 100644 --- a/src/Artemis.UI/Services/LayerEditorService.cs +++ b/src/Artemis.UI/Services/LayerEditorService.cs @@ -2,7 +2,6 @@ using System.Windows; using System.Windows.Media; using Artemis.Core; -using Artemis.UI.Services.Interfaces; using SkiaSharp; using SkiaSharp.Views.WPF; diff --git a/src/Artemis.UI/Services/RegistrationService.cs b/src/Artemis.UI/Services/RegistrationService.cs index f64218a08..6ae335bf4 100644 --- a/src/Artemis.UI/Services/RegistrationService.cs +++ b/src/Artemis.UI/Services/RegistrationService.cs @@ -6,7 +6,6 @@ using Artemis.UI.DefaultTypes.DataModel.Input; using Artemis.UI.InputProviders; using Artemis.UI.Ninject; using Artemis.UI.PropertyInput; -using Artemis.UI.Services.Interfaces; using Artemis.UI.Shared.Services; using Serilog; diff --git a/src/Artemis.UI/Services/RemoteManagement/Interfaces/IRemoteManagementService.cs b/src/Artemis.UI/Services/RemoteManagement/Interfaces/IRemoteManagementService.cs new file mode 100644 index 000000000..25cafb0d3 --- /dev/null +++ b/src/Artemis.UI/Services/RemoteManagement/Interfaces/IRemoteManagementService.cs @@ -0,0 +1,6 @@ +namespace Artemis.UI.Services +{ + public interface IRemoteManagementService : IArtemisUIService + { + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Services/RemoteManagement/RemoteController.cs b/src/Artemis.UI/Services/RemoteManagement/RemoteController.cs new file mode 100644 index 000000000..a39468924 --- /dev/null +++ b/src/Artemis.UI/Services/RemoteManagement/RemoteController.cs @@ -0,0 +1,39 @@ +using System; +using Artemis.Core.Services; +using Artemis.UI.Shared.Services; +using EmbedIO; +using EmbedIO.Routing; +using EmbedIO.WebApi; + +namespace Artemis.UI.Services +{ + public class RemoteController : WebApiController + { + private readonly ICoreService _coreService; + private readonly IWindowService _windowService; + + public RemoteController(ICoreService coreService, IWindowService windowService) + { + _coreService = coreService; + _windowService = windowService; + } + + [Route(HttpVerbs.Post, "/remote/bring-to-foreground")] + public void PostBringToForeground() + { + _windowService.OpenMainWindow(); + } + + [Route(HttpVerbs.Post, "/remote/restart")] + public void PostRestart() + { + Core.Utilities.Restart(_coreService.IsElevated, TimeSpan.FromMilliseconds(500)); + } + + [Route(HttpVerbs.Post, "/remote/shutdown")] + public void PostShutdown() + { + Core.Utilities.Shutdown(); + } + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Services/RemoteManagement/RemoteManagementService.cs b/src/Artemis.UI/Services/RemoteManagement/RemoteManagementService.cs new file mode 100644 index 000000000..956e8a474 --- /dev/null +++ b/src/Artemis.UI/Services/RemoteManagement/RemoteManagementService.cs @@ -0,0 +1,12 @@ +using Artemis.Core.Services; + +namespace Artemis.UI.Services +{ + public class RemoteManagementService : IRemoteManagementService + { + public RemoteManagementService(IWebServerService webServerService) + { + webServerService.AddController(); + } + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Services/UpdateService.cs b/src/Artemis.UI/Services/UpdateService.cs index 21af544b1..69704201a 100644 --- a/src/Artemis.UI/Services/UpdateService.cs +++ b/src/Artemis.UI/Services/UpdateService.cs @@ -10,7 +10,6 @@ using Artemis.Core; using Artemis.Core.Services; using Artemis.UI.Exceptions; using Artemis.UI.Screens.Settings.Dialogs; -using Artemis.UI.Services.Interfaces; using Artemis.UI.Shared.Services; using MaterialDesignThemes.Wpf; using Newtonsoft.Json.Linq; @@ -209,7 +208,7 @@ namespace Artemis.UI.Services AutoUpdate(); } - private void WindowServiceOnMainWindowOpened(object? sender, EventArgs e) + private void WindowServiceOnMainWindowOpened(object sender, EventArgs e) { _logger.Information("Main window opened!"); } diff --git a/src/Artemis.UI/packages.lock.json b/src/Artemis.UI/packages.lock.json index 83f215a37..8a022ea4a 100644 --- a/src/Artemis.UI/packages.lock.json +++ b/src/Artemis.UI/packages.lock.json @@ -195,6 +195,14 @@ "System.Xml.XmlDocument": "4.3.0" } }, + "EmbedIO": { + "type": "Transitive", + "resolved": "3.4.3", + "contentHash": "YM6hpZNAfvbbixfG9T4lWDGfF0D/TqutbTROL4ogVcHKwPF1hp+xS3ABwd3cxxTxvDFkj/zZl57QgWuFA8Igxw==", + "dependencies": { + "Unosquare.Swan.Lite": "3.0.0" + } + }, "HidSharp": { "type": "Transitive", "resolved": "2.1.0", @@ -1357,6 +1365,11 @@ "System.Xml.ReaderWriter": "4.3.0" } }, + "Unosquare.Swan.Lite": { + "type": "Transitive", + "resolved": "3.0.0", + "contentHash": "noPwJJl1Q9uparXy1ogtkmyAPGNfSGb0BLT1292nFH1jdMKje6o2kvvrQUvF9Xklj+IoiAI0UzF6Aqxlvo10lw==" + }, "WriteableBitmapEx": { "type": "Transitive", "resolved": "1.6.7", @@ -1367,6 +1380,7 @@ "dependencies": { "Artemis.Storage": "1.0.0", "Ben.Demystifier": "0.1.6", + "EmbedIO": "3.4.3", "HidSharp": "2.1.0", "Humanizer.Core": "2.8.26", "LiteDB": "5.0.9",