diff --git a/ConnectorTest/ConnectorTest.csproj b/ConnectorTest/ConnectorTest.csproj index b90ebde..3c4e285 100644 --- a/ConnectorTest/ConnectorTest.csproj +++ b/ConnectorTest/ConnectorTest.csproj @@ -9,8 +9,12 @@ - + + + + + diff --git a/CrystalConnector.Protocol/CrystalConnector.Protocol.csproj b/CrystalConnector.Protocol/CrystalConnector.Protocol.csproj new file mode 100644 index 0000000..7809f00 --- /dev/null +++ b/CrystalConnector.Protocol/CrystalConnector.Protocol.csproj @@ -0,0 +1,24 @@ + + + net8.0 + enable + enable + True + qyl27,MeowCraftMC + https://github.com/MeowCraftMC/CrystalConnector + Apache-2.0 + True + True + https://github.com/MeowCraftMC/CrystalConnector + + + + + + + + + + + + \ No newline at end of file diff --git a/CrystalConnector.Protocol/Messages/Messages.cs b/CrystalConnector.Protocol/Messages/Messages.cs new file mode 100644 index 0000000..d5ba19b --- /dev/null +++ b/CrystalConnector.Protocol/Messages/Messages.cs @@ -0,0 +1,1799 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: messages.proto +// +#pragma warning disable 1591, 0612, 3021, 8981 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace CrystalConnector.Protocol.Messages { + + /// Holder for reflection information generated from messages.proto + public static partial class MessagesReflection { + + #region Descriptor + /// File descriptor for messages.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static MessagesReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "Cg5tZXNzYWdlcy5wcm90bxIQQ3J5c3RhbENvbm5lY3RvciIxCg5OYW1lc3Bh", + "Y2VkTmFtZRIRCgluYW1lc3BhY2UYASABKAkSDAoEbmFtZRgCIAEoCSIMCgpT", + "dWNjZXNzZnVsInAKBlJlc3VsdBIyCgpzdWNjZXNzZnVsGAEgASgLMhwuQ3J5", + "c3RhbENvbm5lY3Rvci5TdWNjZXNzZnVsSAASKAoFZXJyb3IYAiABKA4yFy5D", + "cnlzdGFsQ29ubmVjdG9yLkVycm9ySABCCAoGcmVzdWx0IpkBCgxBdXRoZW50", + "aWNhdGUSMwoJY2xpZW50X2lkGAEgASgLMiAuQ3J5c3RhbENvbm5lY3Rvci5O", + "YW1lc3BhY2VkTmFtZRITCgtjbGllbnRfbmFtZRgCIAEoCRISCgpzZWNyZXRf", + "a2V5GAMgASgJEisKCGNoYW5uZWxzGAQgAygLMhkuQ3J5c3RhbENvbm5lY3Rv", + "ci5DaGFubmVsIm4KB0NoYW5uZWwSLAoCaWQYASABKAsyIC5DcnlzdGFsQ29u", + "bmVjdG9yLk5hbWVzcGFjZWROYW1lEjUKCWRpcmVjdGlvbhgCIAEoDjIiLkNy", + "eXN0YWxDb25uZWN0b3IuTWVzc2FnZURpcmVjdGlvbiJNCgdQdWJsaXNoEjEK", + "B2NoYW5uZWwYASABKAsyIC5DcnlzdGFsQ29ubmVjdG9yLk5hbWVzcGFjZWRO", + "YW1lEg8KB3BheWxvYWQYAiABKAkiYAoHRm9yd2FyZBIRCglwdWJsaXNoZXIY", + "ASABKAkSMQoHY2hhbm5lbBgCIAEoCzIgLkNyeXN0YWxDb25uZWN0b3IuTmFt", + "ZXNwYWNlZE5hbWUSDwoHcGF5bG9hZBgDIAEoCSpBChBNZXNzYWdlRGlyZWN0", + "aW9uEggKBE5PTkUQABIMCghJTkNPTUlORxABEgwKCE9VVEdPSU5HEAISBwoD", + "QUxMEAMqdQoFRXJyb3ISCwoHVU5LTk9XThAAEhEKDUFVVEhFTlRJQ0FURUQQ", + "ARIPCgtOQU1FX0VYSVNUUxACEhMKD1VOQVVUSEVOVElDQVRFRBADEhgKFFVO", + "UkVHSVNURVJFRF9DSEFOTkVMEAQSDAoISU5URVJOQUwQBUIlqgIiQ3J5c3Rh", + "bENvbm5lY3Rvci5Qcm90b2NvbC5NZXNzYWdlc2IGcHJvdG8z")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { }, + new pbr::GeneratedClrTypeInfo(new[] {typeof(global::CrystalConnector.Protocol.Messages.MessageDirection), typeof(global::CrystalConnector.Protocol.Messages.Error), }, null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::CrystalConnector.Protocol.Messages.NamespacedName), global::CrystalConnector.Protocol.Messages.NamespacedName.Parser, new[]{ "Namespace", "Name" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::CrystalConnector.Protocol.Messages.Successful), global::CrystalConnector.Protocol.Messages.Successful.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::CrystalConnector.Protocol.Messages.Result), global::CrystalConnector.Protocol.Messages.Result.Parser, new[]{ "Successful", "Error" }, new[]{ "Result" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::CrystalConnector.Protocol.Messages.Authenticate), global::CrystalConnector.Protocol.Messages.Authenticate.Parser, new[]{ "ClientId", "ClientName", "SecretKey", "Channels" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::CrystalConnector.Protocol.Messages.Channel), global::CrystalConnector.Protocol.Messages.Channel.Parser, new[]{ "Id", "Direction" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::CrystalConnector.Protocol.Messages.Publish), global::CrystalConnector.Protocol.Messages.Publish.Parser, new[]{ "Channel", "Payload" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::CrystalConnector.Protocol.Messages.Forward), global::CrystalConnector.Protocol.Messages.Forward.Parser, new[]{ "Publisher", "Channel", "Payload" }, null, null, null, null) + })); + } + #endregion + + } + #region Enums + public enum MessageDirection { + [pbr::OriginalName("NONE")] None = 0, + [pbr::OriginalName("INCOMING")] Incoming = 1, + [pbr::OriginalName("OUTGOING")] Outgoing = 2, + [pbr::OriginalName("ALL")] All = 3, + } + + public enum Error { + [pbr::OriginalName("UNKNOWN")] Unknown = 0, + [pbr::OriginalName("AUTHENTICATED")] Authenticated = 1, + [pbr::OriginalName("NAME_EXISTS")] NameExists = 2, + [pbr::OriginalName("UNAUTHENTICATED")] Unauthenticated = 3, + [pbr::OriginalName("UNREGISTERED_CHANNEL")] UnregisteredChannel = 4, + [pbr::OriginalName("INTERNAL")] Internal = 5, + } + + #endregion + + #region Messages + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class NamespacedName : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NamespacedName()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::CrystalConnector.Protocol.Messages.MessagesReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public NamespacedName() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public NamespacedName(NamespacedName other) : this() { + namespace_ = other.namespace_; + name_ = other.name_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public NamespacedName Clone() { + return new NamespacedName(this); + } + + /// Field number for the "namespace" field. + public const int NamespaceFieldNumber = 1; + private string namespace_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Namespace { + get { return namespace_; } + set { + namespace_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "name" field. + public const int NameFieldNumber = 2; + private string name_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Name { + get { return name_; } + set { + name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as NamespacedName); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(NamespacedName other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Namespace != other.Namespace) return false; + if (Name != other.Name) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Namespace.Length != 0) hash ^= Namespace.GetHashCode(); + if (Name.Length != 0) hash ^= Name.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Namespace.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Namespace); + } + if (Name.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Name); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Namespace.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Namespace); + } + if (Name.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Name); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Namespace.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Namespace); + } + if (Name.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(NamespacedName other) { + if (other == null) { + return; + } + if (other.Namespace.Length != 0) { + Namespace = other.Namespace; + } + if (other.Name.Length != 0) { + Name = other.Name; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Namespace = input.ReadString(); + break; + } + case 18: { + Name = input.ReadString(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + Namespace = input.ReadString(); + break; + } + case 18: { + Name = input.ReadString(); + break; + } + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Successful : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Successful()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::CrystalConnector.Protocol.Messages.MessagesReflection.Descriptor.MessageTypes[1]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Successful() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Successful(Successful other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Successful Clone() { + return new Successful(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as Successful); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(Successful other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(Successful other) { + if (other == null) { + return; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Result : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Result()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::CrystalConnector.Protocol.Messages.MessagesReflection.Descriptor.MessageTypes[2]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Result() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Result(Result other) : this() { + switch (other.ResultCase) { + case ResultOneofCase.Successful: + Successful = other.Successful.Clone(); + break; + case ResultOneofCase.Error: + Error = other.Error; + break; + } + + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Result Clone() { + return new Result(this); + } + + /// Field number for the "successful" field. + public const int SuccessfulFieldNumber = 1; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::CrystalConnector.Protocol.Messages.Successful Successful { + get { return resultCase_ == ResultOneofCase.Successful ? (global::CrystalConnector.Protocol.Messages.Successful) result_ : null; } + set { + result_ = value; + resultCase_ = value == null ? ResultOneofCase.None : ResultOneofCase.Successful; + } + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 2; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::CrystalConnector.Protocol.Messages.Error Error { + get { return HasError ? (global::CrystalConnector.Protocol.Messages.Error) result_ : global::CrystalConnector.Protocol.Messages.Error.Unknown; } + set { + result_ = value; + resultCase_ = ResultOneofCase.Error; + } + } + /// Gets whether the "error" field is set + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool HasError { + get { return resultCase_ == ResultOneofCase.Error; } + } + /// Clears the value of the oneof if it's currently set to "error" + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void ClearError() { + if (HasError) { + ClearResult(); + } + } + + private object result_; + /// Enum of possible cases for the "result" oneof. + public enum ResultOneofCase { + None = 0, + Successful = 1, + Error = 2, + } + private ResultOneofCase resultCase_ = ResultOneofCase.None; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public ResultOneofCase ResultCase { + get { return resultCase_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void ClearResult() { + resultCase_ = ResultOneofCase.None; + result_ = null; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as Result); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(Result other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Successful, other.Successful)) return false; + if (Error != other.Error) return false; + if (ResultCase != other.ResultCase) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (resultCase_ == ResultOneofCase.Successful) hash ^= Successful.GetHashCode(); + if (HasError) hash ^= Error.GetHashCode(); + hash ^= (int) resultCase_; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (resultCase_ == ResultOneofCase.Successful) { + output.WriteRawTag(10); + output.WriteMessage(Successful); + } + if (HasError) { + output.WriteRawTag(16); + output.WriteEnum((int) Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (resultCase_ == ResultOneofCase.Successful) { + output.WriteRawTag(10); + output.WriteMessage(Successful); + } + if (HasError) { + output.WriteRawTag(16); + output.WriteEnum((int) Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (resultCase_ == ResultOneofCase.Successful) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Successful); + } + if (HasError) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(Result other) { + if (other == null) { + return; + } + switch (other.ResultCase) { + case ResultOneofCase.Successful: + if (Successful == null) { + Successful = new global::CrystalConnector.Protocol.Messages.Successful(); + } + Successful.MergeFrom(other.Successful); + break; + case ResultOneofCase.Error: + Error = other.Error; + break; + } + + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + global::CrystalConnector.Protocol.Messages.Successful subBuilder = new global::CrystalConnector.Protocol.Messages.Successful(); + if (resultCase_ == ResultOneofCase.Successful) { + subBuilder.MergeFrom(Successful); + } + input.ReadMessage(subBuilder); + Successful = subBuilder; + break; + } + case 16: { + result_ = input.ReadEnum(); + resultCase_ = ResultOneofCase.Error; + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + global::CrystalConnector.Protocol.Messages.Successful subBuilder = new global::CrystalConnector.Protocol.Messages.Successful(); + if (resultCase_ == ResultOneofCase.Successful) { + subBuilder.MergeFrom(Successful); + } + input.ReadMessage(subBuilder); + Successful = subBuilder; + break; + } + case 16: { + result_ = input.ReadEnum(); + resultCase_ = ResultOneofCase.Error; + break; + } + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Authenticate : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Authenticate()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::CrystalConnector.Protocol.Messages.MessagesReflection.Descriptor.MessageTypes[3]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Authenticate() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Authenticate(Authenticate other) : this() { + clientId_ = other.clientId_ != null ? other.clientId_.Clone() : null; + clientName_ = other.clientName_; + secretKey_ = other.secretKey_; + channels_ = other.channels_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Authenticate Clone() { + return new Authenticate(this); + } + + /// Field number for the "client_id" field. + public const int ClientIdFieldNumber = 1; + private global::CrystalConnector.Protocol.Messages.NamespacedName clientId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::CrystalConnector.Protocol.Messages.NamespacedName ClientId { + get { return clientId_; } + set { + clientId_ = value; + } + } + + /// Field number for the "client_name" field. + public const int ClientNameFieldNumber = 2; + private string clientName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string ClientName { + get { return clientName_; } + set { + clientName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "secret_key" field. + public const int SecretKeyFieldNumber = 3; + private string secretKey_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string SecretKey { + get { return secretKey_; } + set { + secretKey_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "channels" field. + public const int ChannelsFieldNumber = 4; + private static readonly pb::FieldCodec _repeated_channels_codec + = pb::FieldCodec.ForMessage(34, global::CrystalConnector.Protocol.Messages.Channel.Parser); + private readonly pbc::RepeatedField channels_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public pbc::RepeatedField Channels { + get { return channels_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as Authenticate); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(Authenticate other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(ClientId, other.ClientId)) return false; + if (ClientName != other.ClientName) return false; + if (SecretKey != other.SecretKey) return false; + if(!channels_.Equals(other.channels_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (clientId_ != null) hash ^= ClientId.GetHashCode(); + if (ClientName.Length != 0) hash ^= ClientName.GetHashCode(); + if (SecretKey.Length != 0) hash ^= SecretKey.GetHashCode(); + hash ^= channels_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (clientId_ != null) { + output.WriteRawTag(10); + output.WriteMessage(ClientId); + } + if (ClientName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(ClientName); + } + if (SecretKey.Length != 0) { + output.WriteRawTag(26); + output.WriteString(SecretKey); + } + channels_.WriteTo(output, _repeated_channels_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (clientId_ != null) { + output.WriteRawTag(10); + output.WriteMessage(ClientId); + } + if (ClientName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(ClientName); + } + if (SecretKey.Length != 0) { + output.WriteRawTag(26); + output.WriteString(SecretKey); + } + channels_.WriteTo(ref output, _repeated_channels_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (clientId_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ClientId); + } + if (ClientName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ClientName); + } + if (SecretKey.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(SecretKey); + } + size += channels_.CalculateSize(_repeated_channels_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(Authenticate other) { + if (other == null) { + return; + } + if (other.clientId_ != null) { + if (clientId_ == null) { + ClientId = new global::CrystalConnector.Protocol.Messages.NamespacedName(); + } + ClientId.MergeFrom(other.ClientId); + } + if (other.ClientName.Length != 0) { + ClientName = other.ClientName; + } + if (other.SecretKey.Length != 0) { + SecretKey = other.SecretKey; + } + channels_.Add(other.channels_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (clientId_ == null) { + ClientId = new global::CrystalConnector.Protocol.Messages.NamespacedName(); + } + input.ReadMessage(ClientId); + break; + } + case 18: { + ClientName = input.ReadString(); + break; + } + case 26: { + SecretKey = input.ReadString(); + break; + } + case 34: { + channels_.AddEntriesFrom(input, _repeated_channels_codec); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + if (clientId_ == null) { + ClientId = new global::CrystalConnector.Protocol.Messages.NamespacedName(); + } + input.ReadMessage(ClientId); + break; + } + case 18: { + ClientName = input.ReadString(); + break; + } + case 26: { + SecretKey = input.ReadString(); + break; + } + case 34: { + channels_.AddEntriesFrom(ref input, _repeated_channels_codec); + break; + } + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Channel : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Channel()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::CrystalConnector.Protocol.Messages.MessagesReflection.Descriptor.MessageTypes[4]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Channel() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Channel(Channel other) : this() { + id_ = other.id_ != null ? other.id_.Clone() : null; + direction_ = other.direction_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Channel Clone() { + return new Channel(this); + } + + /// Field number for the "id" field. + public const int IdFieldNumber = 1; + private global::CrystalConnector.Protocol.Messages.NamespacedName id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::CrystalConnector.Protocol.Messages.NamespacedName Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "direction" field. + public const int DirectionFieldNumber = 2; + private global::CrystalConnector.Protocol.Messages.MessageDirection direction_ = global::CrystalConnector.Protocol.Messages.MessageDirection.None; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::CrystalConnector.Protocol.Messages.MessageDirection Direction { + get { return direction_; } + set { + direction_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as Channel); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(Channel other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Id, other.Id)) return false; + if (Direction != other.Direction) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (id_ != null) hash ^= Id.GetHashCode(); + if (Direction != global::CrystalConnector.Protocol.Messages.MessageDirection.None) hash ^= Direction.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (id_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Id); + } + if (Direction != global::CrystalConnector.Protocol.Messages.MessageDirection.None) { + output.WriteRawTag(16); + output.WriteEnum((int) Direction); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (id_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Id); + } + if (Direction != global::CrystalConnector.Protocol.Messages.MessageDirection.None) { + output.WriteRawTag(16); + output.WriteEnum((int) Direction); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (id_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Id); + } + if (Direction != global::CrystalConnector.Protocol.Messages.MessageDirection.None) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Direction); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(Channel other) { + if (other == null) { + return; + } + if (other.id_ != null) { + if (id_ == null) { + Id = new global::CrystalConnector.Protocol.Messages.NamespacedName(); + } + Id.MergeFrom(other.Id); + } + if (other.Direction != global::CrystalConnector.Protocol.Messages.MessageDirection.None) { + Direction = other.Direction; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (id_ == null) { + Id = new global::CrystalConnector.Protocol.Messages.NamespacedName(); + } + input.ReadMessage(Id); + break; + } + case 16: { + Direction = (global::CrystalConnector.Protocol.Messages.MessageDirection) input.ReadEnum(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + if (id_ == null) { + Id = new global::CrystalConnector.Protocol.Messages.NamespacedName(); + } + input.ReadMessage(Id); + break; + } + case 16: { + Direction = (global::CrystalConnector.Protocol.Messages.MessageDirection) input.ReadEnum(); + break; + } + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Publish : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Publish()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::CrystalConnector.Protocol.Messages.MessagesReflection.Descriptor.MessageTypes[5]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Publish() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Publish(Publish other) : this() { + channel_ = other.channel_ != null ? other.channel_.Clone() : null; + payload_ = other.payload_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Publish Clone() { + return new Publish(this); + } + + /// Field number for the "channel" field. + public const int ChannelFieldNumber = 1; + private global::CrystalConnector.Protocol.Messages.NamespacedName channel_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::CrystalConnector.Protocol.Messages.NamespacedName Channel { + get { return channel_; } + set { + channel_ = value; + } + } + + /// Field number for the "payload" field. + public const int PayloadFieldNumber = 2; + private string payload_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Payload { + get { return payload_; } + set { + payload_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as Publish); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(Publish other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Channel, other.Channel)) return false; + if (Payload != other.Payload) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (channel_ != null) hash ^= Channel.GetHashCode(); + if (Payload.Length != 0) hash ^= Payload.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (channel_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Channel); + } + if (Payload.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Payload); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (channel_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Channel); + } + if (Payload.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Payload); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (channel_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Channel); + } + if (Payload.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Payload); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(Publish other) { + if (other == null) { + return; + } + if (other.channel_ != null) { + if (channel_ == null) { + Channel = new global::CrystalConnector.Protocol.Messages.NamespacedName(); + } + Channel.MergeFrom(other.Channel); + } + if (other.Payload.Length != 0) { + Payload = other.Payload; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (channel_ == null) { + Channel = new global::CrystalConnector.Protocol.Messages.NamespacedName(); + } + input.ReadMessage(Channel); + break; + } + case 18: { + Payload = input.ReadString(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + if (channel_ == null) { + Channel = new global::CrystalConnector.Protocol.Messages.NamespacedName(); + } + input.ReadMessage(Channel); + break; + } + case 18: { + Payload = input.ReadString(); + break; + } + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Forward : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Forward()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::CrystalConnector.Protocol.Messages.MessagesReflection.Descriptor.MessageTypes[6]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Forward() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Forward(Forward other) : this() { + publisher_ = other.publisher_; + channel_ = other.channel_ != null ? other.channel_.Clone() : null; + payload_ = other.payload_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Forward Clone() { + return new Forward(this); + } + + /// Field number for the "publisher" field. + public const int PublisherFieldNumber = 1; + private string publisher_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Publisher { + get { return publisher_; } + set { + publisher_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "channel" field. + public const int ChannelFieldNumber = 2; + private global::CrystalConnector.Protocol.Messages.NamespacedName channel_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::CrystalConnector.Protocol.Messages.NamespacedName Channel { + get { return channel_; } + set { + channel_ = value; + } + } + + /// Field number for the "payload" field. + public const int PayloadFieldNumber = 3; + private string payload_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Payload { + get { return payload_; } + set { + payload_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as Forward); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(Forward other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Publisher != other.Publisher) return false; + if (!object.Equals(Channel, other.Channel)) return false; + if (Payload != other.Payload) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Publisher.Length != 0) hash ^= Publisher.GetHashCode(); + if (channel_ != null) hash ^= Channel.GetHashCode(); + if (Payload.Length != 0) hash ^= Payload.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Publisher.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Publisher); + } + if (channel_ != null) { + output.WriteRawTag(18); + output.WriteMessage(Channel); + } + if (Payload.Length != 0) { + output.WriteRawTag(26); + output.WriteString(Payload); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Publisher.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Publisher); + } + if (channel_ != null) { + output.WriteRawTag(18); + output.WriteMessage(Channel); + } + if (Payload.Length != 0) { + output.WriteRawTag(26); + output.WriteString(Payload); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Publisher.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Publisher); + } + if (channel_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Channel); + } + if (Payload.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Payload); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(Forward other) { + if (other == null) { + return; + } + if (other.Publisher.Length != 0) { + Publisher = other.Publisher; + } + if (other.channel_ != null) { + if (channel_ == null) { + Channel = new global::CrystalConnector.Protocol.Messages.NamespacedName(); + } + Channel.MergeFrom(other.Channel); + } + if (other.Payload.Length != 0) { + Payload = other.Payload; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Publisher = input.ReadString(); + break; + } + case 18: { + if (channel_ == null) { + Channel = new global::CrystalConnector.Protocol.Messages.NamespacedName(); + } + input.ReadMessage(Channel); + break; + } + case 26: { + Payload = input.ReadString(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + Publisher = input.ReadString(); + break; + } + case 18: { + if (channel_ == null) { + Channel = new global::CrystalConnector.Protocol.Messages.NamespacedName(); + } + input.ReadMessage(Channel); + break; + } + case 26: { + Payload = input.ReadString(); + break; + } + } + } + } + #endif + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/CrystalConnector.Protocol/Packets/C2S/AuthenticatePacket.cs b/CrystalConnector.Protocol/Packets/C2S/AuthenticatePacket.cs new file mode 100644 index 0000000..93cd228 --- /dev/null +++ b/CrystalConnector.Protocol/Packets/C2S/AuthenticatePacket.cs @@ -0,0 +1,53 @@ +using CrystalConnector.Protocol.Messages; +using Google.Protobuf; + +namespace CrystalConnector.Protocol.Packets.C2S; + +public class AuthenticatePacket : IPacket +{ + public NamespacedName ClientId { get; set; } + public string ClientName { get; set; } + public string Key { get; set; } + + public List Channels { get; } = []; + + public AuthenticatePacket(NamespacedName clientId, string clientName, string key, List channels) + { + ClientId = clientId; + ClientName = clientName; + Key = key; + Channels.AddRange(channels); + } + + public AuthenticatePacket(byte[] bytes) + { + Read(bytes); + } + + public AuthenticatePacket() + { + } + + public void Read(byte[] bytes) + { + var message = Authenticate.Parser.ParseFrom(bytes); + + ClientId = message.ClientId; + ClientName = message.ClientName; + Key = message.SecretKey; + Channels.AddRange(message.Channels); + } + + public byte[] Write() + { + var message = new Authenticate + { + ClientId = ClientId, + ClientName = ClientName, + SecretKey = Key + }; + message.Channels.AddRange(Channels); + + return message.ToByteArray(); + } +} \ No newline at end of file diff --git a/CrystalConnector.Protocol/Packets/C2S/PublishPacket.cs b/CrystalConnector.Protocol/Packets/C2S/PublishPacket.cs new file mode 100644 index 0000000..107110f --- /dev/null +++ b/CrystalConnector.Protocol/Packets/C2S/PublishPacket.cs @@ -0,0 +1,43 @@ +using CrystalConnector.Protocol.Messages; +using Google.Protobuf; + +namespace CrystalConnector.Protocol.Packets.C2S; + +public class PublishPacket : IPacket +{ + public NamespacedName Channel { get; set; } + public string Payload { get; set; } + + public PublishPacket(NamespacedName channel, string payload) + { + Channel = channel; + Payload = payload; + } + + public PublishPacket(byte[] bytes) + { + Read(bytes); + } + + public PublishPacket() + { + } + + public void Read(byte[] bytes) + { + var message = Publish.Parser.ParseFrom(bytes); + Channel = message.Channel; + Payload = message.Payload; + } + + public byte[] Write() + { + var message = new Publish + { + Channel = Channel, + Payload = Payload + }; + + return message.ToByteArray(); + } +} \ No newline at end of file diff --git a/CrystalConnector.Protocol/Packets/IPacket.cs b/CrystalConnector.Protocol/Packets/IPacket.cs new file mode 100644 index 0000000..8446e92 --- /dev/null +++ b/CrystalConnector.Protocol/Packets/IPacket.cs @@ -0,0 +1,50 @@ +using CrystalConnector.Protocol.Packets.C2S; +using CrystalConnector.Protocol.Packets.S2C; +using Google.Protobuf; + +namespace CrystalConnector.Protocol.Packets; + +public interface IPacket +{ + public void Read(byte[] bytes); + + public byte[] Write(); + + public static IPacket? From(byte[] data) + { + var result = TryForm(data); + if (result is not null) + { + return result; + } + + result = TryForm(data); + if (result is not null) + { + return result; + } + + result = TryForm(data); + if (result is not null) + { + return result; + } + + result = TryForm(data); + return result; + } + + private static IPacket? TryForm(byte[] data) where T : IPacket, new() + { + try + { + var message = new T(); + message.Read(data); + return message; + } + catch (InvalidProtocolBufferException ex) + { + return null; + } + } +} \ No newline at end of file diff --git a/CrystalConnector.Protocol/Packets/S2C/ForwardPacket.cs b/CrystalConnector.Protocol/Packets/S2C/ForwardPacket.cs new file mode 100644 index 0000000..42e8989 --- /dev/null +++ b/CrystalConnector.Protocol/Packets/S2C/ForwardPacket.cs @@ -0,0 +1,51 @@ +using CrystalConnector.Protocol.Messages; +using Google.Protobuf; + +namespace CrystalConnector.Protocol.Packets.S2C; + +public class ForwardPacket : IPacket +{ + public string Publisher { get; set; } + public NamespacedName Channel { get; set; } + public string Payload { get; set; } + + public ForwardPacket(string publisher, (string Namespace, string Name) channel, string payload) + { + Publisher = publisher; + Channel = new NamespacedName + { + Namespace = channel.Namespace, + Name = channel.Name + }; + Payload = payload; + } + + public ForwardPacket(byte[] bytes) + { + Read(bytes); + } + + public ForwardPacket() + { + } + + public void Read(byte[] bytes) + { + var message = Forward.Parser.ParseFrom(bytes); + Publisher = message.Publisher; + Channel = message.Channel; + Payload = message.Payload; + } + + public byte[] Write() + { + var message = new Forward + { + Publisher = Publisher, + Channel = Channel, + Payload = Payload + }; + + return message.ToByteArray(); + } +} \ No newline at end of file diff --git a/CrystalConnector.Protocol/Packets/S2C/ResultPacket.cs b/CrystalConnector.Protocol/Packets/S2C/ResultPacket.cs new file mode 100644 index 0000000..8ce3146 --- /dev/null +++ b/CrystalConnector.Protocol/Packets/S2C/ResultPacket.cs @@ -0,0 +1,59 @@ +using CrystalConnector.Protocol.Messages; +using Google.Protobuf; + +namespace CrystalConnector.Protocol.Packets.S2C; + +public class ResultPacket : IPacket +{ + public Result.ResultOneofCase ResultOneofCase { get; set; } + public Error? Error { get; set; } + + public ResultPacket() + { + ResultOneofCase = Result.ResultOneofCase.Successful; + } + + public ResultPacket(Error error) + { + ResultOneofCase = Result.ResultOneofCase.Error; + Error = error; + } + + public ResultPacket(byte[] bytes) + { + Read(bytes); + } + + public void Read(byte[] bytes) + { + var message = Result.Parser.ParseFrom(bytes); + ResultOneofCase = message.ResultCase; + + if (message.HasError) + { + Error = message.Error; + } + } + + public byte[] Write() + { + var message = ResultOneofCase switch + { + Result.ResultOneofCase.None => new Result + { + Error = Messages.Error.Unknown + }, + Result.ResultOneofCase.Successful => new Result + { + Successful = new Successful() + }, + Result.ResultOneofCase.Error => new Result + { + Error = Error!.Value + }, + _ => throw new ArgumentOutOfRangeException() + }; + + return message.ToByteArray(); + } +} \ No newline at end of file diff --git a/CrystalConnector.Protocol/README.md b/CrystalConnector.Protocol/README.md new file mode 100644 index 0000000..25da0f4 --- /dev/null +++ b/CrystalConnector.Protocol/README.md @@ -0,0 +1,7 @@ +# CrystalConnector.Protocol + +## Generate Proto file + +```shell +protoc.exe --proto_path=proto --csharp_out=Messages proto\messages.proto +``` diff --git a/CrystalConnector.Protocol/Utilities/PacketHelperExtensions.cs b/CrystalConnector.Protocol/Utilities/PacketHelperExtensions.cs new file mode 100644 index 0000000..f781221 --- /dev/null +++ b/CrystalConnector.Protocol/Utilities/PacketHelperExtensions.cs @@ -0,0 +1,25 @@ +using CrystalConnector.Protocol.Messages; + +namespace CrystalConnector.Protocol.Utilities; + +public static class PacketHelperExtensions +{ + public static (string Namespace, string Name) ToTuple(this NamespacedName name) + { + return (name.Namespace, name.Name); + } + + public static NamespacedName ToName(this (string Namespace, string Name) name) + { + return new NamespacedName + { + Namespace = name.Namespace, + Name = name.Name + }; + } + + public static string ToIdString(this (string Namespace, string Name) name) + { + return $"{name.Namespace}:{name.Name}"; + } +} \ No newline at end of file diff --git a/CrystalConnector.Protocol/proto/messages.proto b/CrystalConnector.Protocol/proto/messages.proto new file mode 100644 index 0000000..a8c9e94 --- /dev/null +++ b/CrystalConnector.Protocol/proto/messages.proto @@ -0,0 +1,59 @@ +syntax = "proto3"; +option csharp_namespace = "CrystalConnector.Protocol.Messages"; + +package CrystalConnector; + +message NamespacedName { + string namespace = 1; + string name = 2; +} + +enum MessageDirection { + NONE = 0; + INCOMING = 1; + OUTGOING = 2; + ALL = 3; +} + +message Successful { +} + +enum Error { + UNKNOWN = 0; + AUTHENTICATED = 1; + NAME_EXISTS = 2; + UNAUTHENTICATED = 3; + UNREGISTERED_CHANNEL = 4; + INTERNAL = 5; +} + +message Result { + oneof result { + Successful successful = 1; + Error error = 2; + } +} + +message Authenticate { + NamespacedName client_id = 1; + string client_name = 2; + string secret_key = 3; + + repeated Channel channels = 4; +} + +message Channel { + NamespacedName id = 1; + MessageDirection direction = 2; +} + +message Publish { + NamespacedName channel = 1; + string payload = 2; +} + +message Forward { + string publisher = 1; + NamespacedName channel = 2; + string payload = 3; +} diff --git a/CrystalConnector.sln b/CrystalConnector.sln index c0f31b2..1d1c5ab 100644 --- a/CrystalConnector.sln +++ b/CrystalConnector.sln @@ -4,6 +4,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrystalConnector", "Crystal EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConnectorTest", "ConnectorTest\ConnectorTest.csproj", "{7DA8728D-146A-4E85-AEB8-A48130836CF7}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrystalConnector.Protocol", "CrystalConnector.Protocol\CrystalConnector.Protocol.csproj", "{1769D402-129D-46D2-9347-70F3E875FE7B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -18,5 +20,9 @@ Global {7DA8728D-146A-4E85-AEB8-A48130836CF7}.Debug|Any CPU.Build.0 = Debug|Any CPU {7DA8728D-146A-4E85-AEB8-A48130836CF7}.Release|Any CPU.ActiveCfg = Release|Any CPU {7DA8728D-146A-4E85-AEB8-A48130836CF7}.Release|Any CPU.Build.0 = Release|Any CPU + {1769D402-129D-46D2-9347-70F3E875FE7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1769D402-129D-46D2-9347-70F3E875FE7B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1769D402-129D-46D2-9347-70F3E875FE7B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1769D402-129D-46D2-9347-70F3E875FE7B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/CrystalConnector/Connector/MessageChannel.cs b/CrystalConnector/Connector/MessageChannel.cs index 957082b..f0aa82f 100644 --- a/CrystalConnector/Connector/MessageChannel.cs +++ b/CrystalConnector/Connector/MessageChannel.cs @@ -1,8 +1,10 @@ -namespace CrystalConnector.Connector; +using CrystalConnector.Protocol.Messages; + +namespace CrystalConnector.Connector; public class MessageChannel { - public required string Id { get; set; } + public required (string Namespace, string Name) Id { get; set; } public required MessageDirection Direction { get; set; } } \ No newline at end of file diff --git a/CrystalConnector/Connector/MessageDirection.cs b/CrystalConnector/Connector/MessageDirection.cs deleted file mode 100644 index 32fab28..0000000 --- a/CrystalConnector/Connector/MessageDirection.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace CrystalConnector.Connector; - -[Flags] -public enum MessageDirection -{ - None = 0, - Incoming = 1, - Outgoing = 2, - All = Incoming | Outgoing -} \ No newline at end of file diff --git a/CrystalConnector/Connector/Packet/IPacket.cs b/CrystalConnector/Connector/Packet/IPacket.cs deleted file mode 100644 index 8a85d43..0000000 --- a/CrystalConnector/Connector/Packet/IPacket.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Formats.Cbor; - -namespace CrystalConnector.Connector.Packet; - -public interface IPacket -{ - public void Write(CborWriter writer) - { - } - - public void Read(CborReader reader) - { - } -} \ No newline at end of file diff --git a/CrystalConnector/Connector/Packet/S2C/PacketS2C.cs b/CrystalConnector/Connector/Packet/S2C/PacketS2C.cs deleted file mode 100644 index d044808..0000000 --- a/CrystalConnector/Connector/Packet/S2C/PacketS2C.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Formats.Cbor; - -namespace CrystalConnector.Connector.Packet.S2C; - -public abstract class PacketS2C : IPacket -{ - public void Write(CborWriter writer) - { - writer.WriteStartArray(null); - WriteData(writer); - writer.WriteEndArray(); - } - - protected abstract void WriteData(CborWriter writer); -} \ No newline at end of file diff --git a/CrystalConnector/Connector/Packet/S2C/S2CAuthenticatedPacket.cs b/CrystalConnector/Connector/Packet/S2C/S2CAuthenticatedPacket.cs deleted file mode 100644 index a5e6a55..0000000 --- a/CrystalConnector/Connector/Packet/S2C/S2CAuthenticatedPacket.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Formats.Cbor; -using CrystalConnector.Handlers; - -namespace CrystalConnector.Connector.Packet.S2C; - -public class S2CAuthenticatedPacket : PacketS2C -{ - protected override void WriteData(CborWriter writer) - { - writer.WriteTextString(HandlerConstants.ResponseErrorAuthenticated); - } -} \ No newline at end of file diff --git a/CrystalConnector/Connector/Packet/S2C/S2CForwardMessagePacket.cs b/CrystalConnector/Connector/Packet/S2C/S2CForwardMessagePacket.cs deleted file mode 100644 index a24cacf..0000000 --- a/CrystalConnector/Connector/Packet/S2C/S2CForwardMessagePacket.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Formats.Cbor; -using CrystalConnector.Handlers; - -namespace CrystalConnector.Connector.Packet.S2C; - -public class S2CForwardMessagePacket : PacketS2C -{ - private string Origin { get; } - private string ChannelId { get; } - private byte[] Payload { get; } - - public S2CForwardMessagePacket(string origin, string channelId, byte[] payload) - { - Origin = origin; - ChannelId = channelId; - Payload = payload; - } - - protected override void WriteData(CborWriter writer) - { - writer.WriteTextString(HandlerConstants.ResponseForward); - writer.WriteTextString(Origin); - writer.WriteTextString(ChannelId); - writer.WriteByteString(Payload); - } -} \ No newline at end of file diff --git a/CrystalConnector/Connector/Packet/S2C/S2CMalformedPacket.cs b/CrystalConnector/Connector/Packet/S2C/S2CMalformedPacket.cs deleted file mode 100644 index b46b4ff..0000000 --- a/CrystalConnector/Connector/Packet/S2C/S2CMalformedPacket.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Formats.Cbor; -using CrystalConnector.Handlers; - -namespace CrystalConnector.Connector.Packet.S2C; - -public class S2CMalformedPacket : PacketS2C -{ - protected override void WriteData(CborWriter writer) - { - writer.WriteTextString(HandlerConstants.ResponseErrorMalformed); - } -} \ No newline at end of file diff --git a/CrystalConnector/Connector/Packet/S2C/S2CNameAuthenticatedPacket.cs b/CrystalConnector/Connector/Packet/S2C/S2CNameAuthenticatedPacket.cs deleted file mode 100644 index cabfa26..0000000 --- a/CrystalConnector/Connector/Packet/S2C/S2CNameAuthenticatedPacket.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Formats.Cbor; -using CrystalConnector.Handlers; - -namespace CrystalConnector.Connector.Packet.S2C; - -public class S2CNameAuthenticatedPacket : PacketS2C -{ - protected override void WriteData(CborWriter writer) - { - writer.WriteTextString(HandlerConstants.ResponseErrorNameAuthenticated); - } -} \ No newline at end of file diff --git a/CrystalConnector/Connector/Packet/S2C/S2CSuccessfulPacket.cs b/CrystalConnector/Connector/Packet/S2C/S2CSuccessfulPacket.cs deleted file mode 100644 index 358856b..0000000 --- a/CrystalConnector/Connector/Packet/S2C/S2CSuccessfulPacket.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Formats.Cbor; -using CrystalConnector.Handlers; - -namespace CrystalConnector.Connector.Packet.S2C; - -public class S2CSuccessfulPacket : PacketS2C -{ - protected override void WriteData(CborWriter writer) - { - writer.WriteTextString(HandlerConstants.ResponseSuccessful); - } -} \ No newline at end of file diff --git a/CrystalConnector/Connector/Packet/S2C/S2CUnauthenticatedPacket.cs b/CrystalConnector/Connector/Packet/S2C/S2CUnauthenticatedPacket.cs deleted file mode 100644 index 8525ea6..0000000 --- a/CrystalConnector/Connector/Packet/S2C/S2CUnauthenticatedPacket.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Formats.Cbor; -using CrystalConnector.Handlers; - -namespace CrystalConnector.Connector.Packet.S2C; - -public class S2CUnauthenticatedPacket : PacketS2C -{ - protected override void WriteData(CborWriter writer) - { - writer.WriteTextString(HandlerConstants.ResponseErrorUnauthenticated); - } -} \ No newline at end of file diff --git a/CrystalConnector/Connector/Packet/S2C/S2CUndefinedDirectionPacket.cs b/CrystalConnector/Connector/Packet/S2C/S2CUndefinedDirectionPacket.cs deleted file mode 100644 index 1f3dff7..0000000 --- a/CrystalConnector/Connector/Packet/S2C/S2CUndefinedDirectionPacket.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Formats.Cbor; -using CrystalConnector.Handlers; - -namespace CrystalConnector.Connector.Packet.S2C; - -public class S2CUndefinedDirectionPacket : PacketS2C -{ - protected override void WriteData(CborWriter writer) - { - writer.WriteTextString(HandlerConstants.ResponseErrorUndefinedDirection); - } -} \ No newline at end of file diff --git a/CrystalConnector/Connector/Packet/S2C/S2CUnknownPacket.cs b/CrystalConnector/Connector/Packet/S2C/S2CUnknownPacket.cs deleted file mode 100644 index 9f818ae..0000000 --- a/CrystalConnector/Connector/Packet/S2C/S2CUnknownPacket.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Formats.Cbor; -using CrystalConnector.Handlers; - -namespace CrystalConnector.Connector.Packet.S2C; - -public class S2CUnknownPacket : PacketS2C -{ - protected override void WriteData(CborWriter writer) - { - writer.WriteTextString(HandlerConstants.ResponseErrorUnknownPacket); - } -} \ No newline at end of file diff --git a/CrystalConnector/Connector/Packet/S2C/S2CUnregisteredDirectionPacket.cs b/CrystalConnector/Connector/Packet/S2C/S2CUnregisteredDirectionPacket.cs deleted file mode 100644 index 3c4bbad..0000000 --- a/CrystalConnector/Connector/Packet/S2C/S2CUnregisteredDirectionPacket.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Formats.Cbor; -using CrystalConnector.Handlers; - -namespace CrystalConnector.Connector.Packet.S2C; - -public class S2CUnregisteredDirectionPacket : PacketS2C -{ - protected override void WriteData(CborWriter writer) - { - writer.WriteTextString(HandlerConstants.ResponseErrorUnregisteredDirection); - } -} \ No newline at end of file diff --git a/CrystalConnector/Connector/WebSocketConnectionManager.cs b/CrystalConnector/Connector/WebSocketConnectionManager.cs index 0d774e7..fe074bd 100644 --- a/CrystalConnector/Connector/WebSocketConnectionManager.cs +++ b/CrystalConnector/Connector/WebSocketConnectionManager.cs @@ -1,5 +1,6 @@ using System.Net.WebSockets; -using CrystalConnector.Connector.Packet.S2C; +using CrystalConnector.Protocol.Messages; +using CrystalConnector.Protocol.Packets.S2C; using CrystalConnector.Utilities; namespace CrystalConnector.Connector; @@ -8,11 +9,11 @@ public class WebSocketConnectionManager { internal static Dictionary Info { get; } = new(); - public static bool HaveNameRegistered(string name) + public static bool HaveClientRegistered((string Namespace, string Name) client) { - foreach (var (webSocket, info) in Info) + foreach (var (_, info) in Info) { - if (info.Name == name) + if (info.ClientId == client) { return true; } @@ -23,21 +24,20 @@ public class WebSocketConnectionManager public static void DisconnectAll() { - foreach (var (webSocket, info) in Info) + foreach (var (webSocket, _) in Info) { webSocket.Disconnect(); } } - public static async Task Broadcast(string origin, string channelId, byte[] payload, bool allowUnauthenticated = false) + public static async Task Broadcast(string origin, (string Namespace, string Name) channel, string payload, bool allowUnauthenticated = false) { - var packet = new S2CForwardMessagePacket(origin, channelId, payload); + var packet = new ForwardPacket(origin, channel, payload); foreach (var (webSocket, info) in Info) { - if (info.RegisteredChannels.TryGetValue(channelId, out var value) - && value.Direction.HasFlag(MessageDirection.Incoming) - && info.Name != origin) + if (info.RegisteredChannels.TryGetValue(channel, out var value) + && value.Direction is MessageDirection.Incoming or MessageDirection.All) { if (webSocket.State != WebSocketState.Open) { @@ -45,7 +45,7 @@ public class WebSocketConnectionManager continue; } - await webSocket.Send(packet); + await webSocket.Send(packet.Write()); } } } diff --git a/CrystalConnector/CrystalConnector.csproj b/CrystalConnector/CrystalConnector.csproj index 408cc6c..e2852d7 100644 --- a/CrystalConnector/CrystalConnector.csproj +++ b/CrystalConnector/CrystalConnector.csproj @@ -8,14 +8,13 @@ - - - - - + + + + + - @@ -31,6 +30,14 @@ + + + + + + + + diff --git a/CrystalConnector/Handlers/WebSocketHandler.cs b/CrystalConnector/Handlers/WebSocketHandler.cs index 5d65048..bc0f700 100644 --- a/CrystalConnector/Handlers/WebSocketHandler.cs +++ b/CrystalConnector/Handlers/WebSocketHandler.cs @@ -1,9 +1,11 @@ -using System.Formats.Cbor; -using System.Net.WebSockets; +using System.Net.WebSockets; using CrystalConnector.Configs; using CrystalConnector.Connector; -using CrystalConnector.Connector.Packet; -using CrystalConnector.Connector.Packet.S2C; +using CrystalConnector.Protocol.Messages; +using CrystalConnector.Protocol.Packets; +using CrystalConnector.Protocol.Packets.C2S; +using CrystalConnector.Protocol.Packets.S2C; +using CrystalConnector.Protocol.Utilities; using CrystalConnector.Utilities; using Microsoft.Extensions.Logging; @@ -21,111 +23,96 @@ public class WebSocketHandler Logger = logger; } - public async Task Handle(WebSocket webSocket, CborReader reader) + public async Task Handle(WebSocket webSocket, byte[] data) { - reader.ReadStartArray(); - - // Todo: qyl27: Use C2SPacketReader. - var type = reader.ReadTextString(); - if (type == HandlerConstants.OperationAuthenticate) + var packet = IPacket.From(data); + switch (packet) { - if (!webSocket.GetConnectionInfo().Authenticated) + case AuthenticatePacket authenticatePacket: { - var secret = reader.ReadTextString(); - var name = reader.ReadTextString(); - if (secret == Config.GetSecretKey()) + var clientId = (authenticatePacket.ClientId.Namespace, authenticatePacket.ClientId.Name); + + if (authenticatePacket.Key == Config.GetSecretKey()) { - if (WebSocketConnectionManager.HaveNameRegistered(name)) + if (WebSocketConnectionManager.HaveClientRegistered(clientId)) { - Logger.LogInformation("Client {Id} tried authorize with name {Name}, but it is already authorized!", webSocket.GetConnectionInfo().Id, name); - return new S2CNameAuthenticatedPacket(); + Logger.LogInformation("Client {Id} tried authorize with name {Name}, but it is already authorized!", clientId.ToIdString(), authenticatePacket.ClientName); + return new ResultPacket(Error.NameExists); } - Logger.LogInformation("Client {Name}({Id}) authorized", name, webSocket.GetConnectionInfo().Id); - webSocket.GetConnectionInfo().Authenticated = true; - webSocket.GetConnectionInfo().Name = name; - return new S2CSuccessfulPacket(); + Logger.LogInformation("Client {Name}({Id}) authorized", authenticatePacket.ClientName, clientId.ToIdString()); + + var connectionInfo = webSocket.GetConnectionInfo(); + + connectionInfo.Authenticated = true; + connectionInfo.ClientId = clientId; + connectionInfo.Name = authenticatePacket.ClientName; + + var channels = connectionInfo.RegisteredChannels; + + foreach (var channel in authenticatePacket.Channels) + { + var id = channel.Id.ToTuple(); + if (channels.TryGetValue(id, out var chan)) + { + chan.Direction = channel.Direction; + } + else + { + channels.Add(id, new MessageChannel + { + Id = id, + Direction = channel.Direction + }); + } + } + + return new ResultPacket(); } - Logger.LogWarning("Client {Name}({Id}) auth failed with wrong key!", name, webSocket.GetConnectionInfo().Id); - return new S2CUnauthenticatedPacket(); + Logger.LogWarning("Client {Name}({Id}) auth failed with wrong key!", authenticatePacket.ClientName, clientId.ToIdString()); + return new ResultPacket(Error.Unauthenticated); } - - return new S2CAuthenticatedPacket(); - } - - if (type == HandlerConstants.OperationRegisterChannel) - { - if (!webSocket.GetConnectionInfo().Authenticated) + case PublishPacket publishPacket: { - Logger.LogWarning("Client {Id} is unauthenticated!", webSocket.GetConnectionInfo().Id); - return new S2CUnauthenticatedPacket(); - } + var connectionInfo = webSocket.GetConnectionInfo(); + var id = publishPacket.Channel.ToTuple(); - var channelId = reader.ReadTextString(); - var directionValue = reader.ReadInt32(); - - if (!Enum.IsDefined(typeof(MessageDirection), directionValue)) - { - Logger.LogWarning("Client {Name}({Id}) tried to register channel {Channel} with undefined direction {Direction}!", - webSocket.GetConnectionInfo().Name, webSocket.GetConnectionInfo().Id, channelId, directionValue); - return new S2CUndefinedDirectionPacket(); - } - - var direction = (MessageDirection)directionValue; - - var channels = webSocket.GetConnectionInfo().RegisteredChannels; - if (channels.TryGetValue(channelId, out var channel)) - { - channel.Direction |= direction; - } - else - { - webSocket.GetConnectionInfo().RegisteredChannels.Add(channelId, new MessageChannel + if (!connectionInfo.Authenticated) { - Id = channelId, - Direction = direction - }); - } - - Logger.LogInformation("Client {Name}({Id}) registered channel {Channel}(Direction: {Direction})", - webSocket.GetConnectionInfo().Name, webSocket.GetConnectionInfo().Id, channelId, direction.ToString()); - return new S2CSuccessfulPacket(); - } + return new ResultPacket(Error.Unauthenticated); + } + + if (!connectionInfo.RegisteredChannels.TryGetValue(id, out var registered) + || registered.Direction == MessageDirection.Outgoing + || registered.Direction == MessageDirection.All) + { + Logger.LogWarning("Channel {Channel}(Direction: {Direction}) have not been registered by Client {Name}({Id})", + id.ToIdString(), MessageDirection.Outgoing, webSocket.GetConnectionInfo().Name, webSocket.GetConnectionInfo().Id); + return new ResultPacket(Error.UnregisteredChannel); + } - if (type == HandlerConstants.OperationPublish) - { - var channelId = reader.ReadTextString(); - var payload = reader.ReadByteString(); - - if (!webSocket.GetConnectionInfo().RegisteredChannels.TryGetValue(channelId, out var value) - || !value.Direction.HasFlag(MessageDirection.Outgoing)) - { - Logger.LogWarning("Channel {Channel}(Direction: {Direction}) have not been registered by Client {Name}({Id})", - channelId, MessageDirection.Outgoing, webSocket.GetConnectionInfo().Name, webSocket.GetConnectionInfo().Id); - return new S2CUnregisteredDirectionPacket(); - } - - try - { var name = webSocket.GetConnectionInfo().Name; - await WebSocketConnectionManager.Broadcast(name!, channelId, payload); + await WebSocketConnectionManager.Broadcast(name!, id, publishPacket.Payload); if (Config.IsDebug()) { Logger.LogDebug("Client {Name}({Id}) send data in {Channel}: {Data}", - name, webSocket.GetConnectionInfo().Id, channelId, Convert.ToBase64String(payload)); + name, webSocket.GetConnectionInfo().ClientId!.Value.ToIdString(), id.ToIdString(), publishPacket.Payload); } - return new S2CSuccessfulPacket(); + + return new ResultPacket(); } - catch (Exception ex) + case ForwardPacket forwardPacket: { - Logger.LogError(ex, "Send error!"); + break; + } + case ResultPacket resultPacket: + { + break; } } - - reader.ReadEndArray(); - return new S2CUnknownPacket(); + return new ResultPacket(); } } \ No newline at end of file diff --git a/CrystalConnector/Utilities/WebSocketConnectionInfo.cs b/CrystalConnector/Utilities/WebSocketConnectionInfo.cs index 8f2d9bb..2e210d2 100644 --- a/CrystalConnector/Utilities/WebSocketConnectionInfo.cs +++ b/CrystalConnector/Utilities/WebSocketConnectionInfo.cs @@ -13,7 +13,9 @@ public class WebSocketConnectionInfo public string? Name { get; set; } + public (string Namespace, string Name)? ClientId { get; set; } + public bool Authenticated { get; set; } = false; - public Dictionary RegisteredChannels { get; } = new(); + public Dictionary<(string Namespace, string Name), MessageChannel> RegisteredChannels { get; } = new(); } \ No newline at end of file diff --git a/CrystalConnector/Utilities/WebSocketExtension.cs b/CrystalConnector/Utilities/WebSocketExtension.cs index 64c101f..3414c29 100644 --- a/CrystalConnector/Utilities/WebSocketExtension.cs +++ b/CrystalConnector/Utilities/WebSocketExtension.cs @@ -1,8 +1,7 @@ -using System.Formats.Cbor; -using System.Net; +using System.Net; using System.Net.WebSockets; using CrystalConnector.Connector; -using CrystalConnector.Connector.Packet.S2C; +using CrystalConnector.Protocol.Packets; namespace CrystalConnector.Utilities; @@ -34,11 +33,10 @@ public static class WebSocketExtension Purge(webSocket); } - public static async Task Send(this WebSocket webSocket, PacketS2C packet) + public static async Task Send(this WebSocket webSocket, IPacket packet) { - var writer = new CborWriter(); - packet.Write(writer); - await webSocket.Send(writer.Encode()); + var bytes = packet.Write(); + await webSocket.Send(bytes); } public static async Task Send(this WebSocket webSocket, byte[] data) diff --git a/CrystalConnector/WebSockets/WebSocketManager.cs b/CrystalConnector/WebSockets/WebSocketManager.cs index c19796e..3790997 100644 --- a/CrystalConnector/WebSockets/WebSocketManager.cs +++ b/CrystalConnector/WebSockets/WebSocketManager.cs @@ -1,9 +1,9 @@ -using System.Formats.Cbor; -using System.Net; +using System.Net; using System.Net.WebSockets; using CrystalConnector.Configs; -using CrystalConnector.Connector.Packet.S2C; using CrystalConnector.Handlers; +using CrystalConnector.Protocol.Messages; +using CrystalConnector.Protocol.Packets.S2C; using CrystalConnector.Utilities; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; @@ -39,35 +39,21 @@ public class WebSocketManager : IWebSocketManager while (!receiveResult.CloseStatus.HasValue) { - var reader = new CborReader(new ReadOnlyMemory(buffer, 0, receiveResult.Count)); + var bytes = new ReadOnlyMemory(buffer, 0, receiveResult.Count); try { - var resultPacket = await Handler.Handle(webSocket, reader); + var resultPacket = await Handler.Handle(webSocket, bytes.ToArray()); await webSocket.Send(resultPacket); } - catch (CborContentException ex) - { - if (Config.IsDebug()) - { - Logger.LogWarning(ex, "Unknown message!"); - } - - await webSocket.Send(new S2CUnknownPacket()); - } - catch (InvalidOperationException ex) + catch (Exception ex) { if (Config.IsDebug()) { Logger.LogWarning(ex, "Malformed message!"); } - await webSocket.Send(new S2CMalformedPacket()); - } - catch (MessageException ex) - { - Logger.LogWarning(ex, "Why do that?"); - await webSocket.Send(new S2CMalformedPacket()); + await webSocket.Send(new ResultPacket(Error.Internal)); } try diff --git a/README.md b/README.md index 7d782bf..376275c 100644 --- a/README.md +++ b/README.md @@ -5,54 +5,31 @@ ## 传输协议 -版本:**V1.0.1(2023.9.18 更新)** +版本:**V2.0(2024.1.9 更新)** -水晶互联采用 WebSocket 进行消息传输,使用 CBOR 进行消息编码。 +水晶互联采用 WebSocket 进行消息传输,使用 Protobuf 进行消息编码。 -为了贴近 Guava 中 `ByteArrayDataInput` / `ByteArrayDataOutput` 的使用习惯,规定以单层基本类型的数组形式使用 CBOR 。(Todo:支持更复杂的结构。) - -参考代码: - -```c# -var writer = new CborWriter(); -writer.WriteStartArray(null); // 不定长数组 -// 消息序列化 -writer.WriteEndArray(); - -var reader = new CborReader(buffer); -reader.ReadStartArray(); -// 消息反序列化 -reader.ReadEndArray(); -``` - - - -### 文档约定 - -文档中的代码块,以行首的 `>` 代表客户端向服务端传输的消息;以行首的 `<` 代表服务端向客户端传输的消息。其后的消息以纯文本形式发送。如需某一端进行操作,在尖括号后以 `!` 标志体现。 - -服务端是指水晶互联的服务端,一个 C# 程序用来完成消息转发操作。 - -客户端是指所有通过 WebSocket 连接服务端的消息提供或消费者。 - -文档中使用尖括号对 `` 代表必填参数,方括号对 `[type:Name]` 代表可选参数。 `type` 是参数类型,如 `string` 、 `int` 等。 `Name` 是参数名,不在具体传输过程中体现,是方便开发人员记忆的名称。 +Proto 文件见 `CrystalConnector.Protocol/proto` 目录。 ### 协议约定 +传输的所有的字符串都是 UTF-8 编码。 + **服务端不会主动断开客户端的链接。** -当客户端操作成功时,服务端必定响应: -``` -< Successful -``` -当操作失败时,服务端需要指出(供机器处理的)原因: +#### 服务端响应 -``` -< +```protobuf +message Result { + oneof result { + Successful successful = 1; + Error error = 2; + } +} ``` @@ -61,15 +38,14 @@ reader.ReadEndArray(); 目前已定义的原因列表如下: -| 原因 | 说明 | -| --------------------- | ------------------------------------------------------------ | -| Unknown | 服务端无法处理客户端所发送的数据包,产生此错误。 | -| Malformed | 客户端发给服务端的信息是 CBOR 数据包,但无法按协议规则解析时,产生此错误。 | -| Authenticated | 当已认证客户端再次申请认证时,产生此错误。 | -| NameAuthenticated | 当某个客户端尝试以一个已认证的客户端身份进行认证时,产生此错误。 | -| Unauthenticated | 当客户端认证失败或者未经认证的客户端执行除认证外的其他操作时,产生此错误。 | -| UndefinedDirection | 当客户端尝试注册的频道信息方向超过了信息方向枚举允许的值时,产生此错误。 | -| UnregisteredDirection | 当客户端未注册外发某个频道的信息,却想要发布对应频道信息时,产生此错误。 | +| 原因 | 说明 | +| ------------------- | ------------------------------------------------------------ | +| Unknown | 服务端无法理解客户端的需求,产生此错误。 | +| Authenticated | 当已认证客户端再次申请认证时,产生此错误。 | +| NameExists | 当某个客户端尝试以一个已认证的客户端身份进行认证时,产生此错误。 | +| Unauthenticated | 当客户端认证失败或者未经认证的客户端执行除认证外的其他操作时,产生此错误。 | +| UnregisteredChannel | 当客户端未注册外发某个频道的信息,却想要发布对应频道信息时,产生此错误。 | +| Internal | 服务端由于内部问题,无法完整处理客户端的请求时,产生此错误。 | @@ -77,24 +53,22 @@ reader.ReadEndArray(); ##### 消息方向(MessageDirection) -``` +```protobuf enum MessageDirection { - None = 0, - Incoming = 1, - Outgoing = 2, - All = Incoming | Outgoing // 3 + NONE = 0; + INCOMING = 1; + OUTGOING = 2; + ALL = 3; } ``` `Incoming` 代表服务端向客户端转发的信息,`Outgoing` 代表客户端向服务端发布的信息,`All` 代表双向通信。 -注意:**在 WebSocket 传输过程中,枚举值使用对应的 Int 值进行传输。** - ##### ID 字符串(IdString) -一个字符串,满足正则表达式 `/a-z0-9_/` 。 +一个字符串,满足正则表达式 `/^[a-z0-9_]+$/` 。 例如,以下每一行都是合法的 ID 字符串: @@ -114,10 +88,13 @@ Hello, world! -##### 频道 ID (ChannelId) +##### 命名空间名 (NamespacedName) -``` -: +```protobuf +message NamespacedName { + string namespace = 1; + string name = 2; +} ``` Namespace 可以是注册这一频道的项目名称,尽量避免冲突。 @@ -130,54 +107,52 @@ ChannelName 是自定义的频道名。 ### 协议操作 -#### 认证客户端 +#### 认证客户端并注册频道 -为了防止未授权的传输,水晶互联需要一个 SecretKey 来信任客户端,它由服务端配置文件指定。(这个设计没有任何安全性的保证,请保证不在公网中使用它。) +为了防止未授权的传输,水晶互联需要一个 Secret Key 来信任客户端,它由服务端配置文件指定。(这个设计没有任何安全性的保证,请保证不在公网中使用它。) -请求: +为了降低处理压力,客户端需要在启动时向服务端注册频道及所需的消息方向。否则将无法发送或接收消息。 -``` -> Authenticate -> -> -``` +```protobuf +message Authenticate { + NamespacedName client_id = 1; + string client_name = 2; + string secret_key = 3; + + repeated Channel channels = 4; +} - - -#### 注册频道 - -为了降低处理压力,客户端需要在启动时向服务端注册频道及消息方向。否则将无法发送或接收消息。 - -请求: - -``` -> Register -> -> +message Channel { + NamespacedName id = 1; + MessageDirection direction = 2; +} ``` #### 发布消息 -请求: +Payload 是一个字符串,会被原样发给所有注册了该频道 `Incoming` 方向消息的客户端。 -``` -> Publish -> -> +```protobuf +message Publish { + NamespacedName channel = 1; + string payload = 2; +} ``` -Payload 是一个字节型数组,会被原样发给其他的客户端(不会发回给自身)。 -当服务端收到发布消息的请求时,所有注册了该频道的客户端都会收到如下信息: -``` -< Forward -< -< -< +#### 接收消息 + +当服务端收到发布消息的请求时,所有注册了该频道的客户端都会收到转发的信息。 + +```protobuf +message Forward { + string publisher = 1; + NamespacedName channel = 2; + string payload = 3; +} ``` -PublisherName 是先前注册这一频道的客户端。 - +`publisher` 是注册客户端时的 `client_name` 。