diff --git a/src/SiteMonitor/Constants.cs b/src/SiteMonitor/Constants.cs
new file mode 100644
index 0000000..e189039
--- /dev/null
+++ b/src/SiteMonitor/Constants.cs
@@ -0,0 +1,13 @@
+using System.Reflection;
+
+namespace SiteMonitor;
+
+///
+/// Constants used throughout the file.
+///
+public class Constants {
+ ///
+ /// The version of the application being run right now.
+ ///
+ public static readonly string? APP_VERSION = Assembly.GetEntryAssembly()?.GetName().Version?.ToString()[..^2];
+}
\ No newline at end of file
diff --git a/src/SiteMonitor/ViewModels/MainWindowViewModel.cs b/src/SiteMonitor/ViewModels/MainWindowViewModel.cs
index 6ddda96..4fad562 100644
--- a/src/SiteMonitor/ViewModels/MainWindowViewModel.cs
+++ b/src/SiteMonitor/ViewModels/MainWindowViewModel.cs
@@ -3,14 +3,16 @@
using System.Net;
using System.Net.Http;
using System.Net.NetworkInformation;
+using System.Threading;
using System.Threading.Tasks;
+using System.Windows.Input;
using Avalonia.Controls;
-using Nullinside.Api.Common;
-
using ReactiveUI;
+using Renci.SshNet;
+
using SiteMonitor.Models;
namespace SiteMonitor.ViewModels;
@@ -19,19 +21,24 @@ namespace SiteMonitor.ViewModels;
/// The view model for the main UI.
///
public class MainWindowViewModel : ViewModelBase {
- private bool _apiUp;
+ private bool _apiUp = true;
private string? _chatTimestamp;
+ private bool _isDisplayingAdvancedCommands;
private bool _isMinimized;
- private bool _nullUp;
+ private bool _nullUp = true;
private string? _serverAddress;
- private bool _serverUp;
- private bool _websiteUp;
+ private bool _serverUp = true;
+ private string? _sshPassword;
+ private string? _sshUsername;
+ private bool _websiteUp = true;
private WindowState _windowState;
///
/// Initializes a new instance of the class.
///
public MainWindowViewModel() {
+ OnShowCommandsCommand = ReactiveCommand.Create(OnShowCommands);
+ OnRestartCommand = ReactiveCommand.Create(OnRestart);
Task.Factory.StartNew(PingServer);
Task.Factory.StartNew(PingSite);
ServerAddress = Configuration.Instance.ServerAddress;
@@ -112,6 +119,57 @@ public bool IsMinimized {
set => this.RaiseAndSetIfChanged(ref _isMinimized, value);
}
+ ///
+ /// Shows the commands in the UI.
+ ///
+ public ICommand OnShowCommandsCommand { get; set; }
+
+ ///
+ /// True if displaying advanced commands, false otherwise.
+ ///
+ public bool IsDisplayingAdvancedCommands {
+ get => _isDisplayingAdvancedCommands;
+ set => this.RaiseAndSetIfChanged(ref _isDisplayingAdvancedCommands, value);
+ }
+
+ ///
+ /// The username to use for the SSH session for commands.
+ ///
+ public string? SshUsername {
+ get => _sshUsername;
+ set => this.RaiseAndSetIfChanged(ref _sshUsername, value);
+ }
+
+ ///
+ /// The password to use for the SSH session for commands.
+ ///
+ public string? SshPassword {
+ get => _sshPassword;
+ set => this.RaiseAndSetIfChanged(ref _sshPassword, value);
+ }
+
+ ///
+ /// Restarts the remote machine.
+ ///
+ public ICommand OnRestartCommand { get; set; }
+
+ ///
+ /// Restarts the remote machine.
+ ///
+ private async Task OnRestart() {
+ using SshClient client = new(_serverAddress!, _sshUsername!, _sshPassword!);
+ await client.ConnectAsync(CancellationToken.None);
+ string command = "shutdown -r now";
+ using SshCommand? ssh = client.RunCommand($"echo {_sshPassword} | sudo -S {command}");
+ }
+
+ ///
+ /// Handles showing the server commands.
+ ///
+ private void OnShowCommands() {
+ IsDisplayingAdvancedCommands = true;
+ }
+
///
/// Pings the web resources.
///
@@ -152,7 +210,7 @@ private async Task SendHeadRequest(string address) {
handler.AutomaticDecompression = ~DecompressionMethods.None;
using var httpClient = new HttpClient(handler);
using var request = new HttpRequestMessage(HttpMethod.Get, address);
- request.Headers.TryAddWithoutValidation("user-agent", Constants.FAKE_USER_AGENT);
+ request.Headers.TryAddWithoutValidation("user-agent", Nullinside.Api.Common.Constants.FAKE_USER_AGENT);
HttpResponseMessage response = await httpClient.SendAsync(request);
return response.IsSuccessStatusCode;
}
@@ -172,7 +230,7 @@ private async Task SendHeadRequest(string address) {
handler.AutomaticDecompression = ~DecompressionMethods.None;
using var httpClient = new HttpClient(handler);
using var request = new HttpRequestMessage(HttpMethod.Get, address);
- request.Headers.TryAddWithoutValidation("user-agent", Constants.FAKE_USER_AGENT);
+ request.Headers.TryAddWithoutValidation("user-agent", Nullinside.Api.Common.Constants.FAKE_USER_AGENT);
HttpResponseMessage response = await httpClient.SendAsync(request);
return await response.Content.ReadAsStringAsync();
}
diff --git a/src/SiteMonitor/Views/MainWindow.axaml b/src/SiteMonitor/Views/MainWindow.axaml
index 3f7141f..e70bdde 100644
--- a/src/SiteMonitor/Views/MainWindow.axaml
+++ b/src/SiteMonitor/Views/MainWindow.axaml
@@ -7,7 +7,7 @@
d:DesignWidth="475"
d:DesignHeight="300"
Width="475"
- Height="300"
+ Height="400"
CanResize="False"
WindowState="{Binding WindowState, Mode=TwoWay}"
ShowInTaskbar="{Binding !IsMinimized, Mode=TwoWay}"
@@ -24,41 +24,88 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/SiteMonitor/Views/MainWindow.axaml.cs b/src/SiteMonitor/Views/MainWindow.axaml.cs
index e552282..0f05a92 100644
--- a/src/SiteMonitor/Views/MainWindow.axaml.cs
+++ b/src/SiteMonitor/Views/MainWindow.axaml.cs
@@ -1,13 +1,20 @@
using System;
-using System.Reflection;
+using System.Linq;
using System.Threading.Tasks;
using Avalonia.Controls;
-using Avalonia.Threading;
using Nullinside.Api.Common.Desktop;
+#if !DEBUG
+using Microsoft.Extensions.DependencyInjection;
+
+using Avalonia.Threading;
using SiteMonitor.ViewModels;
+#else
+using Avalonia;
+#endif
+
namespace SiteMonitor.Views;
@@ -20,41 +27,69 @@ public partial class MainWindow : Window {
///
public MainWindow() {
InitializeComponent();
+#if DEBUG
+ this.AttachDevTools();
+#endif
}
+ ///
+ /// The service provider for DI.
+ ///
+ public IServiceProvider? ServiceProvider { get; set; }
+
///
/// Checks for a new version number of the application.
///
protected override void OnInitialized() {
base.OnInitialized();
+ // handle the command line arguments for updating the application if applicable.
+ string[] args = Environment.GetCommandLineArgs();
+ if (args.Contains("--update")) {
+ _ = GitHubUpdateManager.PerformUpdateAndRestart("nullinside-development-group", "twitch-streaming-tools", args[2], "windows-x64.zip");
+ return;
+ }
+
+ if (args.Contains("--justUpdated")) {
+ _ = GitHubUpdateManager.CleanupUpdate();
+ }
+
+ // check for a new version of the application.
Task.Factory.StartNew(async () => {
GithubLatestReleaseJson? serverVersion =
await GitHubUpdateManager.GetLatestVersion("nullinside-development-group", "nullinside-site-monitor");
- string? localVersion = Assembly.GetEntryAssembly()?.GetName().Version?.ToString();
- if (null == serverVersion || string.IsNullOrWhiteSpace(serverVersion.name) ||
- string.IsNullOrWhiteSpace(localVersion)) {
+ if (null == serverVersion || string.IsNullOrWhiteSpace(serverVersion.name)) {
return;
}
- localVersion = localVersion.Substring(0, localVersion.LastIndexOf('.'));
- if (string.IsNullOrWhiteSpace(localVersion)) {
+ if (serverVersion.name?.Equals(Constants.APP_VERSION, StringComparison.InvariantCultureIgnoreCase) ?? true) {
+// Had to add this because code clean up tools were removing the "redundant" return statement.
+// which was causing the check to always be ignored.
+#if !DEBUG
return;
+#endif
}
- if (serverVersion.name?.Equals(localVersion, StringComparison.InvariantCultureIgnoreCase) ?? true) {
+#if !DEBUG
+ var vm = ServiceProvider?.GetRequiredService();
+ if (null == vm) {
return;
}
- Dispatcher.UIThread.Post(async () => {
- var versionWindow = new NewVersionWindow {
- DataContext = new NewVersionWindowViewModel {
- LocalVersion = localVersion
- }
- };
+ vm.LocalVersion = Constants.APP_VERSION;
+ Dispatcher.UIThread.Post(async void () => {
+ try {
+ var versionWindow = new NewVersionWindow {
+ DataContext = vm
+ };
- await versionWindow.ShowDialog(this);
+ await versionWindow.ShowDialog(this);
+ }
+ catch {
+ // do nothing, don't crash
+ }
});
+#endif
});
}
}
\ No newline at end of file