From 826cfbee3109e967c6c4564098d86b96e3ffc995 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Sat, 21 Mar 2026 11:37:39 -0400 Subject: [PATCH] feat: add sitestream.proto definition and generated gRPC stubs Define the SiteStreamService proto for real-time instance event streaming (attribute value changes, alarm state changes) from site nodes to central. Add pre-generated C# stubs following the existing LmxProxy pattern, gRPC NuGet packages with FrameworkReference for ASP.NET Core server types, and proto roundtrip tests. --- .../Protos/sitestream.proto | 52 + .../ScadaLink.Communication.csproj | 11 +- .../SiteStreamGrpc/Sitestream.cs | 1396 +++++++++++++++++ .../SiteStreamGrpc/SitestreamGrpc.cs | 145 ++ .../Grpc/ProtoRoundtripTests.cs | 129 ++ 5 files changed, 1729 insertions(+), 4 deletions(-) create mode 100644 src/ScadaLink.Communication/Protos/sitestream.proto create mode 100644 src/ScadaLink.Communication/SiteStreamGrpc/Sitestream.cs create mode 100644 src/ScadaLink.Communication/SiteStreamGrpc/SitestreamGrpc.cs create mode 100644 tests/ScadaLink.Communication.Tests/Grpc/ProtoRoundtripTests.cs diff --git a/src/ScadaLink.Communication/Protos/sitestream.proto b/src/ScadaLink.Communication/Protos/sitestream.proto new file mode 100644 index 0000000..0d0ebe0 --- /dev/null +++ b/src/ScadaLink.Communication/Protos/sitestream.proto @@ -0,0 +1,52 @@ +syntax = "proto3"; +option csharp_namespace = "ScadaLink.Communication.Grpc"; +package sitestream; + +import "google/protobuf/timestamp.proto"; + +service SiteStreamService { + rpc SubscribeInstance(InstanceStreamRequest) returns (stream SiteStreamEvent); +} + +message InstanceStreamRequest { + string correlation_id = 1; + string instance_unique_name = 2; +} + +message SiteStreamEvent { + string correlation_id = 1; + oneof event { + AttributeValueUpdate attribute_changed = 2; + AlarmStateUpdate alarm_changed = 3; + } +} + +enum Quality { + QUALITY_UNSPECIFIED = 0; + QUALITY_GOOD = 1; + QUALITY_UNCERTAIN = 2; + QUALITY_BAD = 3; +} + +enum AlarmStateEnum { + ALARM_STATE_UNSPECIFIED = 0; + ALARM_STATE_NORMAL = 1; + ALARM_STATE_ACTIVE = 2; +} + +message AttributeValueUpdate { + string instance_unique_name = 1; + string attribute_path = 2; + string attribute_name = 3; + string value = 4; + Quality quality = 5; + google.protobuf.Timestamp timestamp = 6; +} + +message AlarmStateUpdate { + string instance_unique_name = 1; + string alarm_name = 2; + AlarmStateEnum state = 3; + int32 priority = 4; + google.protobuf.Timestamp timestamp = 5; +} diff --git a/src/ScadaLink.Communication/ScadaLink.Communication.csproj b/src/ScadaLink.Communication/ScadaLink.Communication.csproj index 30d0b03..0d77342 100644 --- a/src/ScadaLink.Communication/ScadaLink.Communication.csproj +++ b/src/ScadaLink.Communication/ScadaLink.Communication.csproj @@ -7,15 +7,18 @@ true + + + + - - - - + + + diff --git a/src/ScadaLink.Communication/SiteStreamGrpc/Sitestream.cs b/src/ScadaLink.Communication/SiteStreamGrpc/Sitestream.cs new file mode 100644 index 0000000..4eb8b44 --- /dev/null +++ b/src/ScadaLink.Communication/SiteStreamGrpc/Sitestream.cs @@ -0,0 +1,1396 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: sitestream.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 ScadaLink.Communication.Grpc { + + /// Holder for reflection information generated from sitestream.proto + public static partial class SitestreamReflection { + + #region Descriptor + /// File descriptor for sitestream.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static SitestreamReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "ChBzaXRlc3RyZWFtLnByb3RvEgpzaXRlc3RyZWFtGh9nb29nbGUvcHJvdG9i", + "dWYvdGltZXN0YW1wLnByb3RvIk0KFUluc3RhbmNlU3RyZWFtUmVxdWVzdBIW", + "Cg5jb3JyZWxhdGlvbl9pZBgBIAEoCRIcChRpbnN0YW5jZV91bmlxdWVfbmFt", + "ZRgCIAEoCSKoAQoPU2l0ZVN0cmVhbUV2ZW50EhYKDmNvcnJlbGF0aW9uX2lk", + "GAEgASgJEj0KEWF0dHJpYnV0ZV9jaGFuZ2VkGAIgASgLMiAuc2l0ZXN0cmVh", + "bS5BdHRyaWJ1dGVWYWx1ZVVwZGF0ZUgAEjUKDWFsYXJtX2NoYW5nZWQYAyAB", + "KAsyHC5zaXRlc3RyZWFtLkFsYXJtU3RhdGVVcGRhdGVIAEIHCgVldmVudCLI", + "AQoUQXR0cmlidXRlVmFsdWVVcGRhdGUSHAoUaW5zdGFuY2VfdW5pcXVlX25h", + "bWUYASABKAkSFgoOYXR0cmlidXRlX3BhdGgYAiABKAkSFgoOYXR0cmlidXRl", + "X25hbWUYAyABKAkSDQoFdmFsdWUYBCABKAkSJAoHcXVhbGl0eRgFIAEoDjIT", + "LnNpdGVzdHJlYW0uUXVhbGl0eRItCgl0aW1lc3RhbXAYBiABKAsyGi5nb29n", + "bGUucHJvdG9idWYuVGltZXN0YW1wIrABChBBbGFybVN0YXRlVXBkYXRlEhwK", + "FGluc3RhbmNlX3VuaXF1ZV9uYW1lGAEgASgJEhIKCmFsYXJtX25hbWUYAiAB", + "KAkSKQoFc3RhdGUYAyABKA4yGi5zaXRlc3RyZWFtLkFsYXJtU3RhdGVFbnVt", + "EhAKCHByaW9yaXR5GAQgASgFEi0KCXRpbWVzdGFtcBgFIAEoCzIaLmdvb2ds", + "ZS5wcm90b2J1Zi5UaW1lc3RhbXAqXAoHUXVhbGl0eRIXChNRVUFMSVRZX1VO", + "U1BFQ0lGSUVEEAASEAoMUVVBTElUWV9HT09EEAESFQoRUVVBTElUWV9VTkNF", + "UlRBSU4QAhIPCgtRVUFMSVRZX0JBRBADKl0KDkFsYXJtU3RhdGVFbnVtEhsK", + "F0FMQVJNX1NUQVRFX1VOU1BFQ0lGSUVEEAASFgoSQUxBUk1fU1RBVEVfTk9S", + "TUFMEAESFgoSQUxBUk1fU1RBVEVfQUNUSVZFEAIyagoRU2l0ZVN0cmVhbVNl", + "cnZpY2USVQoRU3Vic2NyaWJlSW5zdGFuY2USIS5zaXRlc3RyZWFtLkluc3Rh", + "bmNlU3RyZWFtUmVxdWVzdBobLnNpdGVzdHJlYW0uU2l0ZVN0cmVhbUV2ZW50", + "MAFCH6oCHFNjYWRhTGluay5Db21tdW5pY2F0aW9uLkdycGNiBnByb3RvMw==")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.TimestampReflection.Descriptor, }, + new pbr::GeneratedClrTypeInfo(new[] {typeof(global::ScadaLink.Communication.Grpc.Quality), typeof(global::ScadaLink.Communication.Grpc.AlarmStateEnum), }, null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::ScadaLink.Communication.Grpc.InstanceStreamRequest), global::ScadaLink.Communication.Grpc.InstanceStreamRequest.Parser, new[]{ "CorrelationId", "InstanceUniqueName" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ScadaLink.Communication.Grpc.SiteStreamEvent), global::ScadaLink.Communication.Grpc.SiteStreamEvent.Parser, new[]{ "CorrelationId", "AttributeChanged", "AlarmChanged" }, new[]{ "Event" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ScadaLink.Communication.Grpc.AttributeValueUpdate), global::ScadaLink.Communication.Grpc.AttributeValueUpdate.Parser, new[]{ "InstanceUniqueName", "AttributePath", "AttributeName", "Value", "Quality", "Timestamp" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ScadaLink.Communication.Grpc.AlarmStateUpdate), global::ScadaLink.Communication.Grpc.AlarmStateUpdate.Parser, new[]{ "InstanceUniqueName", "AlarmName", "State", "Priority", "Timestamp" }, null, null, null, null) + })); + } + #endregion + + } + #region Enums + public enum Quality { + [pbr::OriginalName("QUALITY_UNSPECIFIED")] Unspecified = 0, + [pbr::OriginalName("QUALITY_GOOD")] Good = 1, + [pbr::OriginalName("QUALITY_UNCERTAIN")] Uncertain = 2, + [pbr::OriginalName("QUALITY_BAD")] Bad = 3, + } + + public enum AlarmStateEnum { + [pbr::OriginalName("ALARM_STATE_UNSPECIFIED")] AlarmStateUnspecified = 0, + [pbr::OriginalName("ALARM_STATE_NORMAL")] AlarmStateNormal = 1, + [pbr::OriginalName("ALARM_STATE_ACTIVE")] AlarmStateActive = 2, + } + + #endregion + + #region Messages + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class InstanceStreamRequest : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new InstanceStreamRequest()); + 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::ScadaLink.Communication.Grpc.SitestreamReflection.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 InstanceStreamRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public InstanceStreamRequest(InstanceStreamRequest other) : this() { + correlationId_ = other.correlationId_; + instanceUniqueName_ = other.instanceUniqueName_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public InstanceStreamRequest Clone() { + return new InstanceStreamRequest(this); + } + + /// Field number for the "correlation_id" field. + public const int CorrelationIdFieldNumber = 1; + private string correlationId_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string CorrelationId { + get { return correlationId_; } + set { + correlationId_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "instance_unique_name" field. + public const int InstanceUniqueNameFieldNumber = 2; + private string instanceUniqueName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string InstanceUniqueName { + get { return instanceUniqueName_; } + set { + instanceUniqueName_ = 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 InstanceStreamRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(InstanceStreamRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (CorrelationId != other.CorrelationId) return false; + if (InstanceUniqueName != other.InstanceUniqueName) 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 (CorrelationId.Length != 0) hash ^= CorrelationId.GetHashCode(); + if (InstanceUniqueName.Length != 0) hash ^= InstanceUniqueName.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 (CorrelationId.Length != 0) { + output.WriteRawTag(10); + output.WriteString(CorrelationId); + } + if (InstanceUniqueName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(InstanceUniqueName); + } + 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 (CorrelationId.Length != 0) { + output.WriteRawTag(10); + output.WriteString(CorrelationId); + } + if (InstanceUniqueName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(InstanceUniqueName); + } + 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 (CorrelationId.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(CorrelationId); + } + if (InstanceUniqueName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(InstanceUniqueName); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(InstanceStreamRequest other) { + if (other == null) { + return; + } + if (other.CorrelationId.Length != 0) { + CorrelationId = other.CorrelationId; + } + if (other.InstanceUniqueName.Length != 0) { + InstanceUniqueName = other.InstanceUniqueName; + } + _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) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + CorrelationId = input.ReadString(); + break; + } + case 18: { + InstanceUniqueName = 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) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + CorrelationId = input.ReadString(); + break; + } + case 18: { + InstanceUniqueName = input.ReadString(); + break; + } + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class SiteStreamEvent : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SiteStreamEvent()); + 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::ScadaLink.Communication.Grpc.SitestreamReflection.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 SiteStreamEvent() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public SiteStreamEvent(SiteStreamEvent other) : this() { + correlationId_ = other.correlationId_; + switch (other.EventCase) { + case EventOneofCase.AttributeChanged: + AttributeChanged = other.AttributeChanged.Clone(); + break; + case EventOneofCase.AlarmChanged: + AlarmChanged = other.AlarmChanged.Clone(); + break; + } + + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public SiteStreamEvent Clone() { + return new SiteStreamEvent(this); + } + + /// Field number for the "correlation_id" field. + public const int CorrelationIdFieldNumber = 1; + private string correlationId_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string CorrelationId { + get { return correlationId_; } + set { + correlationId_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "attribute_changed" field. + public const int AttributeChangedFieldNumber = 2; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::ScadaLink.Communication.Grpc.AttributeValueUpdate AttributeChanged { + get { return eventCase_ == EventOneofCase.AttributeChanged ? (global::ScadaLink.Communication.Grpc.AttributeValueUpdate) event_ : null; } + set { + event_ = value; + eventCase_ = value == null ? EventOneofCase.None : EventOneofCase.AttributeChanged; + } + } + + /// Field number for the "alarm_changed" field. + public const int AlarmChangedFieldNumber = 3; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::ScadaLink.Communication.Grpc.AlarmStateUpdate AlarmChanged { + get { return eventCase_ == EventOneofCase.AlarmChanged ? (global::ScadaLink.Communication.Grpc.AlarmStateUpdate) event_ : null; } + set { + event_ = value; + eventCase_ = value == null ? EventOneofCase.None : EventOneofCase.AlarmChanged; + } + } + + private object event_; + /// Enum of possible cases for the "event" oneof. + public enum EventOneofCase { + None = 0, + AttributeChanged = 2, + AlarmChanged = 3, + } + private EventOneofCase eventCase_ = EventOneofCase.None; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public EventOneofCase EventCase { + get { return eventCase_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void ClearEvent() { + eventCase_ = EventOneofCase.None; + event_ = null; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as SiteStreamEvent); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(SiteStreamEvent other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (CorrelationId != other.CorrelationId) return false; + if (!object.Equals(AttributeChanged, other.AttributeChanged)) return false; + if (!object.Equals(AlarmChanged, other.AlarmChanged)) return false; + if (EventCase != other.EventCase) 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 (CorrelationId.Length != 0) hash ^= CorrelationId.GetHashCode(); + if (eventCase_ == EventOneofCase.AttributeChanged) hash ^= AttributeChanged.GetHashCode(); + if (eventCase_ == EventOneofCase.AlarmChanged) hash ^= AlarmChanged.GetHashCode(); + hash ^= (int) eventCase_; + 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 (CorrelationId.Length != 0) { + output.WriteRawTag(10); + output.WriteString(CorrelationId); + } + if (eventCase_ == EventOneofCase.AttributeChanged) { + output.WriteRawTag(18); + output.WriteMessage(AttributeChanged); + } + if (eventCase_ == EventOneofCase.AlarmChanged) { + output.WriteRawTag(26); + output.WriteMessage(AlarmChanged); + } + 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 (CorrelationId.Length != 0) { + output.WriteRawTag(10); + output.WriteString(CorrelationId); + } + if (eventCase_ == EventOneofCase.AttributeChanged) { + output.WriteRawTag(18); + output.WriteMessage(AttributeChanged); + } + if (eventCase_ == EventOneofCase.AlarmChanged) { + output.WriteRawTag(26); + output.WriteMessage(AlarmChanged); + } + 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 (CorrelationId.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(CorrelationId); + } + if (eventCase_ == EventOneofCase.AttributeChanged) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(AttributeChanged); + } + if (eventCase_ == EventOneofCase.AlarmChanged) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(AlarmChanged); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(SiteStreamEvent other) { + if (other == null) { + return; + } + if (other.CorrelationId.Length != 0) { + CorrelationId = other.CorrelationId; + } + switch (other.EventCase) { + case EventOneofCase.AttributeChanged: + if (AttributeChanged == null) { + AttributeChanged = new global::ScadaLink.Communication.Grpc.AttributeValueUpdate(); + } + AttributeChanged.MergeFrom(other.AttributeChanged); + break; + case EventOneofCase.AlarmChanged: + if (AlarmChanged == null) { + AlarmChanged = new global::ScadaLink.Communication.Grpc.AlarmStateUpdate(); + } + AlarmChanged.MergeFrom(other.AlarmChanged); + 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) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + CorrelationId = input.ReadString(); + break; + } + case 18: { + global::ScadaLink.Communication.Grpc.AttributeValueUpdate subBuilder = new global::ScadaLink.Communication.Grpc.AttributeValueUpdate(); + if (eventCase_ == EventOneofCase.AttributeChanged) { + subBuilder.MergeFrom(AttributeChanged); + } + input.ReadMessage(subBuilder); + AttributeChanged = subBuilder; + break; + } + case 26: { + global::ScadaLink.Communication.Grpc.AlarmStateUpdate subBuilder = new global::ScadaLink.Communication.Grpc.AlarmStateUpdate(); + if (eventCase_ == EventOneofCase.AlarmChanged) { + subBuilder.MergeFrom(AlarmChanged); + } + input.ReadMessage(subBuilder); + AlarmChanged = subBuilder; + 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) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + CorrelationId = input.ReadString(); + break; + } + case 18: { + global::ScadaLink.Communication.Grpc.AttributeValueUpdate subBuilder = new global::ScadaLink.Communication.Grpc.AttributeValueUpdate(); + if (eventCase_ == EventOneofCase.AttributeChanged) { + subBuilder.MergeFrom(AttributeChanged); + } + input.ReadMessage(subBuilder); + AttributeChanged = subBuilder; + break; + } + case 26: { + global::ScadaLink.Communication.Grpc.AlarmStateUpdate subBuilder = new global::ScadaLink.Communication.Grpc.AlarmStateUpdate(); + if (eventCase_ == EventOneofCase.AlarmChanged) { + subBuilder.MergeFrom(AlarmChanged); + } + input.ReadMessage(subBuilder); + AlarmChanged = subBuilder; + break; + } + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class AttributeValueUpdate : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new AttributeValueUpdate()); + 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::ScadaLink.Communication.Grpc.SitestreamReflection.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 AttributeValueUpdate() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public AttributeValueUpdate(AttributeValueUpdate other) : this() { + instanceUniqueName_ = other.instanceUniqueName_; + attributePath_ = other.attributePath_; + attributeName_ = other.attributeName_; + value_ = other.value_; + quality_ = other.quality_; + timestamp_ = other.timestamp_ != null ? other.timestamp_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public AttributeValueUpdate Clone() { + return new AttributeValueUpdate(this); + } + + /// Field number for the "instance_unique_name" field. + public const int InstanceUniqueNameFieldNumber = 1; + private string instanceUniqueName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string InstanceUniqueName { + get { return instanceUniqueName_; } + set { + instanceUniqueName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "attribute_path" field. + public const int AttributePathFieldNumber = 2; + private string attributePath_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string AttributePath { + get { return attributePath_; } + set { + attributePath_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "attribute_name" field. + public const int AttributeNameFieldNumber = 3; + private string attributeName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string AttributeName { + get { return attributeName_; } + set { + attributeName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "value" field. + public const int ValueFieldNumber = 4; + private string value_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Value { + get { return value_; } + set { + value_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "quality" field. + public const int QualityFieldNumber = 5; + private global::ScadaLink.Communication.Grpc.Quality quality_ = global::ScadaLink.Communication.Grpc.Quality.Unspecified; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::ScadaLink.Communication.Grpc.Quality Quality { + get { return quality_; } + set { + quality_ = value; + } + } + + /// Field number for the "timestamp" field. + public const int TimestampFieldNumber = 6; + private global::Google.Protobuf.WellKnownTypes.Timestamp timestamp_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Protobuf.WellKnownTypes.Timestamp Timestamp { + get { return timestamp_; } + set { + timestamp_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as AttributeValueUpdate); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(AttributeValueUpdate other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (InstanceUniqueName != other.InstanceUniqueName) return false; + if (AttributePath != other.AttributePath) return false; + if (AttributeName != other.AttributeName) return false; + if (Value != other.Value) return false; + if (Quality != other.Quality) return false; + if (!object.Equals(Timestamp, other.Timestamp)) 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 (InstanceUniqueName.Length != 0) hash ^= InstanceUniqueName.GetHashCode(); + if (AttributePath.Length != 0) hash ^= AttributePath.GetHashCode(); + if (AttributeName.Length != 0) hash ^= AttributeName.GetHashCode(); + if (Value.Length != 0) hash ^= Value.GetHashCode(); + if (Quality != global::ScadaLink.Communication.Grpc.Quality.Unspecified) hash ^= Quality.GetHashCode(); + if (timestamp_ != null) hash ^= Timestamp.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 (InstanceUniqueName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(InstanceUniqueName); + } + if (AttributePath.Length != 0) { + output.WriteRawTag(18); + output.WriteString(AttributePath); + } + if (AttributeName.Length != 0) { + output.WriteRawTag(26); + output.WriteString(AttributeName); + } + if (Value.Length != 0) { + output.WriteRawTag(34); + output.WriteString(Value); + } + if (Quality != global::ScadaLink.Communication.Grpc.Quality.Unspecified) { + output.WriteRawTag(40); + output.WriteEnum((int) Quality); + } + if (timestamp_ != null) { + output.WriteRawTag(50); + output.WriteMessage(Timestamp); + } + 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 (InstanceUniqueName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(InstanceUniqueName); + } + if (AttributePath.Length != 0) { + output.WriteRawTag(18); + output.WriteString(AttributePath); + } + if (AttributeName.Length != 0) { + output.WriteRawTag(26); + output.WriteString(AttributeName); + } + if (Value.Length != 0) { + output.WriteRawTag(34); + output.WriteString(Value); + } + if (Quality != global::ScadaLink.Communication.Grpc.Quality.Unspecified) { + output.WriteRawTag(40); + output.WriteEnum((int) Quality); + } + if (timestamp_ != null) { + output.WriteRawTag(50); + output.WriteMessage(Timestamp); + } + 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 (InstanceUniqueName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(InstanceUniqueName); + } + if (AttributePath.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(AttributePath); + } + if (AttributeName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(AttributeName); + } + if (Value.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Value); + } + if (Quality != global::ScadaLink.Communication.Grpc.Quality.Unspecified) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Quality); + } + if (timestamp_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Timestamp); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(AttributeValueUpdate other) { + if (other == null) { + return; + } + if (other.InstanceUniqueName.Length != 0) { + InstanceUniqueName = other.InstanceUniqueName; + } + if (other.AttributePath.Length != 0) { + AttributePath = other.AttributePath; + } + if (other.AttributeName.Length != 0) { + AttributeName = other.AttributeName; + } + if (other.Value.Length != 0) { + Value = other.Value; + } + if (other.Quality != global::ScadaLink.Communication.Grpc.Quality.Unspecified) { + Quality = other.Quality; + } + if (other.timestamp_ != null) { + if (timestamp_ == null) { + Timestamp = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + Timestamp.MergeFrom(other.Timestamp); + } + _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) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + InstanceUniqueName = input.ReadString(); + break; + } + case 18: { + AttributePath = input.ReadString(); + break; + } + case 26: { + AttributeName = input.ReadString(); + break; + } + case 34: { + Value = input.ReadString(); + break; + } + case 40: { + Quality = (global::ScadaLink.Communication.Grpc.Quality) input.ReadEnum(); + break; + } + case 50: { + if (timestamp_ == null) { + Timestamp = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(Timestamp); + 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) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + InstanceUniqueName = input.ReadString(); + break; + } + case 18: { + AttributePath = input.ReadString(); + break; + } + case 26: { + AttributeName = input.ReadString(); + break; + } + case 34: { + Value = input.ReadString(); + break; + } + case 40: { + Quality = (global::ScadaLink.Communication.Grpc.Quality) input.ReadEnum(); + break; + } + case 50: { + if (timestamp_ == null) { + Timestamp = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(Timestamp); + break; + } + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class AlarmStateUpdate : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new AlarmStateUpdate()); + 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::ScadaLink.Communication.Grpc.SitestreamReflection.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 AlarmStateUpdate() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public AlarmStateUpdate(AlarmStateUpdate other) : this() { + instanceUniqueName_ = other.instanceUniqueName_; + alarmName_ = other.alarmName_; + state_ = other.state_; + priority_ = other.priority_; + timestamp_ = other.timestamp_ != null ? other.timestamp_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public AlarmStateUpdate Clone() { + return new AlarmStateUpdate(this); + } + + /// Field number for the "instance_unique_name" field. + public const int InstanceUniqueNameFieldNumber = 1; + private string instanceUniqueName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string InstanceUniqueName { + get { return instanceUniqueName_; } + set { + instanceUniqueName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "alarm_name" field. + public const int AlarmNameFieldNumber = 2; + private string alarmName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string AlarmName { + get { return alarmName_; } + set { + alarmName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "state" field. + public const int StateFieldNumber = 3; + private global::ScadaLink.Communication.Grpc.AlarmStateEnum state_ = global::ScadaLink.Communication.Grpc.AlarmStateEnum.AlarmStateUnspecified; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::ScadaLink.Communication.Grpc.AlarmStateEnum State { + get { return state_; } + set { + state_ = value; + } + } + + /// Field number for the "priority" field. + public const int PriorityFieldNumber = 4; + private int priority_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int Priority { + get { return priority_; } + set { + priority_ = value; + } + } + + /// Field number for the "timestamp" field. + public const int TimestampFieldNumber = 5; + private global::Google.Protobuf.WellKnownTypes.Timestamp timestamp_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Protobuf.WellKnownTypes.Timestamp Timestamp { + get { return timestamp_; } + set { + timestamp_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as AlarmStateUpdate); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(AlarmStateUpdate other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (InstanceUniqueName != other.InstanceUniqueName) return false; + if (AlarmName != other.AlarmName) return false; + if (State != other.State) return false; + if (Priority != other.Priority) return false; + if (!object.Equals(Timestamp, other.Timestamp)) 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 (InstanceUniqueName.Length != 0) hash ^= InstanceUniqueName.GetHashCode(); + if (AlarmName.Length != 0) hash ^= AlarmName.GetHashCode(); + if (State != global::ScadaLink.Communication.Grpc.AlarmStateEnum.AlarmStateUnspecified) hash ^= State.GetHashCode(); + if (Priority != 0) hash ^= Priority.GetHashCode(); + if (timestamp_ != null) hash ^= Timestamp.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 (InstanceUniqueName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(InstanceUniqueName); + } + if (AlarmName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(AlarmName); + } + if (State != global::ScadaLink.Communication.Grpc.AlarmStateEnum.AlarmStateUnspecified) { + output.WriteRawTag(24); + output.WriteEnum((int) State); + } + if (Priority != 0) { + output.WriteRawTag(32); + output.WriteInt32(Priority); + } + if (timestamp_ != null) { + output.WriteRawTag(42); + output.WriteMessage(Timestamp); + } + 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 (InstanceUniqueName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(InstanceUniqueName); + } + if (AlarmName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(AlarmName); + } + if (State != global::ScadaLink.Communication.Grpc.AlarmStateEnum.AlarmStateUnspecified) { + output.WriteRawTag(24); + output.WriteEnum((int) State); + } + if (Priority != 0) { + output.WriteRawTag(32); + output.WriteInt32(Priority); + } + if (timestamp_ != null) { + output.WriteRawTag(42); + output.WriteMessage(Timestamp); + } + 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 (InstanceUniqueName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(InstanceUniqueName); + } + if (AlarmName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(AlarmName); + } + if (State != global::ScadaLink.Communication.Grpc.AlarmStateEnum.AlarmStateUnspecified) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) State); + } + if (Priority != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Priority); + } + if (timestamp_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Timestamp); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(AlarmStateUpdate other) { + if (other == null) { + return; + } + if (other.InstanceUniqueName.Length != 0) { + InstanceUniqueName = other.InstanceUniqueName; + } + if (other.AlarmName.Length != 0) { + AlarmName = other.AlarmName; + } + if (other.State != global::ScadaLink.Communication.Grpc.AlarmStateEnum.AlarmStateUnspecified) { + State = other.State; + } + if (other.Priority != 0) { + Priority = other.Priority; + } + if (other.timestamp_ != null) { + if (timestamp_ == null) { + Timestamp = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + Timestamp.MergeFrom(other.Timestamp); + } + _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) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + InstanceUniqueName = input.ReadString(); + break; + } + case 18: { + AlarmName = input.ReadString(); + break; + } + case 24: { + State = (global::ScadaLink.Communication.Grpc.AlarmStateEnum) input.ReadEnum(); + break; + } + case 32: { + Priority = input.ReadInt32(); + break; + } + case 42: { + if (timestamp_ == null) { + Timestamp = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(Timestamp); + 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) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + InstanceUniqueName = input.ReadString(); + break; + } + case 18: { + AlarmName = input.ReadString(); + break; + } + case 24: { + State = (global::ScadaLink.Communication.Grpc.AlarmStateEnum) input.ReadEnum(); + break; + } + case 32: { + Priority = input.ReadInt32(); + break; + } + case 42: { + if (timestamp_ == null) { + Timestamp = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(Timestamp); + break; + } + } + } + } + #endif + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/ScadaLink.Communication/SiteStreamGrpc/SitestreamGrpc.cs b/src/ScadaLink.Communication/SiteStreamGrpc/SitestreamGrpc.cs new file mode 100644 index 0000000..172be57 --- /dev/null +++ b/src/ScadaLink.Communication/SiteStreamGrpc/SitestreamGrpc.cs @@ -0,0 +1,145 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: sitestream.proto +// +#pragma warning disable 0414, 1591, 8981, 0612 +#region Designer generated code + +using grpc = global::Grpc.Core; + +namespace ScadaLink.Communication.Grpc { + public static partial class SiteStreamService + { + static readonly string __ServiceName = "sitestream.SiteStreamService"; + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static void __Helper_SerializeMessage(global::Google.Protobuf.IMessage message, grpc::SerializationContext context) + { + #if !GRPC_DISABLE_PROTOBUF_BUFFER_SERIALIZATION + if (message is global::Google.Protobuf.IBufferMessage) + { + context.SetPayloadLength(message.CalculateSize()); + global::Google.Protobuf.MessageExtensions.WriteTo(message, context.GetBufferWriter()); + context.Complete(); + return; + } + #endif + context.Complete(global::Google.Protobuf.MessageExtensions.ToByteArray(message)); + } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static class __Helper_MessageCache + { + public static readonly bool IsBufferMessage = global::System.Reflection.IntrospectionExtensions.GetTypeInfo(typeof(global::Google.Protobuf.IBufferMessage)).IsAssignableFrom(typeof(T)); + } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static T __Helper_DeserializeMessage(grpc::DeserializationContext context, global::Google.Protobuf.MessageParser parser) where T : global::Google.Protobuf.IMessage + { + #if !GRPC_DISABLE_PROTOBUF_BUFFER_SERIALIZATION + if (__Helper_MessageCache.IsBufferMessage) + { + return parser.ParseFrom(context.PayloadAsReadOnlySequence()); + } + #endif + return parser.ParseFrom(context.PayloadAsNewBuffer()); + } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_sitestream_InstanceStreamRequest = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::ScadaLink.Communication.Grpc.InstanceStreamRequest.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_sitestream_SiteStreamEvent = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::ScadaLink.Communication.Grpc.SiteStreamEvent.Parser)); + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Method __Method_SubscribeInstance = new grpc::Method( + grpc::MethodType.ServerStreaming, + __ServiceName, + "SubscribeInstance", + __Marshaller_sitestream_InstanceStreamRequest, + __Marshaller_sitestream_SiteStreamEvent); + + /// Service descriptor + public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor + { + get { return global::ScadaLink.Communication.Grpc.SitestreamReflection.Descriptor.Services[0]; } + } + + /// Base class for server-side implementations of SiteStreamService + [grpc::BindServiceMethod(typeof(SiteStreamService), "BindService")] + public abstract partial class SiteStreamServiceBase + { + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::System.Threading.Tasks.Task SubscribeInstance(global::ScadaLink.Communication.Grpc.InstanceStreamRequest request, grpc::IServerStreamWriter responseStream, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + } + + /// Client for SiteStreamService + public partial class SiteStreamServiceClient : grpc::ClientBase + { + /// Creates a new client for SiteStreamService + /// The channel to use to make remote calls. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public SiteStreamServiceClient(grpc::ChannelBase channel) : base(channel) + { + } + /// Creates a new client for SiteStreamService that uses a custom CallInvoker. + /// The callInvoker to use to make remote calls. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public SiteStreamServiceClient(grpc::CallInvoker callInvoker) : base(callInvoker) + { + } + /// Protected parameterless constructor to allow creation of test doubles. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + protected SiteStreamServiceClient() : base() + { + } + /// Protected constructor to allow creation of configured clients. + /// The client configuration. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + protected SiteStreamServiceClient(ClientBaseConfiguration configuration) : base(configuration) + { + } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncServerStreamingCall SubscribeInstance(global::ScadaLink.Communication.Grpc.InstanceStreamRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return SubscribeInstance(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncServerStreamingCall SubscribeInstance(global::ScadaLink.Communication.Grpc.InstanceStreamRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncServerStreamingCall(__Method_SubscribeInstance, null, options, request); + } + /// Creates a new instance of client from given ClientBaseConfiguration. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + protected override SiteStreamServiceClient NewInstance(ClientBaseConfiguration configuration) + { + return new SiteStreamServiceClient(configuration); + } + } + + /// Creates service definition that can be registered with a server + /// An object implementing the server-side handling logic. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public static grpc::ServerServiceDefinition BindService(SiteStreamServiceBase serviceImpl) + { + return grpc::ServerServiceDefinition.CreateBuilder() + .AddMethod(__Method_SubscribeInstance, serviceImpl.SubscribeInstance).Build(); + } + + /// Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. + /// Note: this method is part of an experimental API that can change or be removed without any prior notice. + /// Service methods will be bound by calling AddMethod on this object. + /// An object implementing the server-side handling logic. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public static void BindService(grpc::ServiceBinderBase serviceBinder, SiteStreamServiceBase serviceImpl) + { + serviceBinder.AddMethod(__Method_SubscribeInstance, serviceImpl == null ? null : new grpc::ServerStreamingServerMethod(serviceImpl.SubscribeInstance)); + } + + } +} +#endregion diff --git a/tests/ScadaLink.Communication.Tests/Grpc/ProtoRoundtripTests.cs b/tests/ScadaLink.Communication.Tests/Grpc/ProtoRoundtripTests.cs new file mode 100644 index 0000000..d49a421 --- /dev/null +++ b/tests/ScadaLink.Communication.Tests/Grpc/ProtoRoundtripTests.cs @@ -0,0 +1,129 @@ +using Google.Protobuf; +using Google.Protobuf.WellKnownTypes; +using ScadaLink.Communication.Grpc; + +namespace ScadaLink.Communication.Tests.Grpc; + +public class ProtoRoundtripTests +{ + [Theory] + [InlineData(Quality.Good)] + [InlineData(Quality.Uncertain)] + [InlineData(Quality.Bad)] + [InlineData(Quality.Unspecified)] + public void AttributeValueUpdate_RoundTrip(Quality quality) + { + var timestamp = Timestamp.FromDateTimeOffset( + new DateTimeOffset(2026, 3, 21, 12, 0, 0, TimeSpan.Zero)); + + var original = new AttributeValueUpdate + { + InstanceUniqueName = "Site1.Pump01", + AttributePath = "Modules.PressureModule", + AttributeName = "CurrentPressure", + Value = "42.5", + Quality = quality, + Timestamp = timestamp + }; + + var bytes = original.ToByteArray(); + var deserialized = AttributeValueUpdate.Parser.ParseFrom(bytes); + + Assert.Equal(original.InstanceUniqueName, deserialized.InstanceUniqueName); + Assert.Equal(original.AttributePath, deserialized.AttributePath); + Assert.Equal(original.AttributeName, deserialized.AttributeName); + Assert.Equal(original.Value, deserialized.Value); + Assert.Equal(original.Quality, deserialized.Quality); + Assert.Equal(original.Timestamp, deserialized.Timestamp); + Assert.Equal(timestamp.Seconds, deserialized.Timestamp.Seconds); + Assert.Equal(timestamp.Nanos, deserialized.Timestamp.Nanos); + } + + [Theory] + [InlineData(AlarmStateEnum.AlarmStateNormal)] + [InlineData(AlarmStateEnum.AlarmStateActive)] + [InlineData(AlarmStateEnum.AlarmStateUnspecified)] + public void AlarmStateUpdate_RoundTrip(AlarmStateEnum state) + { + var timestamp = Timestamp.FromDateTimeOffset( + new DateTimeOffset(2026, 3, 21, 12, 30, 0, TimeSpan.Zero)); + + var original = new AlarmStateUpdate + { + InstanceUniqueName = "Site1.Pump01", + AlarmName = "HighPressure", + State = state, + Priority = 3, + Timestamp = timestamp + }; + + var bytes = original.ToByteArray(); + var deserialized = AlarmStateUpdate.Parser.ParseFrom(bytes); + + Assert.Equal(original.InstanceUniqueName, deserialized.InstanceUniqueName); + Assert.Equal(original.AlarmName, deserialized.AlarmName); + Assert.Equal(original.State, deserialized.State); + Assert.Equal(original.Priority, deserialized.Priority); + Assert.Equal(original.Timestamp, deserialized.Timestamp); + } + + [Fact] + public void SiteStreamEvent_OneOf_AttributeChanged() + { + var evt = new SiteStreamEvent + { + CorrelationId = "corr-123", + AttributeChanged = new AttributeValueUpdate + { + InstanceUniqueName = "Site1.Pump01", + AttributePath = "Modules.PressureModule", + AttributeName = "CurrentPressure", + Value = "42.5", + Quality = Quality.Good, + Timestamp = Timestamp.FromDateTimeOffset(DateTimeOffset.UtcNow) + } + }; + + Assert.Equal(SiteStreamEvent.EventOneofCase.AttributeChanged, evt.EventCase); + Assert.NotNull(evt.AttributeChanged); + Assert.Null(evt.AlarmChanged); + + // Round-trip + var bytes = evt.ToByteArray(); + var deserialized = SiteStreamEvent.Parser.ParseFrom(bytes); + + Assert.Equal(SiteStreamEvent.EventOneofCase.AttributeChanged, deserialized.EventCase); + Assert.Equal("corr-123", deserialized.CorrelationId); + Assert.Equal("42.5", deserialized.AttributeChanged.Value); + } + + [Fact] + public void SiteStreamEvent_OneOf_AlarmChanged() + { + var evt = new SiteStreamEvent + { + CorrelationId = "corr-456", + AlarmChanged = new AlarmStateUpdate + { + InstanceUniqueName = "Site1.Pump01", + AlarmName = "HighPressure", + State = AlarmStateEnum.AlarmStateActive, + Priority = 1, + Timestamp = Timestamp.FromDateTimeOffset(DateTimeOffset.UtcNow) + } + }; + + Assert.Equal(SiteStreamEvent.EventOneofCase.AlarmChanged, evt.EventCase); + Assert.NotNull(evt.AlarmChanged); + Assert.Null(evt.AttributeChanged); + + // Round-trip + var bytes = evt.ToByteArray(); + var deserialized = SiteStreamEvent.Parser.ParseFrom(bytes); + + Assert.Equal(SiteStreamEvent.EventOneofCase.AlarmChanged, deserialized.EventCase); + Assert.Equal("corr-456", deserialized.CorrelationId); + Assert.Equal(AlarmStateEnum.AlarmStateActive, deserialized.AlarmChanged.State); + Assert.Equal(1, deserialized.AlarmChanged.Priority); + } +}