Skip to content

Commit bb668c7

Browse files
committed
Add StartAsync method to Speaker and add RpcRole to RpcMessage via new attribute
1 parent 9e19d40 commit bb668c7

File tree

9 files changed

+265
-282
lines changed

9 files changed

+265
-282
lines changed

.editorconfig

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
[*]
2+
indent_style = space
3+
indent_size = 4
4+
tab_width = 4
5+
trim_trailing_whitespace = true
6+
insert_final_newline = true
7+
charset = utf-8
8+
end_of_line = crlf
9+
10+
resharper_csharp_brace_style = next_line
11+
resharper_csharp_braces_for_foreach = not_required
12+
resharper_csharp_braces_for_for = not_required
13+
resharper_csharp_braces_for_while = not_required
14+
15+
# Microsoft .NET properties
16+
csharp_new_line_before_members_in_object_initializers = false
17+
csharp_preferred_modifier_order = public, private, protected, internal, file, new, static, abstract, virtual, sealed, readonly, override, extern, unsafe, volatile, async, required:suggestion
18+
csharp_style_prefer_utf8_string_literals = true:suggestion
19+
csharp_style_var_elsewhere = true:suggestion
20+
csharp_style_var_for_built_in_types = true:suggestion
21+
csharp_style_var_when_type_is_apparent = true:suggestion
22+
dotnet_naming_rule.unity_serialized_field_rule.import_to_resharper = True
23+
dotnet_naming_rule.unity_serialized_field_rule.resharper_description = Unity serialized field
24+
dotnet_naming_rule.unity_serialized_field_rule.resharper_guid = 5f0fdb63-c892-4d2c-9324-15c80b22a7ef
25+
dotnet_naming_rule.unity_serialized_field_rule.severity = warning
26+
dotnet_naming_rule.unity_serialized_field_rule.style = lower_camel_case_style
27+
dotnet_naming_rule.unity_serialized_field_rule.symbols = unity_serialized_field_symbols
28+
dotnet_naming_style.lower_camel_case_style.capitalization = camel_case
29+
dotnet_naming_symbols.unity_serialized_field_symbols.applicable_accessibilities = *
30+
dotnet_naming_symbols.unity_serialized_field_symbols.applicable_kinds =
31+
dotnet_naming_symbols.unity_serialized_field_symbols.resharper_applicable_kinds = unity_serialised_field
32+
dotnet_naming_symbols.unity_serialized_field_symbols.resharper_required_modifiers = instance
33+
dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:none
34+
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:none
35+
dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:none
36+
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
37+
dotnet_style_predefined_type_for_member_access = true:suggestion
38+
dotnet_style_qualification_for_event = false:suggestion
39+
dotnet_style_qualification_for_field = false:suggestion
40+
dotnet_style_qualification_for_method = false:suggestion
41+
dotnet_style_qualification_for_property = false:suggestion
42+
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
43+
44+
# ReSharper properties
45+
resharper_autodetect_indent_settings = true
46+
resharper_formatter_off_tag = @formatter:off
47+
resharper_formatter_on_tag = @formatter:on
48+
resharper_formatter_tags_enabled = true
49+
resharper_no_indent_inside_if_element_longer_than = 2147483647
50+
resharper_trailing_comma_in_multiline_lists = true
51+
resharper_use_indent_from_vs = false
52+
53+
# ReSharper inspection severities
54+
resharper_arrange_redundant_parentheses_highlighting = hint
55+
resharper_arrange_this_qualifier_highlighting = hint
56+
resharper_arrange_type_member_modifiers_highlighting = hint
57+
resharper_arrange_type_modifiers_highlighting = hint
58+
resharper_built_in_type_reference_style_for_member_access_highlighting = hint
59+
resharper_built_in_type_reference_style_highlighting = hint
60+
resharper_mvc_action_not_resolved_highlighting = warning
61+
resharper_mvc_area_not_resolved_highlighting = warning
62+
resharper_mvc_controller_not_resolved_highlighting = warning
63+
resharper_mvc_masterpage_not_resolved_highlighting = warning
64+
resharper_mvc_partial_view_not_resolved_highlighting = warning
65+
resharper_mvc_template_not_resolved_highlighting = warning
66+
resharper_mvc_view_component_not_resolved_highlighting = warning
67+
resharper_mvc_view_component_view_not_resolved_highlighting = warning
68+
resharper_mvc_view_not_resolved_highlighting = warning
69+
resharper_razor_assembly_not_resolved_highlighting = warning
70+
resharper_redundant_base_qualifier_highlighting = warning
71+
resharper_suggest_var_or_type_built_in_types_highlighting = hint
72+
resharper_suggest_var_or_type_elsewhere_highlighting = hint
73+
resharper_suggest_var_or_type_simple_types_highlighting = hint
74+
resharper_unnecessary_whitespace_highlighting = suggestion
75+
resharper_web_config_module_not_resolved_highlighting = warning
76+
resharper_web_config_type_not_resolved_highlighting = warning
77+
resharper_web_config_wrong_module_highlighting = warning
78+
79+
[{*.json,*.jsonc,*.yml,*.yaml,*.proto}]
80+
indent_style = space
81+
indent_size = 2

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,3 +398,6 @@ FodyWeavers.xsd
398398

