Skip to content

Commit 68a7357

Browse files
feat: adding button to restart machine
1 parent eb84ec8 commit 68a7357

File tree

4 files changed

+211
-58
lines changed

4 files changed

+211
-58
lines changed

src/SiteMonitor/Constants.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System.Reflection;
2+
3+
namespace SiteMonitor;
4+
5+
/// <summary>
6+
/// Constants used throughout the file.
7+
/// </summary>
8+
public class Constants {
9+
/// <summary>
10+
/// The version of the application being run right now.
11+
/// </summary>
12+
public static readonly string? APP_VERSION = Assembly.GetEntryAssembly()?.GetName().Version?.ToString()[..^2];
13+
}

src/SiteMonitor/ViewModels/MainWindowViewModel.cs

Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@
33
using System.Net;
44
using System.Net.Http;
55
using System.Net.NetworkInformation;
6+
using System.Threading;
67
using System.Threading.Tasks;
8+
using System.Windows.Input;
79

810
using Avalonia.Controls;
911

10-
using Nullinside.Api.Common;
11-
1212
using ReactiveUI;
1313

14+
using Renci.SshNet;
15+
1416
using SiteMonitor.Models;
1517

1618
namespace SiteMonitor.ViewModels;
@@ -19,19 +21,24 @@ namespace SiteMonitor.ViewModels;
1921
/// The view model for the main UI.
2022
/// </summary>
2123
public class MainWindowViewModel : ViewModelBase {
22-
private bool _apiUp;
24+
private bool _apiUp = true;
2325
private string? _chatTimestamp;
26+
private bool _isDisplayingAdvancedCommands;
2427
private bool _isMinimized;
25-
private bool _nullUp;
28+
private bool _nullUp = true;
2629
private string? _serverAddress;
27-
private bool _serverUp;
28-
private bool _websiteUp;
30+
private bool _serverUp = true;
31+
private string? _sshPassword;
32+
private string? _sshUsername;
33+
private bool _websiteUp = true;
2934
private WindowState _windowState;
3035

3136
/// <summary>
3237
/// Initializes a new instance of the <see cref="MainWindowViewModel" /> class.
3338
/// </summary>
3439
public MainWindowViewModel() {
40+
OnShowCommandsCommand = ReactiveCommand.Create(OnShowCommands);
41+
OnRestartCommand = ReactiveCommand.Create(OnRestart);
3542
Task.Factory.StartNew(PingServer);
3643
Task.Factory.StartNew(PingSite);
3744
ServerAddress = Configuration.Instance.ServerAddress;
@@ -112,6 +119,57 @@ public bool IsMinimized {
112119
set => this.RaiseAndSetIfChanged(ref _isMinimized, value);
113120
}
114121

122+
/// <summary>
123+
/// Shows the commands in the UI.
124+
/// </summary>
125+
public ICommand OnShowCommandsCommand { get; set; }
126+
127+
/// <summary>
128+
/// True if displaying advanced commands, false otherwise.
129+
/// </summary>
130+
public bool IsDisplayingAdvancedCommands {
131+
get => _isDisplayingAdvancedCommands;
132+
set => this.RaiseAndSetIfChanged(ref _isDisplayingAdvancedCommands, value);
133+
}
134+
135+
/// <summary>
136+
/// The username to use for the SSH session for commands.
137+
/// </summary>
138+
public string? SshUsername {
139+
get => _sshUsername;
140+
set => this.RaiseAndSetIfChanged(ref _sshUsername, value);
141+
}
142+
143+
/// <summary>
144+
/// The password to use for the SSH session for commands.
145+
/// </summary>
146+
public string? SshPassword {
147+
get => _sshPassword;
148+
set => this.RaiseAndSetIfChanged(ref _sshPassword, value);
149+
}
150+
151+
/// <summary>
152+
/// Restarts the remote machine.
153+
/// </summary>
154+
public ICommand OnRestartCommand { get; set; }
155+
156+
/// <summary>
157+
/// Restarts the remote machine.
158+
/// </summary>
159+
private async Task OnRestart() {
160+
using SshClient client = new(_serverAddress!, _sshUsername!, _sshPassword!);
161+
await client.ConnectAsync(CancellationToken.None);
162+
string command = "shutdown -r now";
163+
using SshCommand? ssh = client.RunCommand($"echo {_sshPassword} | sudo -S {command}");
164+
}
165+
166+
/// <summary>
167+
/// Handles showing the server commands.
168+
/// </summary>
169+
private void OnShowCommands() {
170+
IsDisplayingAdvancedCommands = true;
171+
}
172+
115173
/// <summary>
116174
/// Pings the web resources.
117175
/// </summary>
@@ -152,7 +210,7 @@ private async Task<bool> SendHeadRequest(string address) {
152210
handler.AutomaticDecompression = ~DecompressionMethods.None;
153211
using var httpClient = new HttpClient(handler);
154212
using var request = new HttpRequestMessage(HttpMethod.Get, address);
155-
request.Headers.TryAddWithoutValidation("user-agent", Constants.FAKE_USER_AGENT);
213+
request.Headers.TryAddWithoutValidation("user-agent", Nullinside.Api.Common.Constants.FAKE_USER_AGENT);
156214
HttpResponseMessage response = await httpClient.SendAsync(request);
157215
return response.IsSuccessStatusCode;
158216
}
@@ -172,7 +230,7 @@ private async Task<bool> SendHeadRequest(string address) {
172230
handler.AutomaticDecompression = ~DecompressionMethods.None;
173231
using var httpClient = new HttpClient(handler);
174232
using var request = new HttpRequestMessage(HttpMethod.Get, address);
175-
request.Headers.TryAddWithoutValidation("user-agent", Constants.FAKE_USER_AGENT);
233+
request.Headers.TryAddWithoutValidation("user-agent", Nullinside.Api.Common.Constants.FAKE_USER_AGENT);
176234
HttpResponseMessage response = await httpClient.SendAsync(request);
177235
return await response.Content.ReadAsStringAsync();
178236
}

src/SiteMonitor/Views/MainWindow.axaml

Lines changed: 82 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
d:DesignWidth="475"
88
d:DesignHeight="300"
99
Width="475"
10-
Height="300"
10+
Height="400"
1111
CanResize="False"
1212
WindowState="{Binding WindowState, Mode=TwoWay}"
1313
ShowInTaskbar="{Binding !IsMinimized, Mode=TwoWay}"
@@ -24,41 +24,88 @@
2424
<viewModels:MainWindowViewModel />
2525
</Design.DataContext>
2626

27-
<Grid Margin="20">
28-
<Grid.RowDefinitions>
29-
<RowDefinition Height="Auto" />
30-
<RowDefinition Height="Auto" />
31-
<RowDefinition />
32-
</Grid.RowDefinitions>
33-
<StackPanel Orientation="Horizontal" Grid.Row="0">
34-
<Label VerticalAlignment="Center">Server Address:</Label>
35-
<TextBox Text="{Binding ServerAddress, Mode=TwoWay}" Width="300" />
36-
</StackPanel>
37-
<StackPanel Orientation="Horizontal" Grid.Row="1" Margin="0, 5, 0, 0">
38-
<Label VerticalAlignment="Center">Last Chat Received:</Label>
39-
<TextBox IsReadOnly="True" Text="{Binding ChatTimestamp}" Width="300" />
40-
</StackPanel>
41-
<UniformGrid Grid.Row="2" Margin="0 25 0 0">
42-
<StackPanel>
43-
<Label FontSize="26" HorizontalAlignment="Center">Server Online</Label>
44-
<Image Source="/Assets/good.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding ServerUp}" />
45-
<Image Source="/Assets/bad.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding !ServerUp}" />
27+
<ScrollViewer>
28+
<Grid Margin="20">
29+
<Grid.RowDefinitions>
30+
<RowDefinition Height="Auto" />
31+
<RowDefinition Height="Auto" />
32+
<RowDefinition Height="Auto" />
33+
<RowDefinition />
34+
</Grid.RowDefinitions>
35+
<StackPanel Orientation="Horizontal" Grid.Row="0">
36+
<Label VerticalAlignment="Center">Server Address:</Label>
37+
<TextBox Text="{Binding ServerAddress, Mode=TwoWay}" Width="300" />
4638
</StackPanel>
47-
<StackPanel>
48-
<Label FontSize="26" HorizontalAlignment="Center">Website</Label>
49-
<Image Source="/Assets/good.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding WebsiteUp}" />
50-
<Image Source="/Assets/bad.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding !WebsiteUp}" />
39+
<StackPanel Orientation="Horizontal" Grid.Row="1" Margin="0, 5, 0, 5">
40+
<Label VerticalAlignment="Center">Last Chat Received:</Label>
41+
<TextBox IsReadOnly="True" Text="{Binding ChatTimestamp}" Width="300" />
5142
</StackPanel>
52-
<StackPanel>
53-
<Label FontSize="26" HorizontalAlignment="Center">Api</Label>
54-
<Image Source="/Assets/good.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding ApiUp}" />
55-
<Image Source="/Assets/bad.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding !ApiUp}" />
56-
</StackPanel>
57-
<StackPanel>
58-
<Label FontSize="26" HorizontalAlignment="Center">Null</Label>
59-
<Image Source="/Assets/good.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding NullUp}" />
60-
<Image Source="/Assets/bad.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding !NullUp}" />
43+
<StackPanel Grid.Row="2">
44+
<Button HorizontalAlignment="Right"
45+
IsVisible="{Binding !IsDisplayingAdvancedCommands}"
46+
Command="{Binding OnShowCommandsCommand}">
47+
Show Advanced Commands
48+
</Button>
49+
<StackPanel IsVisible="{Binding IsDisplayingAdvancedCommands}">
50+
<Grid>
51+
<Grid.RowDefinitions>
52+
<RowDefinition />
53+
<RowDefinition />
54+
</Grid.RowDefinitions>
55+
<Grid.ColumnDefinitions>
56+
<ColumnDefinition Width="Auto" />
57+
<ColumnDefinition Width="*" />
58+
</Grid.ColumnDefinitions>
59+
60+
<Label Grid.Row="0"
61+
Grid.Column="0"
62+
HorizontalAlignment="Right">
63+
Username:
64+
</Label>
65+
<TextBox Grid.Row="0"
66+
Grid.Column="1"
67+
Margin="0 0 0 5"
68+
Text="{Binding SshUsername}" />
69+
<Label Grid.Row="1"
70+
Grid.Column="0"
71+
HorizontalAlignment="Right">
72+
Password:
73+
</Label>
74+
<TextBox Grid.Row="1"
75+
Grid.Column="1"
76+
Margin="0 0 0 5"
77+
PasswordChar="*"
78+
RevealPassword="False"
79+
Text="{Binding SshPassword}" />
80+
</Grid>
81+
<Button HorizontalAlignment="Right"
82+
Command="{Binding OnRestartCommand}">
83+
Restart Computer
84+
</Button>
85+
</StackPanel>
6186
</StackPanel>
62-
</UniformGrid>
63-
</Grid>
87+
<UniformGrid Grid.Row="3" Margin="0 25 0 0">
88+
<StackPanel>
89+
<Label FontSize="26" HorizontalAlignment="Center">Server Online</Label>
90+
<Image Source="/Assets/good.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding ServerUp}" />
91+
<Image Source="/Assets/bad.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding !ServerUp}" />
92+
</StackPanel>
93+
<StackPanel>
94+
<Label FontSize="26" HorizontalAlignment="Center">Website</Label>
95+
<Image Source="/Assets/good.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding WebsiteUp}" />
96+
<Image Source="/Assets/bad.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding !WebsiteUp}" />
97+
</StackPanel>
98+
<StackPanel>
99+
<Label FontSize="26" HorizontalAlignment="Center">Api</Label>
100+
<Image Source="/Assets/good.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding ApiUp}" />
101+
<Image Source="/Assets/bad.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding !ApiUp}" />
102+
</StackPanel>
103+
<StackPanel>
104+
<Label FontSize="26" HorizontalAlignment="Center">Null</Label>
105+
<Image Source="/Assets/good.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding NullUp}" />
106+
<Image Source="/Assets/bad.png" Width="48" Stretch="UniformToFill" IsVisible="{Binding !NullUp}" />
107+
</StackPanel>
108+
</UniformGrid>
109+
</Grid>
110+
</ScrollViewer>
64111
</Window>
Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
using System;
2-
using System.Reflection;
2+
using System.Linq;
33
using System.Threading.Tasks;
44

55
using Avalonia.Controls;
6-
using Avalonia.Threading;
76

87
using Nullinside.Api.Common.Desktop;
8+
#if !DEBUG
9+
using Microsoft.Extensions.DependencyInjection;
10+
11+
using Avalonia.Threading;
912

1013
using SiteMonitor.ViewModels;
14+
#else
15+
using Avalonia;
16+
#endif
17+
1118

1219
namespace SiteMonitor.Views;
1320

@@ -20,41 +27,69 @@ public partial class MainWindow : Window {
2027
/// </summary>
2128
public MainWindow() {
2229
InitializeComponent();
30+
#if DEBUG
31+
this.AttachDevTools();
32+
#endif
2333
}
2434

35+
/// <summary>
36+
/// The service provider for DI.
37+
/// </summary>
38+
public IServiceProvider? ServiceProvider { get; set; }
39+
2540
/// <summary>
2641
/// Checks for a new version number of the application.
2742
/// </summary>
2843
protected override void OnInitialized() {
2944
base.OnInitialized();
3045

46+
// handle the command line arguments for updating the application if applicable.
47+
string[] args = Environment.GetCommandLineArgs();
48+
if (args.Contains("--update")) {
49+
_ = GitHubUpdateManager.PerformUpdateAndRestart("nullinside-development-group", "twitch-streaming-tools", args[2], "windows-x64.zip");
50+
return;
51+
}
52+
53+
if (args.Contains("--justUpdated")) {
54+
_ = GitHubUpdateManager.CleanupUpdate();
55+
}
56+
57+
// check for a new version of the application.
3158
Task.Factory.StartNew(async () => {
3259
GithubLatestReleaseJson? serverVersion =
3360
await GitHubUpdateManager.GetLatestVersion("nullinside-development-group", "nullinside-site-monitor");
34-
string? localVersion = Assembly.GetEntryAssembly()?.GetName().Version?.ToString();
35-
if (null == serverVersion || string.IsNullOrWhiteSpace(serverVersion.name) ||
36-
string.IsNullOrWhiteSpace(localVersion)) {
61+
if (null == serverVersion || string.IsNullOrWhiteSpace(serverVersion.name)) {
3762
return;
3863
}
3964

40-
localVersion = localVersion.Substring(0, localVersion.LastIndexOf('.'));
41-
if (string.IsNullOrWhiteSpace(localVersion)) {
65+
if (serverVersion.name?.Equals(Constants.APP_VERSION, StringComparison.InvariantCultureIgnoreCase) ?? true) {
66+
// Had to add this because code clean up tools were removing the "redundant" return statement.
67+
// which was causing the check to always be ignored.
68+
#if !DEBUG
4269
return;
70+
#endif
4371
}
4472

45-
if (serverVersion.name?.Equals(localVersion, StringComparison.InvariantCultureIgnoreCase) ?? true) {
73+
#if !DEBUG
74+
var vm = ServiceProvider?.GetRequiredService<NewVersionWindowViewModel>();
75+
if (null == vm) {
4676
return;
4777
}
4878

49-
Dispatcher.UIThread.Post(async () => {
50-
var versionWindow = new NewVersionWindow {
51-
DataContext = new NewVersionWindowViewModel {
52-
LocalVersion = localVersion
53-
}
54-
};
79+
vm.LocalVersion = Constants.APP_VERSION;
80+
Dispatcher.UIThread.Post(async void () => {
81+
try {
82+
var versionWindow = new NewVersionWindow {
83+
DataContext = vm
84+
};
5585

56-
await versionWindow.ShowDialog(this);
86+
await versionWindow.ShowDialog(this);
87+
}
88+
catch {
89+
// do nothing, don't crash
90+
}
5791
});
92+
#endif
5893
});
5994
}
6095
}

0 commit comments

Comments
 (0)