Skip to content

Commit 41cf916

Browse files
committed
config defaulting, also include VPN service
1 parent 37ee7e4 commit 41cf916

File tree

7 files changed

+129
-77
lines changed

7 files changed

+129
-77
lines changed

App/App.xaml.cs

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System;
22
using System.Diagnostics;
33
using System.IO;
4-
using System.Linq;
54
using System.Threading;
65
using System.Threading.Tasks;
76
using Coder.Desktop.App.Models;
@@ -19,6 +18,7 @@
1918
using Windows.ApplicationModel.Activation;
2019
using Microsoft.Extensions.Logging;
2120
using Serilog;
21+
using System.Collections.Generic;
2222

2323
namespace Coder.Desktop.App;
2424

@@ -29,9 +29,6 @@ public partial class App : Application
2929
private bool _handleWindowClosed = true;
3030
private const string MutagenControllerConfigSection = "MutagenController";
3131

32-
private const string logTemplate =
33-
"{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {SourceContext} - {Message:lj}{NewLine}{Exception}";
34-
3532
#if !DEBUG
3633
private const string ConfigSubKey = @"SOFTWARE\Coder Desktop\App";
3734
private const string logFilename = "app.log";
@@ -45,31 +42,22 @@ public partial class App : Application
4542
public App()
4643
{
4744
var builder = Host.CreateApplicationBuilder();
45+
var configBuilder = builder.Configuration as IConfigurationBuilder;
4846

49-
(builder.Configuration as IConfigurationBuilder).Add(
47+
// Add config in increasing order of precedence: first builtin defaults, then HKLM, finally HKCU
48+
// so that the user's settings in the registry take precedence.
49+
AddDefaultConfig(configBuilder);
50+
configBuilder.Add(
5051
new RegistryConfigurationSource(Registry.LocalMachine, ConfigSubKey));
52+
configBuilder.Add(
53+
new RegistryConfigurationSource(Registry.CurrentUser, ConfigSubKey));
5154

5255
var services = builder.Services;
5356

5457
// Logging
5558
builder.Services.AddSerilog((_, loggerConfig) =>
5659
{
5760
loggerConfig.ReadFrom.Configuration(builder.Configuration);
58-
var sinkConfig = builder.Configuration.GetSection("Serilog").GetSection("WriteTo");
59-
if (!sinkConfig.GetChildren().Any())
60-
{
61-
// no log sink defined in the registry, so we'll add one here.
62-
// We can't generally define these in the registry because we don't
63-
// know, a priori, what user will execute Coder Desktop, and therefore
64-
// what directories are writable by them. But, it's nice to be able to
65-
// directly customize Serilog via the registry if you know what you are
66-
// doing.
67-
var logPath = Path.Combine(
68-
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
69-
"CoderDesktop",
70-
logFilename);
71-
loggerConfig.WriteTo.File(logPath, outputTemplate: logTemplate, rollingInterval: RollingInterval.Day);
72-
}
7361
});
7462

7563
services.AddSingleton<ICredentialManager, CredentialManager>();
@@ -108,6 +96,7 @@ public App()
10896

10997
public async Task ExitApplication()
11098
{
99+
_logger.LogDebug("exiting app");
111100
_handleWindowClosed = false;
112101
Exit();
113102
var syncController = _services.GetRequiredService<ISyncSessionController>();
@@ -169,6 +158,7 @@ protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs ar
169158
Debugger.Break();
170159
#endif
171160
}
161+
172162
syncSessionCts.Dispose();
173163
}, CancellationToken.None);
174164