399399
# JetBrains Rider
400400
*.sln.iml
401+
.idea/**/workspace.xml
402+
.idea/**/usage.statistics.xml
403+
.idea/**/shelf

.idea/.idea.Coder.Desktop/.idea/workspace.xml

Lines changed: 0 additions & 96 deletions
This file was deleted.

Rpc/Version.cs renamed to Rpc.Proto/ApiVersion.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace Coder.Desktop.Rpc;
1+
namespace Coder.Desktop.Rpc.Proto;
22

33
/// <summary>
44
/// Thrown when the two peers are incompatible with each other.
@@ -16,9 +16,9 @@ public class ApiVersion(int major, int minor, params int[] additionalMajors)
1616
{
1717
public static readonly ApiVersion Current = new(1, 0);
1818

19-
public int Major { get; } = major;
20-
public int Minor { get; } = minor;
21-
public int[] AdditionalMajors { get; } = additionalMajors;
19+
private int Major { get; } = major;
20+
private int Minor { get; } = minor;
21+
private int[] AdditionalMajors { get; } = additionalMajors;
2222

2323
/// <summary>
2424
/// Parse a string in the format "major.minor" into an ApiVersion.

Rpc.Proto/RpcHeader.cs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using System.Text;
2+
3+
namespace Coder.Desktop.Rpc.Proto;
4+
5+
/// <summary>
6+
/// A header to write or read from a stream to identify the speaker's role and version.
7+
/// </summary>
8+
/// <param name="role">Role of the speaker</param>
9+
/// <param name="version">Version of the speaker</param>
10+
public class RpcHeader(RpcRole role, ApiVersion version)
11+
{
12+
private const string Preamble = "codervpn";
13+
14+
public RpcRole Role { get; } = role;
15+
public ApiVersion Version { get; } = version;
16+
17+
/// <summary>
18+
/// Parse a header string into a <c>SpeakerHeader</c>.
19+
/// </summary>
20+
/// <param name="header">Raw header string without trailing newline</param>
21+
/// <returns>Parsed header</returns>
22+
/// <exception cref="ArgumentException">Invalid header string</exception>
23+
public static RpcHeader Parse(string header)
24+
{
25+
var parts = header.Split(' ');
26+
if (parts.Length != 3) throw new ArgumentException($"Wrong number of parts in header string '{header}'");
27+
if (parts[0] != Preamble) throw new ArgumentException($"Invalid preamble in header string '{header}'");
28+
29+
var version = ApiVersion.ParseString(parts[1]);
30+
var role = new RpcRole(parts[2]);
31+
return new RpcHeader(role, version);
32+
}
33+
34+
/// <summary>
35+
/// Construct a header string from the role and version with a trailing newline.
36+
/// </summary>
37+
public override string ToString()
38+
{
39+
return $"{Preamble} {Version} {Role}\n";
40+
}
41+
42+
public ReadOnlyMemory<byte> ToBytes()
43+
{
44+
return Encoding.UTF8.GetBytes(ToString());
45+
}
46+
}

Rpc.Proto/RpcMessage.cs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1-
using Google.Protobuf;
1+
using System.Reflection;
2+
using Google.Protobuf;
23

34
namespace Coder.Desktop.Rpc.Proto;
45

6+
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
7+
public class RpcRoleAttribute(string role) : Attribute
8+
{
9+
public RpcRole Role { get; } = new(role);
10+
}
11+
512
/// <summary>
613
/// Represents an actual over-the-wire message type.
714
/// </summary>
@@ -19,8 +26,22 @@ public abstract class RpcMessage<T> where T : IMessage<T>
1926
/// contents.
2027
/// </summary>
2128
public abstract T Message { get; }
29+
30+
/// <summary>
31+
/// Gets the RpcRole of the message type from it's RpcRole attribute.
32+
/// </summary>
33+
/// <returns></returns>
34+
/// <exception cref="ArgumentException">The message type does not have an RpcRoleAttribute</exception>
35+
public static RpcRole GetRole()
36+
{
37+
var type = typeof(T);
38+
var attr = type.GetCustomAttribute<RpcRoleAttribute>();
39+
if (attr is null) throw new ArgumentException($"Message type {type} does not have a RpcRoleAttribute");
40+
return attr.Role;
41+
}
2242
}
2343

