Skip to content

Commit fb46593

Browse files
committed
change to enums
1 parent cd966be commit fb46593

File tree

10 files changed

+207
-43
lines changed

10 files changed

+207
-43
lines changed

App/Models/RpcModel.cs

Lines changed: 131 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
using System;
12
using System.Collections.Generic;
3+
using System.Diagnostics;
4+
using Coder.Desktop.App.Converters;
25
using Coder.Desktop.Vpn.Proto;
36

47
namespace Coder.Desktop.App.Models;
@@ -19,17 +22,141 @@ public enum VpnLifecycle
1922
Stopping,
2023
}
2124

25+
public enum VpnStartupStage
26+
{
27+
Unknown,
28+
Initializing,
29+
Downloading,
30+
Finalizing,
31+
}
32+
33+
public class VpnDownloadProgress
34+
{
35+
public ulong BytesWritten { get; set; } = 0;
36+
public ulong? BytesTotal { get; set; } = null; // null means unknown total size
37+
38+
public double Progress
39+
{
40+
get
41+
{
42+
if (BytesTotal is > 0)
43+
{
44+
return (double)BytesWritten / BytesTotal.Value;
45+
}
46+
return 0.0;
47+
}
48+
}
49+
50+
public override string ToString()
51+
{
52+
// TODO: it would be nice if the two suffixes could match
53+
var s = FriendlyByteConverter.FriendlyBytes(BytesWritten);
54+
if (BytesTotal != null)
55+
s += $" of {FriendlyByteConverter.FriendlyBytes(BytesTotal.Value)}";
56+
else
57+
s += " of unknown";
58+
if (BytesTotal != null)
59+
s += $" ({Progress:0%})";
60+
return s;
61+
}
62+
63+
public VpnDownloadProgress Clone()
64+
{
65+
return new VpnDownloadProgress
66+
{
67+
BytesWritten = BytesWritten,
68+
BytesTotal = BytesTotal,
69+
};
70+
}
71+
72+
public static VpnDownloadProgress FromProto(StartProgressDownloadProgress proto)
73+
{
74+
return new VpnDownloadProgress
75+
{
76+
BytesWritten = proto.BytesWritten,
77+
BytesTotal = proto.HasBytesTotal ? proto.BytesTotal : null,
78+
};
79+
}
80+
}
81+
2282
public class VpnStartupProgress
2383
{
24-
public double Progress { get; set; } = 0.0; // 0.0 to 1.0
25-
public string Message { get; set; } = string.Empty;
84+
public const string DefaultStartProgressMessage = "Starting Coder Connect...";
85+
86+
// Scale the download progress to an overall progress value between these
87+
// numbers.
88+
private const double DownloadProgressMin = 0.05;
89+
private const double DownloadProgressMax = 0.80;
90+
91+
public VpnStartupStage Stage { get; set; } = VpnStartupStage.Unknown;
92+
public VpnDownloadProgress? DownloadProgress { get; set; } = null;
93+
94+
// 0.0 to 1.0
95+
public double Progress
96+
{
97+
get
98+
{
99+
switch (Stage)
100+
{
101+
case VpnStartupStage.Unknown:
102+
case VpnStartupStage.Initializing:
103+
return 0.0;
104+
case VpnStartupStage.Downloading:
105+
var progress = DownloadProgress?.Progress ?? 0.0;
106+
return DownloadProgressMin + (DownloadProgressMax - DownloadProgressMin) * progress;
107+
case VpnStartupStage.Finalizing:
108+
return DownloadProgressMax;
109+
default:
110+
throw new ArgumentOutOfRangeException();
111+
}
112+
}
113+
}
114+
115+
public override string ToString()
116+
{
117+
switch (Stage)
118+
{
119+
case VpnStartupStage.Unknown:
120+
case VpnStartupStage.Initializing:
121+
return DefaultStartProgressMessage;
122+
case VpnStartupStage.Downloading:
123+
var s = "Downloading Coder Connect binary...";
124+
if (DownloadProgress is not null)
125+
{
126+
s += "\n" + DownloadProgress;
127+
}
128+
129+
return s;
130+
case VpnStartupStage.Finalizing:
131+
return "Finalizing Coder Connect startup...";
132+
default:
133+
throw new ArgumentOutOfRangeException();
134+
}
135+
}
26136

27137
public VpnStartupProgress Clone()
28138
{
29139
return new VpnStartupProgress
30140
{
31-
Progress = Progress,
32-
Message = Message,
141+
Stage = Stage,
142+
DownloadProgress = DownloadProgress?.Clone(),
143+
};
144+
}
145+
146+
public static VpnStartupProgress FromProto(StartProgress proto)
147+
{
148+
return new VpnStartupProgress
149+
{
150+
Stage = proto.Stage switch
151+
{
152+
StartProgressStage.Initializing => VpnStartupStage.Initializing,
153+
StartProgressStage.Downloading => VpnStartupStage.Downloading,
154+
StartProgressStage.Finalizing => VpnStartupStage.Finalizing,
155+
_ => VpnStartupStage.Unknown,
156+
},
157+
DownloadProgress = proto.Stage is StartProgressStage.Downloading ?
158+
VpnDownloadProgress.FromProto(proto.DownloadProgress) :
159+
null,
33160
};
34161
}
35162
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
https://go.microsoft.com/fwlink/?LinkID=208121.
4+
-->
5+
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
6+
<PropertyGroup>
7+
<PublishProtocol>FileSystem</PublishProtocol>
8+
<Platform>ARM64</Platform>
9+
<RuntimeIdentifier>win-arm64</RuntimeIdentifier>
10+
<PublishDir>bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\</PublishDir>
11+
</PropertyGroup>
12+
</Project>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
https://go.microsoft.com/fwlink/?LinkID=208121.
4+
-->
5+
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
6+
<PropertyGroup>
7+
<PublishProtocol>FileSystem</PublishProtocol>
8+
<Platform>x64</Platform>
9+
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
10+
<PublishDir>bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\</PublishDir>
11+
</PropertyGroup>
12+
</Project>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
https://go.microsoft.com/fwlink/?LinkID=208121.
4+
-->
5+
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
6+
<PropertyGroup>
7+
<PublishProtocol>FileSystem</PublishProtocol>
8+
<Platform>x86</Platform>
9+
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
10+
<PublishDir>bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\</PublishDir>
11+
</PropertyGroup>
12+
</Project>

App/Services/RpcController.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,7 @@ public async Task StartVpn(CancellationToken ct = default)
164164
MutateState(state =>
165165
{
166166
state.VpnLifecycle = VpnLifecycle.Starting;
167-
// Explicitly clear the startup progress.
168-
state.VpnStartupProgress = null;
167+
state.VpnStartupProgress = new VpnStartupProgress();
169168
});
170169

171170
ServiceMessage reply;
@@ -297,11 +296,7 @@ private void ApplyStartProgressUpdate(StartProgress message)
297296
{
298297
// MutateState will undo these changes if it doesn't believe we're
299298
// in the "Starting" state.
300-
state.VpnStartupProgress = new VpnStartupProgress
301-
{
302-
Progress = message.Progress,
303-
Message = message.Message,
304-
};
299+
state.VpnStartupProgress = VpnStartupProgress.FromProto(message);
305300
});
306301
}
307302