@@ -208,4 +198,24 @@ public void HandleURIActivation(Uri uri)
208198
// don't log the query string as that's where we include some sensitive information like passwords
209199
_logger.LogInformation("handling URI activation for {path}", uri.AbsolutePath);
210200
}
201+
202+
private static void AddDefaultConfig(IConfigurationBuilder builder)
203+
{
204+
var logPath = Path.Combine(
205+
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
206+
"CoderDesktop",
207+
logFilename);
208+
builder.AddInMemoryCollection(new Dictionary<string, string?>
209+
{
210+
[MutagenControllerConfigSection + ":MutagenExecutablePath"] = @"C:\mutagen.exe",
211+
["Serilog:Using:0"] = "Serilog.Sinks.File",
212+
["Serilog:MinimumLevel"] = "Information",
213+
["Serilog:Enrich:0"] = "FromLogContext",
214+
["Serilog:WriteTo:0:Name"] = "File",
215+
["Serilog:WriteTo:0:Args:path"] = logPath,
216+
["Serilog:WriteTo:0:Args:outputTemplate"] =
217+
"{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {SourceContext} - {Message:lj}{NewLine}{Exception}",
218+
["Serilog:WriteTo:0:Args:rollingInterval"] = "Day",
219+
});
220+
}
211221
}

Installer/Program.cs

Lines changed: 15 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,8 @@ public class BootstrapperOptions : SharedOptions
130130
if (!SystemFile.Exists(MsiPath))
131131
throw new ArgumentException($"MSI package not found at '{MsiPath}'", nameof(MsiPath));
132132
if (!SystemFile.Exists(WindowsAppSdkPath))
133-
throw new ArgumentException($"Windows App Sdk package not found at '{WindowsAppSdkPath}'", nameof(WindowsAppSdkPath));
133+
throw new ArgumentException($"Windows App Sdk package not found at '{WindowsAppSdkPath}'",
134+
nameof(WindowsAppSdkPath));
134135
}
135136
}
136137

@@ -141,6 +142,7 @@ public class Program
141142
private const string HelpUrl = "https://coder.com/docs";
142143
private const string RegistryKey = @"SOFTWARE\Coder Desktop";
143144
private const string AppConfigRegistryKey = RegistryKey + @"\App";
145+
private const string VpnServiceConfigRegistryKey = RegistryKey + @"\VpnService";
144146

145147
private const string DotNetCheckName = "DOTNET_RUNTIME_CHECK";
146148
private const RollForward DotNetCheckRollForward = RollForward.minor;
@@ -259,42 +261,24 @@ private static int BuildMsiPackage(MsiOptions opts)
259261
project.AddDir(programFiles64Folder);
260262

261263

