Skip to content

Commit f0cca56

Browse files
committed
Merge branch 'main' into dean/login-check-buildinfo
2 parents 709eff9 + be51a7b commit f0cca56

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+2869
-209
lines changed

.gitattributes

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
MutagenSdk/Proto/**/*.proto linguist-generated=true

.github/workflows/release.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ jobs:
6262
id: gcloud_auth
6363
uses: google-github-actions/auth@71f986410dfbc7added4569d411d040a91dc6935 # v2.1.8
6464
with:
65-
workload_identity_provider: ${{ secrets.GCP_CODE_SIGNING_WORKLOAD_ID_PROVIDER }}
66-
service_account: ${{ secrets.GCP_CODE_SIGNING_SERVICE_ACCOUNT }}
65+
workload_identity_provider: ${{ secrets.GCP_WORKLOAD_ID_PROVIDER }}
66+
service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }}
6767
token_format: "access_token"
6868

6969
- name: Install wix

App/App.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
</PropertyGroup>
3131

3232
<ItemGroup>
33-
<Content Include="coder.ico" />
33+
<Content Include="coder.ico" />
3434
</ItemGroup>
3535

3636
<ItemGroup>

App/Converters/AgentStatusToColorConverter.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace Coder.Desktop.App.Converters;
99
public class AgentStatusToColorConverter : IValueConverter
1010
{
1111
private static readonly SolidColorBrush Green = new(Color.FromArgb(255, 52, 199, 89));
12-
private static readonly SolidColorBrush Yellow = new(Color.FromArgb(255, 204, 1, 0));
12+
private static readonly SolidColorBrush Yellow = new(Color.FromArgb(255, 255, 204, 1));
1313
private static readonly SolidColorBrush Red = new(Color.FromArgb(255, 255, 59, 48));
1414
private static readonly SolidColorBrush Gray = new(Color.FromArgb(255, 142, 142, 147));
1515

App/Converters/InverseBoolToVisibilityConverter.cs

-12
This file was deleted.

App/Converters/VpnLifecycleToVisibilityConverter.cs

-14
This file was deleted.

App/Services/RpcController.cs

+22-11
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,8 @@ public async Task Reconnect(CancellationToken ct = default)
146146
Status = new StatusRequest(),
147147
}, ct);
148148
if (statusReply.MsgCase != ServiceMessage.MsgOneofCase.Status)
149-
throw new InvalidOperationException($"Unexpected reply message type: {statusReply.MsgCase}");
149+
throw new VpnLifecycleException(
150+
$"Failed to get VPN status. Unexpected reply message type: {statusReply.MsgCase}");
150151
ApplyStatusUpdate(statusReply.Status);
151152
}
152153

@@ -173,20 +174,26 @@ public async Task StartVpn(CancellationToken ct = default)
173174
ApiToken = credentials.ApiToken,
174175
},
175176
}, ct);
176-
if (reply.MsgCase != ServiceMessage.MsgOneofCase.Start)
177-
throw new InvalidOperationException($"Unexpected reply message type: {reply.MsgCase}");
178177
}
179178
catch (Exception e)
180179
{
181180
MutateState(state => { state.VpnLifecycle = VpnLifecycle.Stopped; });
182181
throw new RpcOperationException("Failed to send start command to service", e);
183182
}
184183

184+
if (reply.MsgCase != ServiceMessage.MsgOneofCase.Start)
185+
{
186+
MutateState(state => { state.VpnLifecycle = VpnLifecycle.Unknown; });
187+
throw new VpnLifecycleException($"Failed to start VPN. Unexpected reply message type: {reply.MsgCase}");
188+
}
189+
185190
if (!reply.Start.Success)
186191
{
192+
// We use Stopped instead of Unknown here as it's usually the case
193+
// that a failed start got cleaned up successfully.
187194
MutateState(state => { state.VpnLifecycle = VpnLifecycle.Stopped; });
188-
throw new VpnLifecycleException("Failed to start VPN",
189-
new InvalidOperationException($"Service reported failure: {reply.Start.ErrorMessage}"));
195+
throw new VpnLifecycleException(
196+
$"Failed to start VPN. Service reported failure: {reply.Start.ErrorMessage}");
190197
}
191198

