Skip to content

Commit 716b98b

Browse files
committed
chore: add MutagenSdk project
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.
1 parent 7fc6398 commit 716b98b

29 files changed

+2007
-0
lines changed

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

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 Synchronization.SynchronizationClient Client { get; }
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+
Client = new Synchronization.SynchronizationClient(_channel);
48+
}
49+
50+
public void Dispose()
51+
{
52+
_channel.Dispose();
53+
GC.SuppressFinalize(this);
54+
}
55+
}

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>
+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+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* This file was taken from
3+
* https://github.com/mutagen-io/mutagen/tree/v0.18.1/pkg/filesystem/behavior/probe_mode.proto
4+
*
5+
* MIT License
6+
*
7+
* Copyright (c) 2016-present Docker, Inc.
8+
*
9+
* Permission is hereby granted, free of charge, to any person obtaining a copy
10+
* of this software and associated documentation files (the "Software"), to deal
11+
* in the Software without restriction, including without limitation the rights
12+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
* copies of the Software, and to permit persons to whom the Software is
14+
* furnished to do so, subject to the following conditions:
15+
*
16+
* The above copyright notice and this permission notice shall be included in all
17+
* copies or substantial portions of the Software.
18+
*
19+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25+
* SOFTWARE.
26+
*/
27+
28+
syntax = "proto3";
29+
30+
package behavior;
31+
option csharp_namespace = "Coder.Desktop.MutagenSdk.Proto.Filesystem.Behavior";
32+
33+
option go_package = "github.com/mutagen-io/mutagen/pkg/filesystem/behavior";
34+
35+
// ProbeMode specifies the mode for filesystem probing.
36+
enum ProbeMode {
37+
// ProbeMode_ProbeModeDefault represents an unspecified probe mode. It
38+
// should be converted to one of the following values based on the desired
39+
// default behavior.
40+
ProbeModeDefault = 0;
41+
// ProbeMode_ProbeModeProbe specifies that filesystem behavior should be
42+
// determined using temporary files or, if possible, a "fast-path" mechanism
43+
// (such as filesystem format detection) that provides quick but certain
44+
// determination of filesystem behavior.
45+
ProbeModeProbe = 1;
46+
// ProbeMode_ProbeModeAssume specifies that filesystem behavior should be
47+
// assumed based on the underlying platform. This is not as accurate as
48+
// ProbeMode_ProbeModeProbe.
49+
ProbeModeAssume = 2;
50+
}
51+
+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/**
2+
* This file was taken from
3+
* https://github.com/mutagen-io/mutagen/tree/v0.18.1/pkg/selection/selection.proto
4+
*
5+
* MIT License
6+
*
7+
* Copyright (c) 2016-present Docker, Inc.
8+
*
9+
* Permission is hereby granted, free of charge, to any person obtaining a copy
10+
* of this software and associated documentation files (the "Software"), to deal
11+
* in the Software without restriction, including without limitation the rights
12+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
* copies of the Software, and to permit persons to whom the Software is
14+
* furnished to do so, subject to the following conditions:
15+
*
16+
* The above copyright notice and this permission notice shall be included in all
17+
* copies or substantial portions of the Software.
18+
*
19+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25+
* SOFTWARE.
26+
*/
27+
28+
syntax = "proto3";
29+
30+
package selection;
31+
option csharp_namespace = "Coder.Desktop.MutagenSdk.Proto.Selection";
32+
33+
option go_package = "github.com/mutagen-io/mutagen/pkg/selection";
34+
35+
// Selection encodes a selection mechanism that can be used to select a
36+
// collection of sessions. It should have exactly one member set.
37+
message Selection {
38+
// All, if true, indicates that all sessions should be selected.
39+
bool all = 1;
40+
// Specifications is a list of session specifications. Each element may be
41+
// either a session identifier or name (or a prefix thereof). If non-empty,
42+
// it indicates that these specifications should be used to select sessions.
43+
repeated string specifications = 2;
44+
// LabelSelector is a label selector specification. If present (non-empty),
45+
// it indicates that this selector should be used to select sessions.
46+
string labelSelector = 3;
47+
}
48+

0 commit comments

Comments
 (0)