Skip to content

Commit 5c94a2a

Browse files
feat: adding button to restart machine
1 parent eb84ec8 commit 5c94a2a

File tree

4 files changed

+212
-60
lines changed

4 files changed

+212
-60
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: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
1+
#if !DEBUG
2+
using Microsoft.Extensions.DependencyInjection;
3+
4+
using Avalonia.Threading;
5+
6+
using TwitchStreamingTools.ViewModels;
7+
#else
8+
using Avalonia;
9+
#endif
110
using System;
2-
using System.Reflection;
11+
using System.Linq;
312
using System.Threading.Tasks;
413

514
using Avalonia.Controls;
6-
using Avalonia.Threading;
715

816
using Nullinside.Api.Common.Desktop;
917

10-
using SiteMonitor.ViewModels;
11-
1218
namespace SiteMonitor.Views;
1319

1420
/// <summary>
@@ -20,41 +26,69 @@ public partial class MainWindow : Window {
2026
/// </summary>
2127
public MainWindow() {
2228
InitializeComponent();
29+
#if DEBUG
30+
this.AttachDevTools();
31+
#endif
2332
}
2433

34+
/// <summary>
35+
/// The service provider for DI.
36+
/// </summary>
37+
public IServiceProvider? ServiceProvider { get; set; }
38+
2539
/// <summary>
2640
/// Checks for a new version number of the application.
2741
/// </summary>
2842
protected override void OnInitialized() {
2943
base.OnInitialized();
3044

45+
// handle the command line arguments for updating the application if applicable.
46+
string[] args = Environment.GetCommandLineArgs();
47+
if (args.Contains("--update")) {
48+
_ = GitHubUpdateManager.PerformUpdateAndRestart("nullinside-development-group", "twitch-streaming-tools", args[2], "windows-x64.zip");
49+
return;
50+
}
51+
52+
if (args.Contains("--justUpdated")) {
53+
_ = GitHubUpdateManager.CleanupUpdate();
54+
}
55+
56+
// check for a new version of the application.
3157
Task.Factory.StartNew(async () => {
3258
GithubLatestReleaseJson? serverVersion =
3359
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)) {
60+
if (null == serverVersion || string.IsNullOrWhiteSpace(serverVersion.name)) {
3761
return;
3862
}
3963

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

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

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

56-
await versionWindow.ShowDialog(this);
85+
await versionWindow.ShowDialog(this);
86+
}
87+
catch {
88+
// do nothing, don't crash
89+
}
5790
});
91+
#endif
5892
});
5993
}
6094
}

0 commit comments

Comments
 (0)