262-
263264
project.AddRegValues(
264265
// Add registry values that are consumed by the manager. Note that these
265-
// should not be changed. See Vpn.Service/Program.cs and
266+
// should not be changed. See Vpn.Service/Program.cs (AddDefaultConfig) and
266267
// Vpn.Service/ManagerConfig.cs for more details.
267-
new RegValue(RegistryHive, RegistryKey, "Manager:ServiceRpcPipeName", "Coder.Desktop.Vpn"),
268-
new RegValue(RegistryHive, RegistryKey, "Manager:TunnelBinaryPath",
268+
new RegValue(RegistryHive, VpnServiceConfigRegistryKey, "Manager:ServiceRpcPipeName", "Coder.Desktop.Vpn"),
269+
new RegValue(RegistryHive, VpnServiceConfigRegistryKey, "Manager:TunnelBinaryPath",
269270
$"[INSTALLFOLDER]{opts.VpnDir}\\coder-vpn.exe"),
270-
new RegValue(RegistryHive, RegistryKey, "Manager:LogFileLocation",
271+
new RegValue(RegistryHive, VpnServiceConfigRegistryKey, "Manager:TunnelBinarySignatureSigner",
272+
"Coder Technologies Inc."),
273+
new RegValue(RegistryHive, VpnServiceConfigRegistryKey, "Manager:TunnelBinaryAllowVersionMismatch",
274+
"false"),
275+
new RegValue(RegistryHive, VpnServiceConfigRegistryKey, "Serilog:WriteTo:0:Args:path",
271276
@"[INSTALLFOLDER]coder-desktop-service.log"),
272-
new RegValue(RegistryHive, RegistryKey, "Manager:TunnelBinarySignatureSigner", "Coder Technologies Inc."),
273-
new RegValue(RegistryHive, RegistryKey, "Manager:TunnelBinaryAllowVersionMismatch", "false")
274-
);
275277

276-
// rather than adding individual reg values, it's much clearer to write the whole config as JSON then
277-
// programmatically spit out the registry values.
278-
var appConfigJson = """
279-
{
280-
"MutagenController": {
281-
"MutagenExecutablePath": "[INSTALLFOLDER]vpn\mutagen.exe"
282-
},
283-
"Serilog": {
284-
"Using": ["Serilog.Sinks.File"],
285-
"MinimumLevel": "Information",
286-
"Enrich": [ "FromLogContext" ],
287-
}
288-
}
289-
""";
290-
var appConfig =
291-
new ConfigurationBuilder().AddJsonStream(new MemoryStream(Encoding.UTF8.GetBytes(appConfigJson))).Build();
292-
293-
foreach (var kvp in appConfig.AsEnumerable())
294-
{
295-
if (kvp.Value is null) continue;
296-
project.AddRegValue(new RegValue(RegistryHive, AppConfigRegistryKey, kvp.Key, kvp.Value));
297-
}
278+
// Add registry values that are consumed by the App MutagenController. See App/Services/MutagenController.cs
279+
new RegValue(RegistryHive, AppConfigRegistryKey, "MutagenController:MutagenExecutablePath",
280+
@"[INSTALLFOLDER]vpn\mutagen.exe")
281+
);
298282

299283
// Note: most of this control panel info will not be visible as this
300284
// package is usually hidden in favor of the bootstrapper showing

Tests.Vpn.Service/packages.lock.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,15 @@
137137
"resolved": "9.0.4",
138138
"contentHash": "UI0TQPVkS78bFdjkTodmkH0Fe8lXv9LnhGFKgKrsgUJ5a5FVdFRcgjIkBVLbGgdRhxWirxH/8IXUtEyYJx6GQg=="
139139
},
140+
"Microsoft.Extensions.DependencyModel": {
141+
"type": "Transitive",
142+
"resolved": "9.0.0",
143+
"contentHash": "saxr2XzwgDU77LaQfYFXmddEDRUKHF4DaGMZkNB3qjdVSZlax3//dGJagJkKrGMIPNZs2jVFXITyCCR6UHJNdA==",
144+
"dependencies": {
145+
"System.Text.Encodings.Web": "9.0.0",
146+
"System.Text.Json": "9.0.0"
147+
}
148+
},
140149
"Microsoft.Extensions.Diagnostics": {
141150
"type": "Transitive",
142151
"resolved": "9.0.4",
@@ -409,6 +418,16 @@
409418
"Serilog": "4.2.0"
410419
}
411420
},
421+
"Serilog.Settings.Configuration": {
422+
"type": "Transitive",
423+
"resolved": "9.0.0",
424+
"contentHash": "4/Et4Cqwa+F88l5SeFeNZ4c4Z6dEAIKbu3MaQb2Zz9F/g27T5a3wvfMcmCOaAiACjfUb4A6wrlTVfyYUZk3RRQ==",
425+
"dependencies": {
426+
"Microsoft.Extensions.Configuration.Binder": "9.0.0",
427+
"Microsoft.Extensions.DependencyModel": "9.0.0",
428+
"Serilog": "4.2.0"
429+
}
430+
},
412431
"Serilog.Sinks.Console": {
413432
"type": "Transitive",
414433
"resolved": "6.0.0",
@@ -496,6 +515,7 @@
496515
"Microsoft.Security.Extensions": "[1.3.0, )",
497516
"Semver": "[3.0.0, )",
498517
"Serilog.Extensions.Hosting": "[9.0.0, )",
518+
"Serilog.Settings.Configuration": "[9.0.0, )",
499519
"Serilog.Sinks.Console": "[6.0.0, )",
500520
"Serilog.Sinks.File": "[6.0.0, )"
501521
}

Vpn.Service/ManagerConfig.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ public class ManagerConfig
1515

1616
[Required] public string TunnelBinaryPath { get; set; } = @"C:\coder-vpn.exe";
1717