44+
[RpcRole(RpcRole.Manager)]
2445
public partial class ManagerMessage : RpcMessage<ManagerMessage>
2546
{
2647
public override RPC RpcField
@@ -32,6 +53,7 @@ public override RPC RpcField
3253
public override ManagerMessage Message => this;
3354
}
3455

56+
[RpcRole(RpcRole.Tunnel)]
3557
public partial class TunnelMessage : RpcMessage<TunnelMessage>
3658
{
3759
public override RPC RpcField

Rpc.Proto/RpcRole.cs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
namespace Coder.Desktop.Rpc.Proto;
2+
3+
/// <summary>
4+
/// Represents a role that either side of the connection can fulfil.
5+
/// </summary>
6+
public sealed class RpcRole
7+
{
8+
internal const string Manager = "manager";
9+
internal const string Tunnel = "tunnel";
10+
11+
public RpcRole(string role)
12+
{
13+
if (role != Manager && role != Tunnel) throw new ArgumentException($"Unknown role '{role}'");
14+
15+
Role = role;
16+
}
17+
18+
private string Role { get; }
19+
20+
public override string ToString()
21+
{
22+
return Role;
23+
}
24+
25+
#region SpeakerRole equality
26+
27+
public static bool operator ==(RpcRole a, RpcRole b)
28+
{
29+
return a.Equals(b);
30+
}
31+
32+
public static bool operator !=(RpcRole a, RpcRole b)
33+
{
34+
return !a.Equals(b);
35+
}
36+
37+
private bool Equals(RpcRole other)
38+
{
39+
return Role == other.Role;
40+
}
41+
42+
public override bool Equals(object? obj)
43+
{
44+
if (obj is null) return false;
45+
if (ReferenceEquals(this, obj)) return true;
46+
if (obj.GetType() != GetType()) return false;
47+
return Equals((RpcRole)obj);
48+
}
49+
50+
public override int GetHashCode()
51+
{
52+
return Role.GetHashCode();
53+
}
54+
55+
#endregion
56+
}

0 commit comments

Comments
 (0)