App/ViewModels/TrayWindowViewModel.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ public partial class TrayWindowViewModel : ObservableObject, IAgentExpanderHost
2929
{
3030
private const int MaxAgents = 5;
3131
private const string DefaultDashboardUrl = "https://coder.com";
32-
private const string DefaultStartProgressMessage = "Starting Coder Connect...";
3332

3433
private readonly IServiceProvider _services;
3534
private readonly IRpcController _rpcController;
@@ -84,7 +83,7 @@ public partial class TrayWindowViewModel : ObservableObject, IAgentExpanderHost
8483
public partial string? VpnStartProgressMessage { get; set; } = null;
8584

8685
public string VpnStartProgressMessageOrDefault =>
87-
string.IsNullOrEmpty(VpnStartProgressMessage) ? DefaultStartProgressMessage : VpnStartProgressMessage;
86+
string.IsNullOrEmpty(VpnStartProgressMessage) ? VpnStartupProgress.DefaultStartProgressMessage : VpnStartProgressMessage;
8887

8988
public bool VpnStartProgressIsIndeterminate => VpnStartProgressValueOrDefault == 0;
9089

@@ -196,7 +195,7 @@ private void UpdateFromRpcModel(RpcModel rpcModel)
196195
// Convert 0.00-1.00 to 0-100.
197196
var progress = (int)(rpcModel.VpnStartupProgress.Progress * 100);
198197
VpnStartProgressValue = Math.Clamp(progress, 0, 100);
199-
VpnStartProgressMessage = string.IsNullOrEmpty(rpcModel.VpnStartupProgress.Message) ? null : rpcModel.VpnStartupProgress.Message;
198+
VpnStartProgressMessage = rpcModel.VpnStartupProgress.ToString();
200199
}
201200
else
202201
{

Tests.Vpn.Service/DownloaderTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -344,11 +344,11 @@ public async Task DownloadWithXOriginalContentLength(CancellationToken ct)
344344
Assert.That(list.Count, Is.GreaterThanOrEqualTo(2)); // there may be an item in the middle
345345
// The first item should be the initial progress with 0 bytes written.
346346
Assert.That(list[0].BytesWritten, Is.EqualTo(0));
347-
Assert.That(list[0].TotalBytes, Is.EqualTo(6)); // from X-Original-Content-Length
347+
Assert.That(list[0].BytesTotal, Is.EqualTo(6)); // from X-Original-Content-Length
348348
Assert.That(list[0].Progress, Is.EqualTo(0.0d));
349349
// The last item should be final progress with the actual total bytes.
350350
Assert.That(list[^1].BytesWritten, Is.EqualTo(4));
351-
Assert.That(list[^1].TotalBytes, Is.EqualTo(4)); // from the actual bytes written
351+
Assert.That(list[^1].BytesTotal, Is.EqualTo(4)); // from the actual bytes written
352352
Assert.That(list[^1].Progress, Is.EqualTo(1.0d));
353353
}
354354