18-
[Required] public string LogFileLocation { get; set; } = @"C:\coder-desktop-service.log";
19-
2018
// If empty, signatures will not be verified.
2119
[Required] public string TunnelBinarySignatureSigner { get; set; } = "Coder Technologies Inc.";
2220

Vpn.Service/Program.cs

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Microsoft.Extensions.Hosting;
44
using Microsoft.Win32;
55
using Serilog;
6+
using ILogger = Serilog.ILogger;
67

78
namespace Coder.Desktop.Vpn.Service;
89

@@ -14,29 +15,22 @@ public static class Program
1415
// installer.
1516
#if !DEBUG
1617
private const string ServiceName = "Coder Desktop";
17-
private const string ManagerConfigSection = "Manager";
18+
private const string ConfigSubKey = @"SOFTWARE\Coder Desktop\VpnService";
1819
#else
1920
// This value matches Create-Service.ps1.
2021
private const string ServiceName = "Coder Desktop (Debug)";
21-
private const string ManagerConfigSection = "DebugManager";
22+
private const string ConfigSubKey = @"SOFTWARE\Coder Desktop\DebugVpnService";
2223
#endif
2324

24-
private const string ConsoleOutputTemplate =
25-
"[{Timestamp:HH:mm:ss} {Level:u3}] {SourceContext} - {Message:lj}{NewLine}{Exception}";
26-
27-
private const string FileOutputTemplate =
28-
"{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {SourceContext} - {Message:lj}{NewLine}{Exception}";
25+
private const string ManagerConfigSection = "Manager";
2926

3027
private static ILogger MainLogger => Log.ForContext("SourceContext", "Coder.Desktop.Vpn.Service.Program");
3128

