diff --git a/src/SiteMonitor/Controls/Loading.axaml b/src/SiteMonitor/Controls/Loading.axaml
new file mode 100644
index 0000000..778ef48
--- /dev/null
+++ b/src/SiteMonitor/Controls/Loading.axaml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/SiteMonitor/Controls/Loading.axaml.cs b/src/SiteMonitor/Controls/Loading.axaml.cs
new file mode 100644
index 0000000..2890eb7
--- /dev/null
+++ b/src/SiteMonitor/Controls/Loading.axaml.cs
@@ -0,0 +1,15 @@
+using Avalonia.Controls;
+
+namespace SiteMonitor.Controls;
+
+///
+/// A loading icon.
+///
+public partial class Loading : UserControl {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public Loading() {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/src/SiteMonitor/Models/Configuration.cs b/src/SiteMonitor/Models/Configuration.cs
index 1d2843e..acb17ab 100644
--- a/src/SiteMonitor/Models/Configuration.cs
+++ b/src/SiteMonitor/Models/Configuration.cs
@@ -20,6 +20,16 @@ public class Configuration {
///
public string? ServerAddress { get; set; }
+ ///
+ /// The server username.
+ ///
+ public string? ServerUsername { get; set; }
+
+ ///
+ /// The server username's password.
+ ///
+ public string? ServerPassword { get; set; }
+
///
/// The singleton instance of the class.
///
@@ -35,6 +45,10 @@ public static Configuration Instance {
private static Configuration? ReadConfiguration() {
try {
+ if (!Directory.Exists(Path.GetDirectoryName(S_CONFIG_LOCATION))) {
+ Directory.CreateDirectory(Path.GetDirectoryName(S_CONFIG_LOCATION)!);
+ }
+
string json = File.ReadAllText(S_CONFIG_LOCATION);
return JsonConvert.DeserializeObject(json);
}
diff --git a/src/SiteMonitor/ServiceCollectionExtensions.cs b/src/SiteMonitor/ServiceCollectionExtensions.cs
new file mode 100644
index 0000000..17cbf80
--- /dev/null
+++ b/src/SiteMonitor/ServiceCollectionExtensions.cs
@@ -0,0 +1,20 @@
+using Microsoft.Extensions.DependencyInjection;
+
+using SiteMonitor.ViewModels;
+
+namespace SiteMonitor;
+
+///
+/// A wrapper that contains the registered services.
+///
+public static class ServiceCollectionExtensions {
+ ///
+ /// Adds the services used throughout the application.
+ ///
+ /// The services collection to initialize.
+ public static void AddCommonServices(this IServiceCollection collection) {
+ // View models
+ collection.AddTransient();
+ collection.AddTransient();
+ }
+}
\ No newline at end of file
diff --git a/src/SiteMonitor/SiteMonitor.csproj b/src/SiteMonitor/SiteMonitor.csproj
index d1ea71b..1b4e6f5 100644
--- a/src/SiteMonitor/SiteMonitor.csproj
+++ b/src/SiteMonitor/SiteMonitor.csproj
@@ -26,13 +26,13 @@
-
-
-
-
+
+
+
+
-
+
diff --git a/src/SiteMonitor/ViewModels/MainWindowViewModel.cs b/src/SiteMonitor/ViewModels/MainWindowViewModel.cs
index 4fad562..12749d2 100644
--- a/src/SiteMonitor/ViewModels/MainWindowViewModel.cs
+++ b/src/SiteMonitor/ViewModels/MainWindowViewModel.cs
@@ -42,6 +42,8 @@ public MainWindowViewModel() {
Task.Factory.StartNew(PingServer);
Task.Factory.StartNew(PingSite);
ServerAddress = Configuration.Instance.ServerAddress;
+ SshUsername = Configuration.Instance.ServerUsername;
+ SshPassword = Configuration.Instance.ServerPassword;
}
///
@@ -137,7 +139,14 @@ public bool IsDisplayingAdvancedCommands {
///
public string? SshUsername {
get => _sshUsername;
- set => this.RaiseAndSetIfChanged(ref _sshUsername, value);
+ set {
+ Configuration.Instance.ServerUsername = value;
+ this.RaiseAndSetIfChanged(ref _sshUsername, value);
+ try {
+ Configuration.WriteConfiguration();
+ }
+ catch { }
+ }
}
///
@@ -145,7 +154,14 @@ public string? SshUsername {
///
public string? SshPassword {
get => _sshPassword;
- set => this.RaiseAndSetIfChanged(ref _sshPassword, value);
+ set {
+ Configuration.Instance.ServerPassword = value;
+ this.RaiseAndSetIfChanged(ref _sshPassword, value);
+ try {
+ Configuration.WriteConfiguration();
+ }
+ catch { }
+ }
}
///
@@ -178,9 +194,10 @@ private async Task PingSite() {
WebsiteUp = await SendHeadRequest("https://nullinside.com");
ApiUp = await SendHeadRequest("https://nullinside.com/api/v1/featureToggle");
NullUp = await SendHeadRequest("https://nullinside.com/null/v1/database/migration");
- ChatTimestamp = await SendGetRequest("https://nullinside.com/twitch-bot/v1/bot/chat/timestamp");
+ (HttpStatusCode, string?) chat = await SendGetRequest("https://nullinside.com/twitch-bot/v1/bot/chat/timestamp");
bool chatNotUpdating = false;
- if (null != ChatTimestamp) {
+ if (HttpStatusCode.OK == chat.Item1 && null != chat.Item2) {
+ ChatTimestamp = chat.Item2;
string parsed = ChatTimestamp.Trim('"');
if (DateTime.TryParse(parsed, out DateTime time)) {
string timestamp = time.ToLocalTime().ToString(CultureInfo.InvariantCulture);
@@ -190,6 +207,10 @@ private async Task PingSite() {
chatNotUpdating = diff > TimeSpan.FromMinutes(5);
}
}
+ else {
+ ChatTimestamp = null;
+ chatNotUpdating = true;
+ }
if ((!WebsiteUp || !ApiUp || !NullUp || chatNotUpdating) && IsMinimized) {
WindowState = WindowState.Normal;
@@ -224,7 +245,7 @@ private async Task SendHeadRequest(string address) {
///
/// The address to send the request to.
/// The content of the response.
- private async Task SendGetRequest(string address) {
+ private async Task<(HttpStatusCode, string?)> SendGetRequest(string address) {
try {
var handler = new HttpClientHandler();
handler.AutomaticDecompression = ~DecompressionMethods.None;
@@ -232,10 +253,10 @@ private async Task SendHeadRequest(string address) {
using var request = new HttpRequestMessage(HttpMethod.Get, address);
request.Headers.TryAddWithoutValidation("user-agent", Nullinside.Api.Common.Constants.FAKE_USER_AGENT);
HttpResponseMessage response = await httpClient.SendAsync(request);
- return await response.Content.ReadAsStringAsync();
+ return (response.StatusCode, await response.Content.ReadAsStringAsync());
}
catch {
- return null;
+ return (HttpStatusCode.InternalServerError, null);
}
}
diff --git a/src/SiteMonitor/ViewModels/NewVersionWindowViewModel.cs b/src/SiteMonitor/ViewModels/NewVersionWindowViewModel.cs
index 8027a53..d1da320 100644
--- a/src/SiteMonitor/ViewModels/NewVersionWindowViewModel.cs
+++ b/src/SiteMonitor/ViewModels/NewVersionWindowViewModel.cs
@@ -17,6 +17,11 @@ namespace SiteMonitor.ViewModels;
/// The view model for the class.
///
public class NewVersionWindowViewModel : ViewModelBase {
+ ///
+ /// True if updating the application currently, false otherwise.
+ ///
+ private bool _isUpdating;
+
///
/// The local version of the software.
///
@@ -36,9 +41,10 @@ public class NewVersionWindowViewModel : ViewModelBase {
/// Initializes a new instance of the class.
///
public NewVersionWindowViewModel() {
- OpenBrowser = ReactiveCommand.Create(LaunchBrowser);
+ UpdateSoftware = ReactiveCommand.Create(StartUpdateSoftware);
CloseWindow = ReactiveCommand.Create(CloseWindowCommand);
+ // asynchronously determine the current version number.
Task.Factory.StartNew(async () => {
GithubLatestReleaseJson? version =
await GitHubUpdateManager.GetLatestVersion("nullinside-development-group", "nullinside-site-monitor");
@@ -69,9 +75,17 @@ public string? ServerVersion {
}
///
- /// A command to open the browser window at the current update's location.
+ /// True if updating the application currently, false otherwise.
+ ///
+ public bool IsUpdating {
+ get => _isUpdating;
+ set => this.RaiseAndSetIfChanged(ref _isUpdating, value);
+ }
+
+ ///
+ /// A command to update the software.
///
- public ICommand OpenBrowser { get; }
+ public ICommand UpdateSoftware { get; }
///
/// A command to close the current window.
@@ -89,11 +103,16 @@ private void CloseWindowCommand(Window self) {
///
/// Launches the web browser at the new release page.
///
- private void LaunchBrowser() {
- if (string.IsNullOrWhiteSpace(_newVersionUrl)) {
- return;
- }
-
- Process.Start("explorer", _newVersionUrl);
+ private void StartUpdateSoftware() {
+ IsUpdating = true;
+ GitHubUpdateManager.PrepareUpdate()
+ .ContinueWith(_ => {
+ if (string.IsNullOrWhiteSpace(_newVersionUrl)) {
+ return;
+ }
+
+ Process.Start("explorer", _newVersionUrl);
+ GitHubUpdateManager.ExitApplicationToUpdate();
+ }).ConfigureAwait(false);
}
}
\ No newline at end of file
diff --git a/src/SiteMonitor/Views/MainWindow.axaml.cs b/src/SiteMonitor/Views/MainWindow.axaml.cs
index 06fc365..ff365e1 100644
--- a/src/SiteMonitor/Views/MainWindow.axaml.cs
+++ b/src/SiteMonitor/Views/MainWindow.axaml.cs
@@ -5,10 +5,10 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
-using Nullinside.Api.Common.Desktop;
-#if !DEBUG
using Microsoft.Extensions.DependencyInjection;
+using Nullinside.Api.Common.Desktop;
+#if !DEBUG
using Avalonia.Threading;
using SiteMonitor.ViewModels;
@@ -44,10 +44,15 @@ public MainWindow() {
protected override void OnInitialized() {
base.OnInitialized();
+ // Register all the services needed for the application to run
+ var collection = new ServiceCollection();
+ collection.AddCommonServices();
+ ServiceProvider = collection.BuildServiceProvider();
+
// 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");
+ _ = GitHubUpdateManager.PerformUpdateAndRestart("nullinside-development-group", "nullinside-site-monitor", args[2], "windows-x64.zip");
return;
}
diff --git a/src/SiteMonitor/Views/NewVersionWindow.axaml b/src/SiteMonitor/Views/NewVersionWindow.axaml
index 8170ab1..ed05fd0 100644
--- a/src/SiteMonitor/Views/NewVersionWindow.axaml
+++ b/src/SiteMonitor/Views/NewVersionWindow.axaml
@@ -3,34 +3,55 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="clr-namespace:SiteMonitor.ViewModels"
+ xmlns:controls="clr-namespace:SiteMonitor.Controls"
x:Name="Window"
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
x:Class="SiteMonitor.Views.NewVersionWindow"
x:DataType="viewModels:NewVersionWindowViewModel"
WindowStartupLocation="CenterOwner"
- Topmost="True"
SizeToContent="WidthAndHeight"
Icon="/Assets/update.png"
- Title="New Version Available">
+ Title="New Version Available"
+ Background="rgb(26, 24, 23)">
-
-
- There is a new version of the software available, would you like to download it?
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+ There is a new version of the software available, would you like to download it?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
\ No newline at end of file