diff --git a/src/ScadaLink.Communication/Protos/sitestream.proto b/src/ScadaLink.Communication/Protos/sitestream.proto index d86459c..d01852f 100644 --- a/src/ScadaLink.Communication/Protos/sitestream.proto +++ b/src/ScadaLink.Communication/Protos/sitestream.proto @@ -3,9 +3,11 @@ option csharp_namespace = "ScadaLink.Communication.Grpc"; package sitestream; import "google/protobuf/timestamp.proto"; +import "google/protobuf/wrappers.proto"; // Int32Value service SiteStreamService { rpc SubscribeInstance(InstanceStreamRequest) returns (stream SiteStreamEvent); + rpc IngestAuditEvents(AuditEventBatch) returns (IngestAck); } message InstanceStreamRequest { @@ -63,3 +65,31 @@ message AlarmStateUpdate { AlarmLevelEnum level = 6; // ALARM_LEVEL_NONE for binary trigger types; set by HiLo. string message = 7; // Optional per-band operator message; empty when unset. } + +// Audit Log (#23) telemetry: single lifecycle event ferried from a site SQLite +// hot-path row to central via IngestAuditEvents. Mirrors AuditEvent (Commons) +// minus the site-local ForwardState and the central IngestedAtUtc (set on ingest). +message AuditEventDto { + string event_id = 1; + google.protobuf.Timestamp occurred_at_utc = 2; + string channel = 3; + string kind = 4; + string correlation_id = 5; // empty string represents null + string source_site_id = 6; + string source_instance_id = 7; + string source_script = 8; + string actor = 9; + string target = 10; + string status = 11; + google.protobuf.Int32Value http_status = 12; // null when absent + google.protobuf.Int32Value duration_ms = 13; + string error_message = 14; + string error_detail = 15; + string request_summary = 16; + string response_summary = 17; + bool payload_truncated = 18; + string extra = 19; +} + +message AuditEventBatch { repeated AuditEventDto events = 1; } +message IngestAck { repeated string accepted_event_ids = 1; } diff --git a/src/ScadaLink.Communication/SiteStreamGrpc/Sitestream.cs b/src/ScadaLink.Communication/SiteStreamGrpc/Sitestream.cs index b1892bc..3a843eb 100644 --- a/src/ScadaLink.Communication/SiteStreamGrpc/Sitestream.cs +++ b/src/ScadaLink.Communication/SiteStreamGrpc/Sitestream.cs @@ -25,40 +25,59 @@ namespace ScadaLink.Communication.Grpc { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "ChdQcm90b3Mvc2l0ZXN0cmVhbS5wcm90bxIKc2l0ZXN0cmVhbRofZ29vZ2xl", - "L3Byb3RvYnVmL3RpbWVzdGFtcC5wcm90byJNChVJbnN0YW5jZVN0cmVhbVJl", - "cXVlc3QSFgoOY29ycmVsYXRpb25faWQYASABKAkSHAoUaW5zdGFuY2VfdW5p", - "cXVlX25hbWUYAiABKAkiqAEKD1NpdGVTdHJlYW1FdmVudBIWCg5jb3JyZWxh", - "dGlvbl9pZBgBIAEoCRI9ChFhdHRyaWJ1dGVfY2hhbmdlZBgCIAEoCzIgLnNp", - "dGVzdHJlYW0uQXR0cmlidXRlVmFsdWVVcGRhdGVIABI1Cg1hbGFybV9jaGFu", - "Z2VkGAMgASgLMhwuc2l0ZXN0cmVhbS5BbGFybVN0YXRlVXBkYXRlSABCBwoF", - "ZXZlbnQiyAEKFEF0dHJpYnV0ZVZhbHVlVXBkYXRlEhwKFGluc3RhbmNlX3Vu", - "aXF1ZV9uYW1lGAEgASgJEhYKDmF0dHJpYnV0ZV9wYXRoGAIgASgJEhYKDmF0", - "dHJpYnV0ZV9uYW1lGAMgASgJEg0KBXZhbHVlGAQgASgJEiQKB3F1YWxpdHkY", - "BSABKA4yEy5zaXRlc3RyZWFtLlF1YWxpdHkSLQoJdGltZXN0YW1wGAYgASgL", - "MhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcCLsAQoQQWxhcm1TdGF0ZVVw", - "ZGF0ZRIcChRpbnN0YW5jZV91bmlxdWVfbmFtZRgBIAEoCRISCgphbGFybV9u", - "YW1lGAIgASgJEikKBXN0YXRlGAMgASgOMhouc2l0ZXN0cmVhbS5BbGFybVN0", - "YXRlRW51bRIQCghwcmlvcml0eRgEIAEoBRItCgl0aW1lc3RhbXAYBSABKAsy", - "Gi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEikKBWxldmVsGAYgASgOMhou", - "c2l0ZXN0cmVhbS5BbGFybUxldmVsRW51bRIPCgdtZXNzYWdlGAcgASgJKlwK", - "B1F1YWxpdHkSFwoTUVVBTElUWV9VTlNQRUNJRklFRBAAEhAKDFFVQUxJVFlf", - "R09PRBABEhUKEVFVQUxJVFlfVU5DRVJUQUlOEAISDwoLUVVBTElUWV9CQUQQ", - "AypdCg5BbGFybVN0YXRlRW51bRIbChdBTEFSTV9TVEFURV9VTlNQRUNJRklF", - "RBAAEhYKEkFMQVJNX1NUQVRFX05PUk1BTBABEhYKEkFMQVJNX1NUQVRFX0FD", - "VElWRRACKoUBCg5BbGFybUxldmVsRW51bRIUChBBTEFSTV9MRVZFTF9OT05F", - "EAASEwoPQUxBUk1fTEVWRUxfTE9XEAESFwoTQUxBUk1fTEVWRUxfTE9XX0xP", - "VxACEhQKEEFMQVJNX0xFVkVMX0hJR0gQAxIZChVBTEFSTV9MRVZFTF9ISUdI", - "X0hJR0gQBDJqChFTaXRlU3RyZWFtU2VydmljZRJVChFTdWJzY3JpYmVJbnN0", - "YW5jZRIhLnNpdGVzdHJlYW0uSW5zdGFuY2VTdHJlYW1SZXF1ZXN0Ghsuc2l0", - "ZXN0cmVhbS5TaXRlU3RyZWFtRXZlbnQwAUIfqgIcU2NhZGFMaW5rLkNvbW11", - "bmljYXRpb24uR3JwY2IGcHJvdG8z")); + "L3Byb3RvYnVmL3RpbWVzdGFtcC5wcm90bxoeZ29vZ2xlL3Byb3RvYnVmL3dy", + "YXBwZXJzLnByb3RvIk0KFUluc3RhbmNlU3RyZWFtUmVxdWVzdBIWCg5jb3Jy", + "ZWxhdGlvbl9pZBgBIAEoCRIcChRpbnN0YW5jZV91bmlxdWVfbmFtZRgCIAEo", + "CSKoAQoPU2l0ZVN0cmVhbUV2ZW50EhYKDmNvcnJlbGF0aW9uX2lkGAEgASgJ", + "Ej0KEWF0dHJpYnV0ZV9jaGFuZ2VkGAIgASgLMiAuc2l0ZXN0cmVhbS5BdHRy", + "aWJ1dGVWYWx1ZVVwZGF0ZUgAEjUKDWFsYXJtX2NoYW5nZWQYAyABKAsyHC5z", + "aXRlc3RyZWFtLkFsYXJtU3RhdGVVcGRhdGVIAEIHCgVldmVudCLIAQoUQXR0", + "cmlidXRlVmFsdWVVcGRhdGUSHAoUaW5zdGFuY2VfdW5pcXVlX25hbWUYASAB", + "KAkSFgoOYXR0cmlidXRlX3BhdGgYAiABKAkSFgoOYXR0cmlidXRlX25hbWUY", + "AyABKAkSDQoFdmFsdWUYBCABKAkSJAoHcXVhbGl0eRgFIAEoDjITLnNpdGVz", + "dHJlYW0uUXVhbGl0eRItCgl0aW1lc3RhbXAYBiABKAsyGi5nb29nbGUucHJv", + "dG9idWYuVGltZXN0YW1wIuwBChBBbGFybVN0YXRlVXBkYXRlEhwKFGluc3Rh", + "bmNlX3VuaXF1ZV9uYW1lGAEgASgJEhIKCmFsYXJtX25hbWUYAiABKAkSKQoF", + "c3RhdGUYAyABKA4yGi5zaXRlc3RyZWFtLkFsYXJtU3RhdGVFbnVtEhAKCHBy", + "aW9yaXR5GAQgASgFEi0KCXRpbWVzdGFtcBgFIAEoCzIaLmdvb2dsZS5wcm90", + "b2J1Zi5UaW1lc3RhbXASKQoFbGV2ZWwYBiABKA4yGi5zaXRlc3RyZWFtLkFs", + "YXJtTGV2ZWxFbnVtEg8KB21lc3NhZ2UYByABKAki9QMKDUF1ZGl0RXZlbnRE", + "dG8SEAoIZXZlbnRfaWQYASABKAkSMwoPb2NjdXJyZWRfYXRfdXRjGAIgASgL", + "MhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIPCgdjaGFubmVsGAMgASgJ", + "EgwKBGtpbmQYBCABKAkSFgoOY29ycmVsYXRpb25faWQYBSABKAkSFgoOc291", + "cmNlX3NpdGVfaWQYBiABKAkSGgoSc291cmNlX2luc3RhbmNlX2lkGAcgASgJ", + "EhUKDXNvdXJjZV9zY3JpcHQYCCABKAkSDQoFYWN0b3IYCSABKAkSDgoGdGFy", + "Z2V0GAogASgJEg4KBnN0YXR1cxgLIAEoCRIwCgtodHRwX3N0YXR1cxgMIAEo", + "CzIbLmdvb2dsZS5wcm90b2J1Zi5JbnQzMlZhbHVlEjAKC2R1cmF0aW9uX21z", + "GA0gASgLMhsuZ29vZ2xlLnByb3RvYnVmLkludDMyVmFsdWUSFQoNZXJyb3Jf", + "bWVzc2FnZRgOIAEoCRIUCgxlcnJvcl9kZXRhaWwYDyABKAkSFwoPcmVxdWVz", + "dF9zdW1tYXJ5GBAgASgJEhgKEHJlc3BvbnNlX3N1bW1hcnkYESABKAkSGQoR", + "cGF5bG9hZF90cnVuY2F0ZWQYEiABKAgSDQoFZXh0cmEYEyABKAkiPAoPQXVk", + "aXRFdmVudEJhdGNoEikKBmV2ZW50cxgBIAMoCzIZLnNpdGVzdHJlYW0uQXVk", + "aXRFdmVudER0byInCglJbmdlc3RBY2sSGgoSYWNjZXB0ZWRfZXZlbnRfaWRz", + "GAEgAygJKlwKB1F1YWxpdHkSFwoTUVVBTElUWV9VTlNQRUNJRklFRBAAEhAK", + "DFFVQUxJVFlfR09PRBABEhUKEVFVQUxJVFlfVU5DRVJUQUlOEAISDwoLUVVB", + "TElUWV9CQUQQAypdCg5BbGFybVN0YXRlRW51bRIbChdBTEFSTV9TVEFURV9V", + "TlNQRUNJRklFRBAAEhYKEkFMQVJNX1NUQVRFX05PUk1BTBABEhYKEkFMQVJN", + "X1NUQVRFX0FDVElWRRACKoUBCg5BbGFybUxldmVsRW51bRIUChBBTEFSTV9M", + "RVZFTF9OT05FEAASEwoPQUxBUk1fTEVWRUxfTE9XEAESFwoTQUxBUk1fTEVW", + "RUxfTE9XX0xPVxACEhQKEEFMQVJNX0xFVkVMX0hJR0gQAxIZChVBTEFSTV9M", + "RVZFTF9ISUdIX0hJR0gQBDKzAQoRU2l0ZVN0cmVhbVNlcnZpY2USVQoRU3Vi", + "c2NyaWJlSW5zdGFuY2USIS5zaXRlc3RyZWFtLkluc3RhbmNlU3RyZWFtUmVx", + "dWVzdBobLnNpdGVzdHJlYW0uU2l0ZVN0cmVhbUV2ZW50MAESRwoRSW5nZXN0", + "QXVkaXRFdmVudHMSGy5zaXRlc3RyZWFtLkF1ZGl0RXZlbnRCYXRjaBoVLnNp", + "dGVzdHJlYW0uSW5nZXN0QWNrQh+qAhxTY2FkYUxpbmsuQ29tbXVuaWNhdGlv", + "bi5HcnBjYgZwcm90bzM=")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, - new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.TimestampReflection.Descriptor, }, + new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.TimestampReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor, }, new pbr::GeneratedClrTypeInfo(new[] {typeof(global::ScadaLink.Communication.Grpc.Quality), typeof(global::ScadaLink.Communication.Grpc.AlarmStateEnum), typeof(global::ScadaLink.Communication.Grpc.AlarmLevelEnum), }, 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", "Level", "Message" }, 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", "Level", "Message" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ScadaLink.Communication.Grpc.AuditEventDto), global::ScadaLink.Communication.Grpc.AuditEventDto.Parser, new[]{ "EventId", "OccurredAtUtc", "Channel", "Kind", "CorrelationId", "SourceSiteId", "SourceInstanceId", "SourceScript", "Actor", "Target", "Status", "HttpStatus", "DurationMs", "ErrorMessage", "ErrorDetail", "RequestSummary", "ResponseSummary", "PayloadTruncated", "Extra" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ScadaLink.Communication.Grpc.AuditEventBatch), global::ScadaLink.Communication.Grpc.AuditEventBatch.Parser, new[]{ "Events" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ScadaLink.Communication.Grpc.IngestAck), global::ScadaLink.Communication.Grpc.IngestAck.Parser, new[]{ "AcceptedEventIds" }, null, null, null, null) })); } #endregion @@ -1487,6 +1506,1280 @@ namespace ScadaLink.Communication.Grpc { } + /// + /// Audit Log (#23) telemetry: single lifecycle event ferried from a site SQLite + /// hot-path row to central via IngestAuditEvents. Mirrors AuditEvent (Commons) + /// minus the site-local ForwardState and the central IngestedAtUtc (set on ingest). + /// + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class AuditEventDto : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new AuditEventDto()); + 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[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 AuditEventDto() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public AuditEventDto(AuditEventDto other) : this() { + eventId_ = other.eventId_; + occurredAtUtc_ = other.occurredAtUtc_ != null ? other.occurredAtUtc_.Clone() : null; + channel_ = other.channel_; + kind_ = other.kind_; + correlationId_ = other.correlationId_; + sourceSiteId_ = other.sourceSiteId_; + sourceInstanceId_ = other.sourceInstanceId_; + sourceScript_ = other.sourceScript_; + actor_ = other.actor_; + target_ = other.target_; + status_ = other.status_; + HttpStatus = other.HttpStatus; + DurationMs = other.DurationMs; + errorMessage_ = other.errorMessage_; + errorDetail_ = other.errorDetail_; + requestSummary_ = other.requestSummary_; + responseSummary_ = other.responseSummary_; + payloadTruncated_ = other.payloadTruncated_; + extra_ = other.extra_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public AuditEventDto Clone() { + return new AuditEventDto(this); + } + + /// Field number for the "event_id" field. + public const int EventIdFieldNumber = 1; + private string eventId_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string EventId { + get { return eventId_; } + set { + eventId_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "occurred_at_utc" field. + public const int OccurredAtUtcFieldNumber = 2; + private global::Google.Protobuf.WellKnownTypes.Timestamp occurredAtUtc_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Protobuf.WellKnownTypes.Timestamp OccurredAtUtc { + get { return occurredAtUtc_; } + set { + occurredAtUtc_ = value; + } + } + + /// Field number for the "channel" field. + public const int ChannelFieldNumber = 3; + private string channel_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Channel { + get { return channel_; } + set { + channel_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "kind" field. + public const int KindFieldNumber = 4; + private string kind_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Kind { + get { return kind_; } + set { + kind_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "correlation_id" field. + public const int CorrelationIdFieldNumber = 5; + private string correlationId_ = ""; + /// + /// empty string represents null + /// + [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 "source_site_id" field. + public const int SourceSiteIdFieldNumber = 6; + private string sourceSiteId_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string SourceSiteId { + get { return sourceSiteId_; } + set { + sourceSiteId_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "source_instance_id" field. + public const int SourceInstanceIdFieldNumber = 7; + private string sourceInstanceId_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string SourceInstanceId { + get { return sourceInstanceId_; } + set { + sourceInstanceId_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "source_script" field. + public const int SourceScriptFieldNumber = 8; + private string sourceScript_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string SourceScript { + get { return sourceScript_; } + set { + sourceScript_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "actor" field. + public const int ActorFieldNumber = 9; + private string actor_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Actor { + get { return actor_; } + set { + actor_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "target" field. + public const int TargetFieldNumber = 10; + private string target_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Target { + get { return target_; } + set { + target_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "status" field. + public const int StatusFieldNumber = 11; + private string status_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Status { + get { return status_; } + set { + status_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "http_status" field. + public const int HttpStatusFieldNumber = 12; + private static readonly pb::FieldCodec _single_httpStatus_codec = pb::FieldCodec.ForStructWrapper(98); + private int? httpStatus_; + /// + /// null when absent + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int? HttpStatus { + get { return httpStatus_; } + set { + httpStatus_ = value; + } + } + + + /// Field number for the "duration_ms" field. + public const int DurationMsFieldNumber = 13; + private static readonly pb::FieldCodec _single_durationMs_codec = pb::FieldCodec.ForStructWrapper(106); + private int? durationMs_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int? DurationMs { + get { return durationMs_; } + set { + durationMs_ = value; + } + } + + + /// Field number for the "error_message" field. + public const int ErrorMessageFieldNumber = 14; + private string errorMessage_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string ErrorMessage { + get { return errorMessage_; } + set { + errorMessage_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "error_detail" field. + public const int ErrorDetailFieldNumber = 15; + private string errorDetail_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string ErrorDetail { + get { return errorDetail_; } + set { + errorDetail_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "request_summary" field. + public const int RequestSummaryFieldNumber = 16; + private string requestSummary_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string RequestSummary { + get { return requestSummary_; } + set { + requestSummary_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "response_summary" field. + public const int ResponseSummaryFieldNumber = 17; + private string responseSummary_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string ResponseSummary { + get { return responseSummary_; } + set { + responseSummary_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "payload_truncated" field. + public const int PayloadTruncatedFieldNumber = 18; + private bool payloadTruncated_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool PayloadTruncated { + get { return payloadTruncated_; } + set { + payloadTruncated_ = value; + } + } + + /// Field number for the "extra" field. + public const int ExtraFieldNumber = 19; + private string extra_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Extra { + get { return extra_; } + set { + extra_ = 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 AuditEventDto); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(AuditEventDto other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (EventId != other.EventId) return false; + if (!object.Equals(OccurredAtUtc, other.OccurredAtUtc)) return false; + if (Channel != other.Channel) return false; + if (Kind != other.Kind) return false; + if (CorrelationId != other.CorrelationId) return false; + if (SourceSiteId != other.SourceSiteId) return false; + if (SourceInstanceId != other.SourceInstanceId) return false; + if (SourceScript != other.SourceScript) return false; + if (Actor != other.Actor) return false; + if (Target != other.Target) return false; + if (Status != other.Status) return false; + if (HttpStatus != other.HttpStatus) return false; + if (DurationMs != other.DurationMs) return false; + if (ErrorMessage != other.ErrorMessage) return false; + if (ErrorDetail != other.ErrorDetail) return false; + if (RequestSummary != other.RequestSummary) return false; + if (ResponseSummary != other.ResponseSummary) return false; + if (PayloadTruncated != other.PayloadTruncated) return false; + if (Extra != other.Extra) 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 (EventId.Length != 0) hash ^= EventId.GetHashCode(); + if (occurredAtUtc_ != null) hash ^= OccurredAtUtc.GetHashCode(); + if (Channel.Length != 0) hash ^= Channel.GetHashCode(); + if (Kind.Length != 0) hash ^= Kind.GetHashCode(); + if (CorrelationId.Length != 0) hash ^= CorrelationId.GetHashCode(); + if (SourceSiteId.Length != 0) hash ^= SourceSiteId.GetHashCode(); + if (SourceInstanceId.Length != 0) hash ^= SourceInstanceId.GetHashCode(); + if (SourceScript.Length != 0) hash ^= SourceScript.GetHashCode(); + if (Actor.Length != 0) hash ^= Actor.GetHashCode(); + if (Target.Length != 0) hash ^= Target.GetHashCode(); + if (Status.Length != 0) hash ^= Status.GetHashCode(); + if (httpStatus_ != null) hash ^= HttpStatus.GetHashCode(); + if (durationMs_ != null) hash ^= DurationMs.GetHashCode(); + if (ErrorMessage.Length != 0) hash ^= ErrorMessage.GetHashCode(); + if (ErrorDetail.Length != 0) hash ^= ErrorDetail.GetHashCode(); + if (RequestSummary.Length != 0) hash ^= RequestSummary.GetHashCode(); + if (ResponseSummary.Length != 0) hash ^= ResponseSummary.GetHashCode(); + if (PayloadTruncated != false) hash ^= PayloadTruncated.GetHashCode(); + if (Extra.Length != 0) hash ^= Extra.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 (EventId.Length != 0) { + output.WriteRawTag(10); + output.WriteString(EventId); + } + if (occurredAtUtc_ != null) { + output.WriteRawTag(18); + output.WriteMessage(OccurredAtUtc); + } + if (Channel.Length != 0) { + output.WriteRawTag(26); + output.WriteString(Channel); + } + if (Kind.Length != 0) { + output.WriteRawTag(34); + output.WriteString(Kind); + } + if (CorrelationId.Length != 0) { + output.WriteRawTag(42); + output.WriteString(CorrelationId); + } + if (SourceSiteId.Length != 0) { + output.WriteRawTag(50); + output.WriteString(SourceSiteId); + } + if (SourceInstanceId.Length != 0) { + output.WriteRawTag(58); + output.WriteString(SourceInstanceId); + } + if (SourceScript.Length != 0) { + output.WriteRawTag(66); + output.WriteString(SourceScript); + } + if (Actor.Length != 0) { + output.WriteRawTag(74); + output.WriteString(Actor); + } + if (Target.Length != 0) { + output.WriteRawTag(82); + output.WriteString(Target); + } + if (Status.Length != 0) { + output.WriteRawTag(90); + output.WriteString(Status); + } + if (httpStatus_ != null) { + _single_httpStatus_codec.WriteTagAndValue(output, HttpStatus); + } + if (durationMs_ != null) { + _single_durationMs_codec.WriteTagAndValue(output, DurationMs); + } + if (ErrorMessage.Length != 0) { + output.WriteRawTag(114); + output.WriteString(ErrorMessage); + } + if (ErrorDetail.Length != 0) { + output.WriteRawTag(122); + output.WriteString(ErrorDetail); + } + if (RequestSummary.Length != 0) { + output.WriteRawTag(130, 1); + output.WriteString(RequestSummary); + } + if (ResponseSummary.Length != 0) { + output.WriteRawTag(138, 1); + output.WriteString(ResponseSummary); + } + if (PayloadTruncated != false) { + output.WriteRawTag(144, 1); + output.WriteBool(PayloadTruncated); + } + if (Extra.Length != 0) { + output.WriteRawTag(154, 1); + output.WriteString(Extra); + } + 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 (EventId.Length != 0) { + output.WriteRawTag(10); + output.WriteString(EventId); + } + if (occurredAtUtc_ != null) { + output.WriteRawTag(18); + output.WriteMessage(OccurredAtUtc); + } + if (Channel.Length != 0) { + output.WriteRawTag(26); + output.WriteString(Channel); + } + if (Kind.Length != 0) { + output.WriteRawTag(34); + output.WriteString(Kind); + } + if (CorrelationId.Length != 0) { + output.WriteRawTag(42); + output.WriteString(CorrelationId); + } + if (SourceSiteId.Length != 0) { + output.WriteRawTag(50); + output.WriteString(SourceSiteId); + } + if (SourceInstanceId.Length != 0) { + output.WriteRawTag(58); + output.WriteString(SourceInstanceId); + } + if (SourceScript.Length != 0) { + output.WriteRawTag(66); + output.WriteString(SourceScript); + } + if (Actor.Length != 0) { + output.WriteRawTag(74); + output.WriteString(Actor); + } + if (Target.Length != 0) { + output.WriteRawTag(82); + output.WriteString(Target); + } + if (Status.Length != 0) { + output.WriteRawTag(90); + output.WriteString(Status); + } + if (httpStatus_ != null) { + _single_httpStatus_codec.WriteTagAndValue(ref output, HttpStatus); + } + if (durationMs_ != null) { + _single_durationMs_codec.WriteTagAndValue(ref output, DurationMs); + } + if (ErrorMessage.Length != 0) { + output.WriteRawTag(114); + output.WriteString(ErrorMessage); + } + if (ErrorDetail.Length != 0) { + output.WriteRawTag(122); + output.WriteString(ErrorDetail); + } + if (RequestSummary.Length != 0) { + output.WriteRawTag(130, 1); + output.WriteString(RequestSummary); + } + if (ResponseSummary.Length != 0) { + output.WriteRawTag(138, 1); + output.WriteString(ResponseSummary); + } + if (PayloadTruncated != false) { + output.WriteRawTag(144, 1); + output.WriteBool(PayloadTruncated); + } + if (Extra.Length != 0) { + output.WriteRawTag(154, 1); + output.WriteString(Extra); + } + 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 (EventId.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(EventId); + } + if (occurredAtUtc_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(OccurredAtUtc); + } + if (Channel.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Channel); + } + if (Kind.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Kind); + } + if (CorrelationId.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(CorrelationId); + } + if (SourceSiteId.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(SourceSiteId); + } + if (SourceInstanceId.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(SourceInstanceId); + } + if (SourceScript.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(SourceScript); + } + if (Actor.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Actor); + } + if (Target.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Target); + } + if (Status.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Status); + } + if (httpStatus_ != null) { + size += _single_httpStatus_codec.CalculateSizeWithTag(HttpStatus); + } + if (durationMs_ != null) { + size += _single_durationMs_codec.CalculateSizeWithTag(DurationMs); + } + if (ErrorMessage.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ErrorMessage); + } + if (ErrorDetail.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ErrorDetail); + } + if (RequestSummary.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(RequestSummary); + } + if (ResponseSummary.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(ResponseSummary); + } + if (PayloadTruncated != false) { + size += 2 + 1; + } + if (Extra.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(Extra); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(AuditEventDto other) { + if (other == null) { + return; + } + if (other.EventId.Length != 0) { + EventId = other.EventId; + } + if (other.occurredAtUtc_ != null) { + if (occurredAtUtc_ == null) { + OccurredAtUtc = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + OccurredAtUtc.MergeFrom(other.OccurredAtUtc); + } + if (other.Channel.Length != 0) { + Channel = other.Channel; + } + if (other.Kind.Length != 0) { + Kind = other.Kind; + } + if (other.CorrelationId.Length != 0) { + CorrelationId = other.CorrelationId; + } + if (other.SourceSiteId.Length != 0) { + SourceSiteId = other.SourceSiteId; + } + if (other.SourceInstanceId.Length != 0) { + SourceInstanceId = other.SourceInstanceId; + } + if (other.SourceScript.Length != 0) { + SourceScript = other.SourceScript; + } + if (other.Actor.Length != 0) { + Actor = other.Actor; + } + if (other.Target.Length != 0) { + Target = other.Target; + } + if (other.Status.Length != 0) { + Status = other.Status; + } + if (other.httpStatus_ != null) { + if (httpStatus_ == null || other.HttpStatus != 0) { + HttpStatus = other.HttpStatus; + } + } + if (other.durationMs_ != null) { + if (durationMs_ == null || other.DurationMs != 0) { + DurationMs = other.DurationMs; + } + } + if (other.ErrorMessage.Length != 0) { + ErrorMessage = other.ErrorMessage; + } + if (other.ErrorDetail.Length != 0) { + ErrorDetail = other.ErrorDetail; + } + if (other.RequestSummary.Length != 0) { + RequestSummary = other.RequestSummary; + } + if (other.ResponseSummary.Length != 0) { + ResponseSummary = other.ResponseSummary; + } + if (other.PayloadTruncated != false) { + PayloadTruncated = other.PayloadTruncated; + } + if (other.Extra.Length != 0) { + Extra = other.Extra; + } + _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: { + EventId = input.ReadString(); + break; + } + case 18: { + if (occurredAtUtc_ == null) { + OccurredAtUtc = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(OccurredAtUtc); + break; + } + case 26: { + Channel = input.ReadString(); + break; + } + case 34: { + Kind = input.ReadString(); + break; + } + case 42: { + CorrelationId = input.ReadString(); + break; + } + case 50: { + SourceSiteId = input.ReadString(); + break; + } + case 58: { + SourceInstanceId = input.ReadString(); + break; + } + case 66: { + SourceScript = input.ReadString(); + break; + } + case 74: { + Actor = input.ReadString(); + break; + } + case 82: { + Target = input.ReadString(); + break; + } + case 90: { + Status = input.ReadString(); + break; + } + case 98: { + int? value = _single_httpStatus_codec.Read(input); + if (httpStatus_ == null || value != 0) { + HttpStatus = value; + } + break; + } + case 106: { + int? value = _single_durationMs_codec.Read(input); + if (durationMs_ == null || value != 0) { + DurationMs = value; + } + break; + } + case 114: { + ErrorMessage = input.ReadString(); + break; + } + case 122: { + ErrorDetail = input.ReadString(); + break; + } + case 130: { + RequestSummary = input.ReadString(); + break; + } + case 138: { + ResponseSummary = input.ReadString(); + break; + } + case 144: { + PayloadTruncated = input.ReadBool(); + break; + } + case 154: { + Extra = 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: { + EventId = input.ReadString(); + break; + } + case 18: { + if (occurredAtUtc_ == null) { + OccurredAtUtc = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(OccurredAtUtc); + break; + } + case 26: { + Channel = input.ReadString(); + break; + } + case 34: { + Kind = input.ReadString(); + break; + } + case 42: { + CorrelationId = input.ReadString(); + break; + } + case 50: { + SourceSiteId = input.ReadString(); + break; + } + case 58: { + SourceInstanceId = input.ReadString(); + break; + } + case 66: { + SourceScript = input.ReadString(); + break; + } + case 74: { + Actor = input.ReadString(); + break; + } + case 82: { + Target = input.ReadString(); + break; + } + case 90: { + Status = input.ReadString(); + break; + } + case 98: { + int? value = _single_httpStatus_codec.Read(ref input); + if (httpStatus_ == null || value != 0) { + HttpStatus = value; + } + break; + } + case 106: { + int? value = _single_durationMs_codec.Read(ref input); + if (durationMs_ == null || value != 0) { + DurationMs = value; + } + break; + } + case 114: { + ErrorMessage = input.ReadString(); + break; + } + case 122: { + ErrorDetail = input.ReadString(); + break; + } + case 130: { + RequestSummary = input.ReadString(); + break; + } + case 138: { + ResponseSummary = input.ReadString(); + break; + } + case 144: { + PayloadTruncated = input.ReadBool(); + break; + } + case 154: { + Extra = input.ReadString(); + break; + } + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class AuditEventBatch : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new AuditEventBatch()); + 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[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 AuditEventBatch() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public AuditEventBatch(AuditEventBatch other) : this() { + events_ = other.events_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public AuditEventBatch Clone() { + return new AuditEventBatch(this); + } + + /// Field number for the "events" field. + public const int EventsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_events_codec + = pb::FieldCodec.ForMessage(10, global::ScadaLink.Communication.Grpc.AuditEventDto.Parser); + private readonly pbc::RepeatedField events_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public pbc::RepeatedField Events { + get { return events_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as AuditEventBatch); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(AuditEventBatch other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!events_.Equals(other.events_)) 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; + hash ^= events_.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 + events_.WriteTo(output, _repeated_events_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) { + events_.WriteTo(ref output, _repeated_events_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; + size += events_.CalculateSize(_repeated_events_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(AuditEventBatch other) { + if (other == null) { + return; + } + events_.Add(other.events_); + _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: { + events_.AddEntriesFrom(input, _repeated_events_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) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + events_.AddEntriesFrom(ref input, _repeated_events_codec); + break; + } + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class IngestAck : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new IngestAck()); + 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[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 IngestAck() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public IngestAck(IngestAck other) : this() { + acceptedEventIds_ = other.acceptedEventIds_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public IngestAck Clone() { + return new IngestAck(this); + } + + /// Field number for the "accepted_event_ids" field. + public const int AcceptedEventIdsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_acceptedEventIds_codec + = pb::FieldCodec.ForString(10); + private readonly pbc::RepeatedField acceptedEventIds_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public pbc::RepeatedField AcceptedEventIds { + get { return acceptedEventIds_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as IngestAck); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(IngestAck other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!acceptedEventIds_.Equals(other.acceptedEventIds_)) 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; + hash ^= acceptedEventIds_.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 + acceptedEventIds_.WriteTo(output, _repeated_acceptedEventIds_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) { + acceptedEventIds_.WriteTo(ref output, _repeated_acceptedEventIds_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; + size += acceptedEventIds_.CalculateSize(_repeated_acceptedEventIds_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(IngestAck other) { + if (other == null) { + return; + } + acceptedEventIds_.Add(other.acceptedEventIds_); + _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: { + acceptedEventIds_.AddEntriesFrom(input, _repeated_acceptedEventIds_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) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + acceptedEventIds_.AddEntriesFrom(ref input, _repeated_acceptedEventIds_codec); + break; + } + } + } + } + #endif + + } + #endregion } diff --git a/src/ScadaLink.Communication/SiteStreamGrpc/SitestreamGrpc.cs b/src/ScadaLink.Communication/SiteStreamGrpc/SitestreamGrpc.cs index 6aa6ecb..0a900cb 100644 --- a/src/ScadaLink.Communication/SiteStreamGrpc/SitestreamGrpc.cs +++ b/src/ScadaLink.Communication/SiteStreamGrpc/SitestreamGrpc.cs @@ -49,6 +49,10 @@ namespace ScadaLink.Communication.Grpc { 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::Marshaller __Marshaller_sitestream_AuditEventBatch = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::ScadaLink.Communication.Grpc.AuditEventBatch.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_sitestream_IngestAck = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::ScadaLink.Communication.Grpc.IngestAck.Parser)); [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] static readonly grpc::Method __Method_SubscribeInstance = new grpc::Method( @@ -58,6 +62,14 @@ namespace ScadaLink.Communication.Grpc { __Marshaller_sitestream_InstanceStreamRequest, __Marshaller_sitestream_SiteStreamEvent); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Method __Method_IngestAuditEvents = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "IngestAuditEvents", + __Marshaller_sitestream_AuditEventBatch, + __Marshaller_sitestream_IngestAck); + /// Service descriptor public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor { @@ -74,6 +86,12 @@ namespace ScadaLink.Communication.Grpc { throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::System.Threading.Tasks.Task IngestAuditEvents(global::ScadaLink.Communication.Grpc.AuditEventBatch request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + } /// Client for SiteStreamService @@ -113,6 +131,26 @@ namespace ScadaLink.Communication.Grpc { { return CallInvoker.AsyncServerStreamingCall(__Method_SubscribeInstance, null, options, request); } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::ScadaLink.Communication.Grpc.IngestAck IngestAuditEvents(global::ScadaLink.Communication.Grpc.AuditEventBatch request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return IngestAuditEvents(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::ScadaLink.Communication.Grpc.IngestAck IngestAuditEvents(global::ScadaLink.Communication.Grpc.AuditEventBatch request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_IngestAuditEvents, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall IngestAuditEventsAsync(global::ScadaLink.Communication.Grpc.AuditEventBatch request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return IngestAuditEventsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall IngestAuditEventsAsync(global::ScadaLink.Communication.Grpc.AuditEventBatch request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_IngestAuditEvents, 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) @@ -127,7 +165,8 @@ namespace ScadaLink.Communication.Grpc { public static grpc::ServerServiceDefinition BindService(SiteStreamServiceBase serviceImpl) { return grpc::ServerServiceDefinition.CreateBuilder() - .AddMethod(__Method_SubscribeInstance, serviceImpl.SubscribeInstance).Build(); + .AddMethod(__Method_SubscribeInstance, serviceImpl.SubscribeInstance) + .AddMethod(__Method_IngestAuditEvents, serviceImpl.IngestAuditEvents).Build(); } /// Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. @@ -138,6 +177,7 @@ namespace ScadaLink.Communication.Grpc { public static void BindService(grpc::ServiceBinderBase serviceBinder, SiteStreamServiceBase serviceImpl) { serviceBinder.AddMethod(__Method_SubscribeInstance, serviceImpl == null ? null : new grpc::ServerStreamingServerMethod(serviceImpl.SubscribeInstance)); + serviceBinder.AddMethod(__Method_IngestAuditEvents, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.IngestAuditEvents)); } } diff --git a/tests/ScadaLink.Communication.Tests/Protos/AuditEventProtoTests.cs b/tests/ScadaLink.Communication.Tests/Protos/AuditEventProtoTests.cs new file mode 100644 index 0000000..4cd0d48 --- /dev/null +++ b/tests/ScadaLink.Communication.Tests/Protos/AuditEventProtoTests.cs @@ -0,0 +1,123 @@ +using Google.Protobuf; +using Google.Protobuf.WellKnownTypes; +using ScadaLink.Communication.Grpc; + +namespace ScadaLink.Communication.Tests.Protos; + +/// +/// Wire-format round-trip tests for the Audit Log (#23) telemetry proto messages +/// (, , ). +/// Locks the additive contract the site → central audit pipeline depends on. +/// +public class AuditEventProtoTests +{ + [Fact] + public void AuditEventDto_RoundTrip_PreservesAllFields() + { + var occurredAt = Timestamp.FromDateTimeOffset( + new DateTimeOffset(2026, 5, 20, 10, 15, 30, 123, TimeSpan.Zero)); + + var original = new AuditEventDto + { + EventId = Guid.NewGuid().ToString(), + OccurredAtUtc = occurredAt, + Channel = "ApiOutbound", + Kind = "ApiCall", + CorrelationId = Guid.NewGuid().ToString(), + SourceSiteId = "site-1", + SourceInstanceId = "Pump01", + SourceScript = "OnDemand", + Actor = "design-key", + Target = "weather-api", + Status = "Delivered", + HttpStatus = 200, + DurationMs = 42, + ErrorMessage = "no error", + ErrorDetail = "stack", + RequestSummary = "GET /weather?city=brisbane", + ResponseSummary = "{ \"temp\": 22.5 }", + PayloadTruncated = true, + Extra = "{ \"retryCount\": 0 }" + }; + + var bytes = original.ToByteArray(); + var deserialized = AuditEventDto.Parser.ParseFrom(bytes); + + Assert.Equal(original.EventId, deserialized.EventId); + Assert.Equal(original.OccurredAtUtc, deserialized.OccurredAtUtc); + Assert.Equal(original.Channel, deserialized.Channel); + Assert.Equal(original.Kind, deserialized.Kind); + Assert.Equal(original.CorrelationId, deserialized.CorrelationId); + Assert.Equal(original.SourceSiteId, deserialized.SourceSiteId); + Assert.Equal(original.SourceInstanceId, deserialized.SourceInstanceId); + Assert.Equal(original.SourceScript, deserialized.SourceScript); + Assert.Equal(original.Actor, deserialized.Actor); + Assert.Equal(original.Target, deserialized.Target); + Assert.Equal(original.Status, deserialized.Status); + Assert.Equal(original.HttpStatus, deserialized.HttpStatus); + Assert.Equal(original.DurationMs, deserialized.DurationMs); + Assert.Equal(original.ErrorMessage, deserialized.ErrorMessage); + Assert.Equal(original.ErrorDetail, deserialized.ErrorDetail); + Assert.Equal(original.RequestSummary, deserialized.RequestSummary); + Assert.Equal(original.ResponseSummary, deserialized.ResponseSummary); + Assert.Equal(original.PayloadTruncated, deserialized.PayloadTruncated); + Assert.Equal(original.Extra, deserialized.Extra); + } + + [Fact] + public void AuditEventDto_NullableInt_AbsentByDefault_NotIncludedInWire() + { + // Int32Value fields (http_status, duration_ms) are wrapper-typed in proto; + // when unset, the wrapper is absent, not serialized, and deserializes back to null. + var original = new AuditEventDto + { + EventId = Guid.NewGuid().ToString(), + OccurredAtUtc = Timestamp.FromDateTimeOffset(DateTimeOffset.UtcNow), + Channel = "Notification", + Kind = "NotifySend", + Status = "Submitted" + }; + + Assert.Null(original.HttpStatus); + Assert.Null(original.DurationMs); + + var bytes = original.ToByteArray(); + var deserialized = AuditEventDto.Parser.ParseFrom(bytes); + + Assert.Null(deserialized.HttpStatus); + Assert.Null(deserialized.DurationMs); + } + + [Fact] + public void AuditEventBatch_Empty_RoundTrip_Yields_EmptyEvents() + { + var original = new AuditEventBatch(); + Assert.Empty(original.Events); + + var bytes = original.ToByteArray(); + var deserialized = AuditEventBatch.Parser.ParseFrom(bytes); + + Assert.Empty(deserialized.Events); + } + + [Fact] + public void IngestAck_PreservesAcceptedEventIds() + { + var id1 = Guid.NewGuid().ToString(); + var id2 = Guid.NewGuid().ToString(); + var id3 = Guid.NewGuid().ToString(); + + var original = new IngestAck(); + original.AcceptedEventIds.Add(id1); + original.AcceptedEventIds.Add(id2); + original.AcceptedEventIds.Add(id3); + + var bytes = original.ToByteArray(); + var deserialized = IngestAck.Parser.ParseFrom(bytes); + + Assert.Equal(3, deserialized.AcceptedEventIds.Count); + Assert.Equal(id1, deserialized.AcceptedEventIds[0]); + Assert.Equal(id2, deserialized.AcceptedEventIds[1]); + Assert.Equal(id3, deserialized.AcceptedEventIds[2]); + } +}