Vpn.Proto/vpn.proto

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,9 +227,18 @@ message StartResponse {
227227
// inability to easily send messages to a specific client in the Speaker
228228
// implementation. If clients are not expecting these messages, they
229229
// should ignore them.
230+
enum StartProgressStage {
231+
Initializing = 0;
232+
Downloading = 1;
233+
Finalizing = 2;
234+
}
235+
message StartProgressDownloadProgress {
236+
uint64 bytes_written = 1;
237+
optional uint64 bytes_total = 2; // unknown in some situations
238+
}
230239
message StartProgress {
231-
double progress = 1; // 0.0 to 1.0
232-
string message = 2; // human-readable status message, must be set
240+
StartProgressStage stage = 1;
241+
optional StartProgressDownloadProgress download_progress = 2; // only set when stage == Downloading
233242
}
234243

235244
// StopRequest is a request from the manager to stop the tunnel. The tunnel replies with a

Vpn.Service/Downloader.cs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -342,14 +342,15 @@ public class DownloadProgressEvent
342342
{
343343
// TODO: speed calculation would be nice
344344
public ulong BytesWritten { get; init; }
345-
public ulong? TotalBytes { get; init; } // null if unknown
346-
public double? Progress { get; init; } // 0.0 - 1.0, null if unknown
345+
public ulong? BytesTotal { get; init; } // null if unknown
346+
347+
public double? Progress => BytesTotal == null ? null : (double)BytesWritten / BytesTotal.Value;
347348

348349
public override string ToString()
349350
{
350351
var s = FriendlyBytes(BytesWritten);
351-
if (TotalBytes != null)
352-
s += $" of {FriendlyBytes(TotalBytes.Value)}";
352+
if (BytesTotal != null)
353+
s += $" of {FriendlyBytes(BytesTotal.Value)}";
353354
else
354355
s += " of unknown";
355356
if (Progress != null)
@@ -513,8 +514,7 @@ private async Task Start(CancellationToken ct = default)
513514
SendProgressUpdate(new DownloadProgressEvent
514515
{
515516
BytesWritten = 0,
516-
TotalBytes = TotalBytes,
517-
Progress = 0.0,
517+
BytesTotal = TotalBytes,
518518
});
519519

520520
await Download(res, ct);
@@ -549,8 +549,7 @@ private async Task Download(HttpResponseMessage res, CancellationToken ct)
549549
await QueueProgressUpdate(new DownloadProgressEvent
550550
{
551551
BytesWritten = BytesWritten,
552-
TotalBytes = TotalBytes,
553-
Progress = Progress,
552+
BytesTotal = TotalBytes,
554553
}, ct);
555554
}
556555
}
@@ -563,8 +562,7 @@ await QueueProgressUpdate(new DownloadProgressEvent
563562
SendProgressUpdate(new DownloadProgressEvent
564563
{
565564
BytesWritten = BytesWritten,
566-
TotalBytes = BytesWritten,
567-
Progress = 1.0,
565+
BytesTotal = BytesWritten,
568566
});
569567

570568
if (TotalBytes != null && BytesWritten != TotalBytes)

Vpn.Service/Manager.cs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,6 @@ public interface IManager : IDisposable
2626
/// </summary>
2727
public class Manager : IManager
2828
{
29-
// We scale the download progress to 0.00-0.90, and use 0.90-1.00 for the
30-
// remainder of startup.
31-
private const double DownloadProgressScale = 0.90;
32-
3329
private readonly ManagerConfig _config;
3430
private readonly IDownloader _downloader;
3531
private readonly ILogger<Manager> _logger;
@@ -135,7 +131,7 @@ private async ValueTask<StartResponse> HandleClientMessageStart(ClientMessage me
135131
{
136132
try
137133
{
138-
await BroadcastStartProgress(0.0, "Starting Coder Connect...", ct);
134+
await BroadcastStartProgress(StartProgressStage.Initializing, cancellationToken: ct);
139135

140136
var serverVersion =
141137
await CheckServerVersionAndCredentials(message.Start.CoderUrl, message.Start.ApiToken, ct);
@@ -164,7 +160,7 @@ private async ValueTask<StartResponse> HandleClientMessageStart(ClientMessage me
164160

165161
await DownloadTunnelBinaryAsync(message.Start.CoderUrl, serverVersion.SemVersion, ct);
166162

167-
await BroadcastStartProgress(DownloadProgressScale, "Starting Coder Connect...", ct);
163+
await BroadcastStartProgress(StartProgressStage.Finalizing, cancellationToken: ct);
168164
await _tunnelSupervisor.StartAsync(_config.TunnelBinaryPath, HandleTunnelRpcMessage,
169165
HandleTunnelRpcError,
170166
ct);
@@ -464,10 +460,14 @@ private async Task DownloadTunnelBinaryAsync(string baseUrl, SemVersion expected
464460
if (progressBroadcastCts.IsCancellationRequested) return;
465461
_logger.LogInformation("Download progress: {ev}", ev);
466462

467-
// Scale the progress value to be between 0.00 and 0.90.
468-
var progress = ev.Progress * DownloadProgressScale ?? 0.0;
469-
var message = $"Downloading Coder Connect binary...\n{ev}";
470-
BroadcastStartProgress(progress, message, progressBroadcastCts.Token).Wait(progressBroadcastCts.Token);
463+
var progress = new StartProgressDownloadProgress
464+
{
465+
BytesWritten = ev.BytesWritten,
466+
};
467+
if (ev.BytesTotal != null)
468+
progress.BytesTotal = ev.BytesTotal.Value;
469+
BroadcastStartProgress(StartProgressStage.Downloading, progress, progressBroadcastCts.Token)
470+
.Wait(progressBroadcastCts.Token);
471471
};
472472

473473
// Awaiting this will check the checksum (via the ETag) if the file
@@ -484,16 +484,16 @@ private async Task DownloadTunnelBinaryAsync(string baseUrl, SemVersion expected
484484
_logger.LogInformation("Completed downloading VPN binary");
485485
}
486486

487-
private async Task BroadcastStartProgress(double progress, string message, CancellationToken ct = default)
487+
private async Task BroadcastStartProgress(StartProgressStage stage, StartProgressDownloadProgress? downloadProgress = null, CancellationToken cancellationToken = default)
488488
{
489-
_logger.LogInformation("Start progress: {Progress:0%} - {Message}", progress, message);
489+
_logger.LogInformation("Start progress: {stage}", stage);
490490
await FallibleBroadcast(new ServiceMessage
491491
{
492492
StartProgress = new StartProgress
493493
{
494-
Progress = progress,
495-
Message = message,
494+
Stage = stage,
495+
DownloadProgress = downloadProgress,
496496
},
497-
}, ct);
497+
}, cancellationToken);
498498
}
499499
}

0 commit comments

Comments
 (0)