Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/SiteMonitor/Constants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Reflection;

namespace SiteMonitor;

/// <summary>
/// Constants used throughout the file.
/// </summary>
public class Constants {
/// <summary>
/// The version of the application being run right now.
/// </summary>
public static readonly string? APP_VERSION = Assembly.GetEntryAssembly()?.GetName().Version?.ToString()[..^2];
}
74 changes: 66 additions & 8 deletions src/SiteMonitor/ViewModels/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -19,19 +21,24 @@ namespace SiteMonitor.ViewModels;
/// The view model for the main UI.
/// </summary>
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;

/// <summary>
/// Initializes a new instance of the <see cref="MainWindowViewModel" /> class.
/// </summary>
public MainWindowViewModel() {
OnShowCommandsCommand = ReactiveCommand.Create(OnShowCommands);
OnRestartCommand = ReactiveCommand.Create(OnRestart);
Task.Factory.StartNew(PingServer);
Task.Factory.StartNew(PingSite);
ServerAddress = Configuration.Instance.ServerAddress;
Expand Down Expand Up @@ -112,6 +119,57 @@ public bool IsMinimized {
set => this.RaiseAndSetIfChanged(ref _isMinimized, value);
}

/// <summary>
/// Shows the commands in the UI.
/// </summary>
public ICommand OnShowCommandsCommand { get; set; }

/// <summary>
/// True if displaying advanced commands, false otherwise.
/// </summary>
public bool IsDisplayingAdvancedCommands {
get => _isDisplayingAdvancedCommands;
set => this.RaiseAndSetIfChanged(ref _isDisplayingAdvancedCommands, value);
}

/// <summary>
/// The username to use for the SSH session for commands.
/// </summary>
public string? SshUsername {
get => _sshUsername;
set => this.RaiseAndSetIfChanged(ref _sshUsername, value);
}

/// <summary>
/// The password to use for the SSH session for commands.
/// </summary>
public string? SshPassword {
get => _sshPassword;
set => this.RaiseAndSetIfChanged(ref _sshPassword, value);
}

/// <summary>
/// Restarts the remote machine.
/// </summary>
public ICommand OnRestartCommand { get; set; }

/// <summary>
/// Restarts the remote machine.
/// </summary>
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}");
}

/// <summary>
/// Handles showing the server commands.
/// </summary>
private void OnShowCommands() {
IsDisplayingAdvancedCommands = true;
}

/// <summary>
/// Pings the web resources.
/// </summary>
Expand Down Expand Up @@ -152,7 +210,7 @@ private async Task<bool> 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;
}
Expand All @@ -172,7 +230,7 @@ private async Task<bool> 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();
}
Expand Down
117 changes: 82 additions & 35 deletions src/SiteMonitor/Views/MainWindow.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -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}"
Expand All @@ -24,41 +24,88 @@
<viewModels:MainWindowViewModel />
</Design.DataContext>

<Grid Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Grid.Row="0">
<Label VerticalAlignment="Center">Server Address:</Label>
<TextBox Text="{Binding ServerAddress, Mode=TwoWay}" Width="300" />
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Row="1" Margin="0, 5, 0, 0">
<Label VerticalAlignment="Center">Last Chat Received:</Label>
<TextBox IsReadOnly="True" Text="{Binding ChatTimestamp}" Width="300" />
</StackPanel>
<UniformGrid Grid.Row="2" Margin="0 25 0 0">
<StackPanel>
<Label FontSize="26" HorizontalAlignment="Center">Server Online</Label>
<Image Source="/Assets/good.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding ServerUp}" />
<Image Source="/Assets/bad.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding !ServerUp}" />
<ScrollViewer>
<Grid Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Grid.Row="0">
<Label VerticalAlignment="Center">Server Address:</Label>
<TextBox Text="{Binding ServerAddress, Mode=TwoWay}" Width="300" />
</StackPanel>
<StackPanel>
<Label FontSize="26" HorizontalAlignment="Center">Website</Label>
<Image Source="/Assets/good.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding WebsiteUp}" />
<Image Source="/Assets/bad.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding !WebsiteUp}" />
<StackPanel Orientation="Horizontal" Grid.Row="1" Margin="0, 5, 0, 5">
<Label VerticalAlignment="Center">Last Chat Received:</Label>
<TextBox IsReadOnly="True" Text="{Binding ChatTimestamp}" Width="300" />
</StackPanel>
<StackPanel>
<Label FontSize="26" HorizontalAlignment="Center">Api</Label>
<Image Source="/Assets/good.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding ApiUp}" />
<Image Source="/Assets/bad.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding !ApiUp}" />
</StackPanel>
<StackPanel>
<Label FontSize="26" HorizontalAlignment="Center">Null</Label>
<Image Source="/Assets/good.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding NullUp}" />
<Image Source="/Assets/bad.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding !NullUp}" />
<StackPanel Grid.Row="2">
<Button HorizontalAlignment="Right"
IsVisible="{Binding !IsDisplayingAdvancedCommands}"
Command="{Binding OnShowCommandsCommand}">
Show Advanced Commands
</Button>
<StackPanel IsVisible="{Binding IsDisplayingAdvancedCommands}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>

<Label Grid.Row="0"
Grid.Column="0"
HorizontalAlignment="Right">
Username:
</Label>
<TextBox Grid.Row="0"
Grid.Column="1"
Margin="0 0 0 5"
Text="{Binding SshUsername}" />
<Label Grid.Row="1"
Grid.Column="0"
HorizontalAlignment="Right">
Password:
</Label>
<TextBox Grid.Row="1"
Grid.Column="1"
Margin="0 0 0 5"
PasswordChar="*"
RevealPassword="False"
Text="{Binding SshPassword}" />
</Grid>
<Button HorizontalAlignment="Right"
Command="{Binding OnRestartCommand}">
Restart Computer
</Button>
</StackPanel>
</StackPanel>
</UniformGrid>
</Grid>
<UniformGrid Grid.Row="3" Margin="0 25 0 0">
<StackPanel>
<Label FontSize="26" HorizontalAlignment="Center">Server Online</Label>
<Image Source="/Assets/good.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding ServerUp}" />
<Image Source="/Assets/bad.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding !ServerUp}" />
</StackPanel>
<StackPanel>
<Label FontSize="26" HorizontalAlignment="Center">Website</Label>
<Image Source="/Assets/good.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding WebsiteUp}" />
<Image Source="/Assets/bad.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding !WebsiteUp}" />
</StackPanel>
<StackPanel>
<Label FontSize="26" HorizontalAlignment="Center">Api</Label>
<Image Source="/Assets/good.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding ApiUp}" />
<Image Source="/Assets/bad.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding !ApiUp}" />
</StackPanel>
<StackPanel>
<Label FontSize="26" HorizontalAlignment="Center">Null</Label>
<Image Source="/Assets/good.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding NullUp}" />
<Image Source="/Assets/bad.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding !NullUp}" />
</StackPanel>
</UniformGrid>
</Grid>
</ScrollViewer>
</Window>
65 changes: 50 additions & 15 deletions src/SiteMonitor/Views/MainWindow.axaml.cs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -20,41 +27,69 @@ public partial class MainWindow : Window {
/// </summary>
public MainWindow() {
InitializeComponent();
#if DEBUG
this.AttachDevTools();
#endif
}

/// <summary>
/// The service provider for DI.
/// </summary>
public IServiceProvider? ServiceProvider { get; set; }

/// <summary>
/// Checks for a new version number of the application.
/// </summary>
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<NewVersionWindowViewModel>();
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
});
}
}