32-
private static LoggerConfiguration BaseLogConfig => new LoggerConfiguration()
33-
.Enrich.FromLogContext()
34-
.MinimumLevel.Debug()
35-
.WriteTo.Console(outputTemplate: ConsoleOutputTemplate);
36-
3729
public static async Task<int> Main(string[] args)
3830
{
39-
Log.Logger = BaseLogConfig.CreateLogger();
31+
// This logger will only be used until we load our full logging configuration and replace it.
32+
Log.Logger = new LoggerConfiguration().MinimumLevel.Debug().WriteTo.Console()
33+
.CreateLogger();
4034
MainLogger.Information("Application is starting");
4135
try
4236
{
@@ -58,27 +52,26 @@ public static async Task<int> Main(string[] args)
5852
private static async Task BuildAndRun(string[] args)
5953
{
6054
var builder = Host.CreateApplicationBuilder(args);
55+
var configBuilder = builder.Configuration as IConfigurationBuilder;
6156

6257
// Configuration sources
6358
builder.Configuration.Sources.Clear();
64-
(builder.Configuration as IConfigurationBuilder).Add(
65-
new RegistryConfigurationSource(Registry.LocalMachine, @"SOFTWARE\Coder Desktop"));
59+
AddDefaultConfig(configBuilder);
60+
configBuilder.Add(
61+
new RegistryConfigurationSource(Registry.LocalMachine, ConfigSubKey));
6662
builder.Configuration.AddEnvironmentVariables("CODER_MANAGER_");
6763
builder.Configuration.AddCommandLine(args);
6864

6965
// Options types (these get registered as IOptions<T> singletons)
7066
builder.Services.AddOptions<ManagerConfig>()
7167
.Bind(builder.Configuration.GetSection(ManagerConfigSection))
72-
.ValidateDataAnnotations()
73-
.PostConfigure(config =>
74-
{
75-
Log.Logger = BaseLogConfig
76-
.WriteTo.File(config.LogFileLocation, outputTemplate: FileOutputTemplate)
77-
.CreateLogger();
78-
});
68+
.ValidateDataAnnotations();
7969

8070
// Logging
81-
builder.Services.AddSerilog();
71+
builder.Services.AddSerilog((_, loggerConfig) =>
72+
{
73+
loggerConfig.ReadFrom.Configuration(builder.Configuration);
74+
});
8275

8376
// Singletons
8477
builder.Services.AddSingleton<IDownloader, Downloader>();
@@ -101,6 +94,32 @@ private static async Task BuildAndRun(string[] args)
10194
builder.Services.AddHostedService<ManagerService>();
10295
builder.Services.AddHostedService<ManagerRpcService>();
10396

104-
await builder.Build().RunAsync();
97+
var host = builder.Build();
98+
Log.Logger = (ILogger)host.Services.GetService(typeof(ILogger))!;
99+
MainLogger.Information("Application is starting");
100+
101+
await host.RunAsync();
102+
}
103+
104+
private static void AddDefaultConfig(IConfigurationBuilder builder)
105+
{
106+
builder.AddInMemoryCollection(new Dictionary<string, string?>
107+
{
108+
["Serilog:Using:0"] = "Serilog.Sinks.File",
109+
["Serilog:Using:1"] = "Serilog.Sinks.Console",
110+
111+
["Serilog:MinimumLevel"] = "Information",
112+
["Serilog:Enrich:0"] = "FromLogContext",
113+
114+
["Serilog:WriteTo:0:Name"] = "File",
115+
["Serilog:WriteTo:0:Args:path"] = @"C:\coder-desktop-service.log",
116+
["Serilog:WriteTo:0:Args:outputTemplate"] =
117+
"{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {SourceContext} - {Message:lj}{NewLine}{Exception}",
118+
["Serilog:WriteTo:0:Args:rollingInterval"] = "Day",
119+
120+
["Serilog:WriteTo:1:Name"] = "Console",
121+
["Serilog:WriteTo:1:Args:outputTemplate"] =
122+
"[{Timestamp:HH:mm:ss} {Level:u3}] {SourceContext} - {Message:lj}{NewLine}{Exception}",
123+
});
105124
}
106125
}

Vpn.Service/Vpn.Service.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
<PackageReference Include="Microsoft.Security.Extensions" Version="1.3.0" />
3232
<PackageReference Include="Semver" Version="3.0.0" />
3333
<PackageReference Include="Serilog.Extensions.Hosting" Version="9.0.0" />
34+
<PackageReference Include="Serilog.Settings.Configuration" Version="9.0.0" />
3435
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
3536
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
3637
</ItemGroup>

Vpn.Service/packages.lock.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,17 @@
8181
"Serilog.Extensions.Logging": "9.0.0"
8282
}
8383
},
84+
"Serilog.Settings.Configuration": {
85+
"type": "Direct",
86+
"requested": "[9.0.0, )",
87+
"resolved": "9.0.0",
88+
"contentHash": "4/Et4Cqwa+F88l5SeFeNZ4c4Z6dEAIKbu3MaQb2Zz9F/g27T5a3wvfMcmCOaAiACjfUb4A6wrlTVfyYUZk3RRQ==",
89+
"dependencies": {
90+
"Microsoft.Extensions.Configuration.Binder": "9.0.0",
91+
"Microsoft.Extensions.DependencyModel": "9.0.0",
92+
"Serilog": "4.2.0"
93+
}
94+
},
8495
"Serilog.Sinks.Console": {
8596
"type": "Direct",
8697
"requested": "[6.0.0, )",
@@ -195,6 +206,15 @@
195206
"resolved": "9.0.4",
196207
"contentHash": "UI0TQPVkS78bFdjkTodmkH0Fe8lXv9LnhGFKgKrsgUJ5a5FVdFRcgjIkBVLbGgdRhxWirxH/8IXUtEyYJx6GQg=="
197208
},
209+
"Microsoft.Extensions.DependencyModel": {
210+
"type": "Transitive",
211+
"resolved": "9.0.0",
212+
"contentHash": "saxr2XzwgDU77LaQfYFXmddEDRUKHF4DaGMZkNB3qjdVSZlax3//dGJagJkKrGMIPNZs2jVFXITyCCR6UHJNdA==",
213+
"dependencies": {
214+
"System.Text.Encodings.Web": "9.0.0",
215+
"System.Text.Json": "9.0.0"
216+
}
217+
},
198218
"Microsoft.Extensions.Diagnostics": {
199219
"type": "Transitive",
200220
"resolved": "9.0.4",

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy