Skip to content

Commit 8e6ec03

Browse files
authored
chore: add MutagenSdk project (#48)
Contains a gRPC client for mutagen's synchronization API. All required .proto files are vendored using a new script `Update-Proto.ps1`, which finds all required files by scanning `import` directives. The vendored files are modified to add `csharp_namespace` and a MIT license header from mutagen. Example usage: ```cs using var client = new MutagenClient(@"C:\Users\dean\.mutagen"); var res = await client.Synchronization.ListAsync(new ListRequest { Selection = new Selection { All = true, }, }); foreach (var state in res.SessionStates) Console.WriteLine(state); ``` Closes coder/internal#378
1 parent 7fc6398 commit 8e6ec03

30 files changed

+2012
-0
lines changed

Diff for: .gitattributes

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

Diff for: Coder.Desktop.sln

+18
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Vpn.DebugClient", "Vpn.Debu
2323
EndProject
2424
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Installer", "Installer\Installer.csproj", "{39F5B55A-09D8-477D-A3FA-ADAC29C52605}"
2525
EndProject
26+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MutagenSdk", "MutagenSdk\MutagenSdk.csproj", "{E2477ADC-03DA-490D-9369-79A4CC4A58D2}"
27+
EndProject
2628
Global
2729
GlobalSection(SolutionConfigurationPlatforms) = preSolution
2830
Debug|Any CPU = Debug|Any CPU
@@ -203,6 +205,22 @@ Global
203205
{39F5B55A-09D8-477D-A3FA-ADAC29C52605}.Release|x64.Build.0 = Release|Any CPU
204206
{39F5B55A-09D8-477D-A3FA-ADAC29C52605}.Release|x86.ActiveCfg = Release|Any CPU
205207
{39F5B55A-09D8-477D-A3FA-ADAC29C52605}.Release|x86.Build.0 = Release|Any CPU
208+
{E2477ADC-03DA-490D-9369-79A4CC4A58D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
209+
{E2477ADC-03DA-490D-9369-79A4CC4A58D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
210+
{E2477ADC-03DA-490D-9369-79A4CC4A58D2}.Debug|ARM64.ActiveCfg = Debug|Any CPU
211+
{E2477ADC-03DA-490D-9369-79A4CC4A58D2}.Debug|ARM64.Build.0 = Debug|Any CPU
212+
{E2477ADC-03DA-490D-9369-79A4CC4A58D2}.Debug|x64.ActiveCfg = Debug|Any CPU
213+
{E2477ADC-03DA-490D-9369-79A4CC4A58D2}.Debug|x64.Build.0 = Debug|Any CPU
214+
{E2477ADC-03DA-490D-9369-79A4CC4A58D2}.Debug|x86.ActiveCfg = Debug|Any CPU
215+
{E2477ADC-03DA-490D-9369-79A4CC4A58D2}.Debug|x86.Build.0 = Debug|Any CPU
216+
{E2477ADC-03DA-490D-9369-79A4CC4A58D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
217+
{E2477ADC-03DA-490D-9369-79A4CC4A58D2}.Release|Any CPU.Build.0 = Release|Any CPU
218+
{E2477ADC-03DA-490D-9369-79A4CC4A58D2}.Release|ARM64.ActiveCfg = Release|Any CPU
219+
{E2477ADC-03DA-490D-9369-79A4CC4A58D2}.Release|ARM64.Build.0 = Release|Any CPU
220+
{E2477ADC-03DA-490D-9369-79A4CC4A58D2}.Release|x64.ActiveCfg = Release|Any CPU
221+
{E2477ADC-03DA-490D-9369-79A4CC4A58D2}.Release|x64.Build.0 = Release|Any CPU
222+
{E2477ADC-03DA-490D-9369-79A4CC4A58D2}.Release|x86.ActiveCfg = Release|Any CPU
223+
{E2477ADC-03DA-490D-9369-79A4CC4A58D2}.Release|x86.Build.0 = Release|Any CPU
206224
EndGlobalSection
207225
GlobalSection(SolutionProperties) = preSolution
208226
HideSolutionNode = FALSE

Diff for: MutagenSdk/MutagenClient.cs

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
using Coder.Desktop.MutagenSdk.Proto.Service.Synchronization;
2+
using Grpc.Core;
3+
using Grpc.Net.Client;
4+
5+
namespace Coder.Desktop.MutagenSdk;
6+
7+
public class MutagenClient : IDisposable
8+
{
9+
private readonly GrpcChannel _channel;
10+
11+
public readonly Synchronization.SynchronizationClient Synchronization;
12+
13+
public MutagenClient(string dataDir)
14+
{
15+
// Check for the lock file first, since it should exist if it's running.
16+
var daemonLockFile = Path.Combine(dataDir, "daemon", "daemon.lock");
17+
if (!File.Exists(daemonLockFile))
18+
throw new FileNotFoundException(
19+
"Mutagen daemon lock file not found, did the mutagen daemon start successfully?", daemonLockFile);
20+
21+
// Read the IPC named pipe address from the sock file.
22+
var daemonSockFile = Path.Combine(dataDir, "daemon", "daemon.sock");
23+
if (!File.Exists(daemonSockFile))
24+
throw new FileNotFoundException(
25+
"Mutagen daemon socket file not found, did the mutagen daemon start successfully?", daemonSockFile);
26+
var daemonSockAddress = File.ReadAllText(daemonSockFile).Trim();
27+
if (string.IsNullOrWhiteSpace(daemonSockAddress))
28+
throw new InvalidOperationException(
29+
"Mutagen daemon socket address is empty, did the mutagen daemon start successfully?");
30+
31+
const string namedPipePrefix = @"\\.\pipe\";
32+
if (!daemonSockAddress.StartsWith(namedPipePrefix))
33+
throw new InvalidOperationException("Mutagen daemon socket address is not a named pipe address");
34+
var pipeName = daemonSockAddress[namedPipePrefix.Length..];
35+
36+
var connectionFactory = new NamedPipesConnectionFactory(pipeName);
37+
var socketsHttpHandler = new SocketsHttpHandler
38+
{
39+
ConnectCallback = connectionFactory.ConnectAsync,
40+
};
41+
42+
_channel = GrpcChannel.ForAddress("http://localhost", new GrpcChannelOptions
43+
{
44+
Credentials = ChannelCredentials.Insecure,
45+
HttpHandler = socketsHttpHandler,
46+
});
47+
Synchronization = new Synchronization.SynchronizationClient(_channel);
48+
}
49+
50+
public void Dispose()
51+
{
52+
_channel.Dispose();
53+
GC.SuppressFinalize(this);
54+
}
55+
}

Diff for: MutagenSdk/MutagenSdk.csproj

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<AssemblyName>Coder.Desktop.MutagenSdk</AssemblyName>
5+
<RootNamespace>Coder.Desktop.MutagenSdk</RootNamespace>
6+
<TargetFramework>net8.0</TargetFramework>
7+
<ImplicitUsings>enable</ImplicitUsings>
8+
<Nullable>enable</Nullable>
9+
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
10+
</PropertyGroup>
11+
12+
<ItemGroup>
13+
<Protobuf Include="Proto\**\*.proto" ProtoRoot="Proto" GrpcServices="Client" />
14+
</ItemGroup>
15+
16+
<ItemGroup>
17+
<PackageReference Include="Google.Protobuf" Version="3.29.3" />
18+
<PackageReference Include="Grpc.Net.Client" Version="2.67.0" />
19+
<PackageReference Include="Grpc.Tools" Version="2.69.0">
20+
<PrivateAssets>all</PrivateAssets>
21+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
22+
</PackageReference>
23+
</ItemGroup>
24+
25+
</Project>

Diff for: MutagenSdk/NamedPipesConnectionFactory.cs

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System.IO.Pipes;
2+
using System.Security.Principal;
3+
4+
namespace Coder.Desktop.MutagenSdk;
5+
6+
public class NamedPipesConnectionFactory
7+
{
8+
private readonly string _pipeName;
9+
10+
public NamedPipesConnectionFactory(string pipeName)
11+
{
12+
_pipeName = pipeName;
13+
}
14+
15+
public async ValueTask<Stream> ConnectAsync(SocketsHttpConnectionContext _,
16+
CancellationToken cancellationToken = default)
17+
{
18+
var client = new NamedPipeClientStream(
19+
".",
20+
_pipeName,
21+
PipeDirection.InOut,
22+
PipeOptions.WriteThrough | PipeOptions.Asynchronous,
23+
TokenImpersonationLevel.Anonymous);
24+
25+
try
26+
{
27+
await client.ConnectAsync(cancellationToken);
28+
return client;
29+
}
30+
catch
31+
{
32+
await client.DisposeAsync();
33+
throw;
34+
}
35+
}
36+
}

Diff for: MutagenSdk/Proto/filesystem/behavior/probe_mode.proto

+51
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: MutagenSdk/Proto/selection/selection.proto

+48
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)