192199
MutateState(state => { state.VpnLifecycle = VpnLifecycle.Started; });
@@ -213,16 +220,20 @@ public async Task StopVpn(CancellationToken ct = default)
213220
}
214221
finally
215222
{
216-
// Technically the state is unknown now.
217-
MutateState(state => { state.VpnLifecycle = VpnLifecycle.Stopped; });
223+
MutateState(state => { state.VpnLifecycle = VpnLifecycle.Unknown; });
218224
}
219225

220226
if (reply.MsgCase != ServiceMessage.MsgOneofCase.Stop)
221-
throw new VpnLifecycleException("Failed to stop VPN",
222-
new InvalidOperationException($"Unexpected reply message type: {reply.MsgCase}"));
227+
{
228+
MutateState(state => { state.VpnLifecycle = VpnLifecycle.Unknown; });
229+
throw new VpnLifecycleException($"Failed to stop VPN. Unexpected reply message type: {reply.MsgCase}");
230+
}
231+
223232
if (!reply.Stop.Success)
224-
throw new VpnLifecycleException("Failed to stop VPN",
225-
new InvalidOperationException($"Service reported failure: {reply.Stop.ErrorMessage}"));
233+
{
234+
MutateState(state => { state.VpnLifecycle = VpnLifecycle.Unknown; });
235+
throw new VpnLifecycleException($"Failed to stop VPN. Service reported failure: {reply.Stop.ErrorMessage}");
236+
}
226237
}
227238

228239
public async ValueTask DisposeAsync()

App/ViewModels/TrayWindowViewModel.cs

+65-17
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq;
4+
using System.Threading.Tasks;
45
using Coder.Desktop.App.Models;
56
using Coder.Desktop.App.Services;
67
using Coder.Desktop.Vpn.Proto;
@@ -10,6 +11,7 @@
1011
using Microsoft.UI.Dispatching;
1112
using Microsoft.UI.Xaml;
1213
using Microsoft.UI.Xaml.Controls;
14+
using Exception = System.Exception;
1315

1416
namespace Coder.Desktop.App.ViewModels;
1517

@@ -23,22 +25,45 @@ public partial class TrayWindowViewModel : ObservableObject
2325

2426
private DispatcherQueue? _dispatcherQueue;
2527

26-
[ObservableProperty] public partial VpnLifecycle VpnLifecycle { get; set; } = VpnLifecycle.Unknown;
28+
[ObservableProperty]
29+
[NotifyPropertyChangedFor(nameof(ShowEnableSection))]
30+
[NotifyPropertyChangedFor(nameof(ShowWorkspacesHeader))]
31+
[NotifyPropertyChangedFor(nameof(ShowNoAgentsSection))]
32+
[NotifyPropertyChangedFor(nameof(ShowAgentsSection))]
33+
public partial VpnLifecycle VpnLifecycle { get; set; } = VpnLifecycle.Unknown;
2734

2835
// This is a separate property because we need the switch to be 2-way.
2936
[ObservableProperty] public partial bool VpnSwitchActive { get; set; } = false;
3037

31-
[ObservableProperty] public partial string? VpnFailedMessage { get; set; } = null;
38+
[ObservableProperty]
39+
[NotifyPropertyChangedFor(nameof(ShowEnableSection))]
40+
[NotifyPropertyChangedFor(nameof(ShowWorkspacesHeader))]
41+
[NotifyPropertyChangedFor(nameof(ShowNoAgentsSection))]
42+
[NotifyPropertyChangedFor(nameof(ShowAgentsSection))]
43+
[NotifyPropertyChangedFor(nameof(ShowAgentOverflowButton))]
44+
[NotifyPropertyChangedFor(nameof(ShowFailedSection))]
45+
public partial string? VpnFailedMessage { get; set; } = null;
3246

