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

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
MutagenSdk/Proto/**/*.proto linguist-generated=true

Coder.Desktop.sln

Lines changed: 18 additions & 0 deletions
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

MutagenSdk/MutagenClient.cs

Lines changed: 55 additions & 0 deletions
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+
}

MutagenSdk/MutagenSdk.csproj

Lines changed: 25 additions & 0 deletions
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>
Lines changed: 36 additions & 0 deletions
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+
}

MutagenSdk/Proto/filesystem/behavior/probe_mode.proto

Lines changed: 51 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

MutagenSdk/Proto/selection/selection.proto

Lines changed: 48 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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