3347
[ObservableProperty]
34-
[NotifyPropertyChangedFor(nameof(NoAgents))]
35-
[NotifyPropertyChangedFor(nameof(AgentOverflow))]
3648
[NotifyPropertyChangedFor(nameof(VisibleAgents))]
49+
[NotifyPropertyChangedFor(nameof(ShowNoAgentsSection))]
50+
[NotifyPropertyChangedFor(nameof(ShowAgentsSection))]
51+
[NotifyPropertyChangedFor(nameof(ShowAgentOverflowButton))]
3752
public partial List<AgentViewModel> Agents { get; set; } = [];
3853

39-
public bool NoAgents => Agents.Count == 0;
54+
public bool ShowEnableSection => VpnFailedMessage is null && VpnLifecycle is not VpnLifecycle.Started;
55+
56+
public bool ShowWorkspacesHeader => VpnFailedMessage is null && VpnLifecycle is VpnLifecycle.Started;
57+
58+
public bool ShowNoAgentsSection =>
59+
VpnFailedMessage is null && Agents.Count == 0 && VpnLifecycle is VpnLifecycle.Started;
60+
61+
public bool ShowAgentsSection =>
62+
VpnFailedMessage is null && Agents.Count > 0 && VpnLifecycle is VpnLifecycle.Started;
63+
64+
public bool ShowFailedSection => VpnFailedMessage is not null;
4065

41-
public bool AgentOverflow => Agents.Count > MaxAgents;
66+
public bool ShowAgentOverflowButton => VpnFailedMessage is null && Agents.Count > MaxAgents;
4267

4368
[ObservableProperty]
4469
[NotifyPropertyChangedFor(nameof(VisibleAgents))]
@@ -190,24 +215,47 @@ public void VpnSwitch_Toggled(object sender, RoutedEventArgs e)
190215
{
191216
if (sender is not ToggleSwitch toggleSwitch) return;
192217

193-
VpnFailedMessage = "";
218+
VpnFailedMessage = null;
219+
220+
// The start/stop methods will call back to update the state.
221+
if (toggleSwitch.IsOn && VpnLifecycle is VpnLifecycle.Stopped)
222+
_ = StartVpn(); // in the background
223+
else if (!toggleSwitch.IsOn && VpnLifecycle is VpnLifecycle.Started)
224+
_ = StopVpn(); // in the background
225+
else
226+
toggleSwitch.IsOn = VpnLifecycle is VpnLifecycle.Starting or VpnLifecycle.Started;
227+
}
228+
229+
private async Task StartVpn()
230+
{
194231
try
195232
{
196-
// The start/stop methods will call back to update the state.
197-
if (toggleSwitch.IsOn && VpnLifecycle is VpnLifecycle.Stopped)
198-
_rpcController.StartVpn();
199-
else if (!toggleSwitch.IsOn && VpnLifecycle is VpnLifecycle.Started)
200-
_rpcController.StopVpn();
201-
else
202-
toggleSwitch.IsOn = VpnLifecycle is VpnLifecycle.Starting or VpnLifecycle.Started;
233+
await _rpcController.StartVpn();
203234
}
204-
catch
235+
catch (Exception e)
205236
{
206-
// TODO: display error
207-
VpnFailedMessage = e.ToString();
237+
VpnFailedMessage = "Failed to start CoderVPN: " + MaybeUnwrapTunnelError(e);
208238
}
209239
}
210240

241+
private async Task StopVpn()
242+
{
243+
try
244+
{
245+
await _rpcController.StopVpn();
246+
}
247+
catch (Exception e)
248+
{
249+
VpnFailedMessage = "Failed to stop CoderVPN: " + MaybeUnwrapTunnelError(e);
250+
}
251+
}
252+
253+
private static string MaybeUnwrapTunnelError(Exception e)
254+
{
255+
if (e is VpnLifecycleException vpnError) return vpnError.Message;
256+
return e.ToString();
257+
}
258+
211259
[RelayCommand]
212260
public void ToggleShowAllAgents()
213261
{

0 commit comments

Comments
 (0)