diff --git a/src/ScadaLink.Communication/Grpc/AuditEventDtoMapper.cs b/src/ScadaLink.Communication/Grpc/AuditEventDtoMapper.cs
index 640cb13..a2fe2ee 100644
--- a/src/ScadaLink.Communication/Grpc/AuditEventDtoMapper.cs
+++ b/src/ScadaLink.Communication/Grpc/AuditEventDtoMapper.cs
@@ -50,6 +50,7 @@ public static class AuditEventDtoMapper
ExecutionId = evt.ExecutionId?.ToString() ?? string.Empty,
ParentExecutionId = evt.ParentExecutionId?.ToString() ?? string.Empty,
SourceSiteId = evt.SourceSiteId ?? string.Empty,
+ SourceNode = evt.SourceNode ?? string.Empty,
SourceInstanceId = evt.SourceInstanceId ?? string.Empty,
SourceScript = evt.SourceScript ?? string.Empty,
Actor = evt.Actor ?? string.Empty,
@@ -97,6 +98,7 @@ public static class AuditEventDtoMapper
ExecutionId = NullIfEmpty(dto.ExecutionId) is { } eid ? Guid.Parse(eid) : null,
ParentExecutionId = NullIfEmpty(dto.ParentExecutionId) is { } pid ? Guid.Parse(pid) : null,
SourceSiteId = NullIfEmpty(dto.SourceSiteId),
+ SourceNode = NullIfEmpty(dto.SourceNode),
SourceInstanceId = NullIfEmpty(dto.SourceInstanceId),
SourceScript = NullIfEmpty(dto.SourceScript),
Actor = NullIfEmpty(dto.Actor),
diff --git a/src/ScadaLink.Communication/Grpc/SiteCallDtoMapper.cs b/src/ScadaLink.Communication/Grpc/SiteCallDtoMapper.cs
index c61e3e5..c3e7ab3 100644
--- a/src/ScadaLink.Communication/Grpc/SiteCallDtoMapper.cs
+++ b/src/ScadaLink.Communication/Grpc/SiteCallDtoMapper.cs
@@ -55,6 +55,7 @@ public static class SiteCallDtoMapper
Channel = dto.Channel,
Target = dto.Target,
SourceSite = dto.SourceSite,
+ SourceNode = string.IsNullOrEmpty(dto.SourceNode) ? null : dto.SourceNode,
Status = dto.Status,
RetryCount = dto.RetryCount,
LastError = string.IsNullOrEmpty(dto.LastError) ? null : dto.LastError,
diff --git a/src/ScadaLink.Communication/Protos/sitestream.proto b/src/ScadaLink.Communication/Protos/sitestream.proto
index dccad81..1d8e4b2 100644
--- a/src/ScadaLink.Communication/Protos/sitestream.proto
+++ b/src/ScadaLink.Communication/Protos/sitestream.proto
@@ -93,6 +93,7 @@ message AuditEventDto {
string extra = 19;
string execution_id = 20; // empty string represents null
string parent_execution_id = 21; // empty string represents null
+ string source_node = 22; // empty string represents null
}
message AuditEventBatch { repeated AuditEventDto events = 1; }
@@ -114,6 +115,7 @@ message SiteCallOperationalDto {
google.protobuf.Timestamp created_at_utc = 9;
google.protobuf.Timestamp updated_at_utc = 10;
google.protobuf.Timestamp terminal_at_utc = 11; // absent when not terminal
+ string source_node = 12; // empty string represents null
}
message CachedTelemetryPacket {
diff --git a/src/ScadaLink.Communication/SiteStreamGrpc/Sitestream.cs b/src/ScadaLink.Communication/SiteStreamGrpc/Sitestream.cs
index 41e11e4..0732cde 100644
--- a/src/ScadaLink.Communication/SiteStreamGrpc/Sitestream.cs
+++ b/src/ScadaLink.Communication/SiteStreamGrpc/Sitestream.cs
@@ -41,7 +41,7 @@ namespace ScadaLink.Communication.Grpc {
"c3RhdGUYAyABKA4yGi5zaXRlc3RyZWFtLkFsYXJtU3RhdGVFbnVtEhAKCHBy",
"aW9yaXR5GAQgASgFEi0KCXRpbWVzdGFtcBgFIAEoCzIaLmdvb2dsZS5wcm90",
"b2J1Zi5UaW1lc3RhbXASKQoFbGV2ZWwYBiABKA4yGi5zaXRlc3RyZWFtLkFs",
- "YXJtTGV2ZWxFbnVtEg8KB21lc3NhZ2UYByABKAkiqAQKDUF1ZGl0RXZlbnRE",
+ "YXJtTGV2ZWxFbnVtEg8KB21lc3NhZ2UYByABKAkivQQKDUF1ZGl0RXZlbnRE",
"dG8SEAoIZXZlbnRfaWQYASABKAkSMwoPb2NjdXJyZWRfYXRfdXRjGAIgASgL",
"MhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIPCgdjaGFubmVsGAMgASgJ",
"EgwKBGtpbmQYBCABKAkSFgoOY29ycmVsYXRpb25faWQYBSABKAkSFgoOc291",
@@ -53,43 +53,44 @@ namespace ScadaLink.Communication.Grpc {
"bWVzc2FnZRgOIAEoCRIUCgxlcnJvcl9kZXRhaWwYDyABKAkSFwoPcmVxdWVz",
"dF9zdW1tYXJ5GBAgASgJEhgKEHJlc3BvbnNlX3N1bW1hcnkYESABKAkSGQoR",
"cGF5bG9hZF90cnVuY2F0ZWQYEiABKAgSDQoFZXh0cmEYEyABKAkSFAoMZXhl",
- "Y3V0aW9uX2lkGBQgASgJEhsKE3BhcmVudF9leGVjdXRpb25faWQYFSABKAki",
- "PAoPQXVkaXRFdmVudEJhdGNoEikKBmV2ZW50cxgBIAMoCzIZLnNpdGVzdHJl",
- "YW0uQXVkaXRFdmVudER0byInCglJbmdlc3RBY2sSGgoSYWNjZXB0ZWRfZXZl",
- "bnRfaWRzGAEgAygJIvQCChZTaXRlQ2FsbE9wZXJhdGlvbmFsRHRvEhwKFHRy",
- "YWNrZWRfb3BlcmF0aW9uX2lkGAEgASgJEg8KB2NoYW5uZWwYAiABKAkSDgoG",
- "dGFyZ2V0GAMgASgJEhMKC3NvdXJjZV9zaXRlGAQgASgJEg4KBnN0YXR1cxgF",
- "IAEoCRITCgtyZXRyeV9jb3VudBgGIAEoBRISCgpsYXN0X2Vycm9yGAcgASgJ",
- "EjAKC2h0dHBfc3RhdHVzGAggASgLMhsuZ29vZ2xlLnByb3RvYnVmLkludDMy",
- "VmFsdWUSMgoOY3JlYXRlZF9hdF91dGMYCSABKAsyGi5nb29nbGUucHJvdG9i",
- "dWYuVGltZXN0YW1wEjIKDnVwZGF0ZWRfYXRfdXRjGAogASgLMhouZ29vZ2xl",
- "LnByb3RvYnVmLlRpbWVzdGFtcBIzCg90ZXJtaW5hbF9hdF91dGMYCyABKAsy",
- "Gi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wIoABChVDYWNoZWRUZWxlbWV0",
- "cnlQYWNrZXQSLgoLYXVkaXRfZXZlbnQYASABKAsyGS5zaXRlc3RyZWFtLkF1",
- "ZGl0RXZlbnREdG8SNwoLb3BlcmF0aW9uYWwYAiABKAsyIi5zaXRlc3RyZWFt",
- "LlNpdGVDYWxsT3BlcmF0aW9uYWxEdG8iSgoUQ2FjaGVkVGVsZW1ldHJ5QmF0",
- "Y2gSMgoHcGFja2V0cxgBIAMoCzIhLnNpdGVzdHJlYW0uQ2FjaGVkVGVsZW1l",
- "dHJ5UGFja2V0IlsKFlB1bGxBdWRpdEV2ZW50c1JlcXVlc3QSLQoJc2luY2Vf",
- "dXRjGAEgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBISCgpiYXRj",
- "aF9zaXplGAIgASgFIlwKF1B1bGxBdWRpdEV2ZW50c1Jlc3BvbnNlEikKBmV2",
- "ZW50cxgBIAMoCzIZLnNpdGVzdHJlYW0uQXVkaXRFdmVudER0bxIWCg5tb3Jl",
- "X2F2YWlsYWJsZRgCIAEoCCpcCgdRdWFsaXR5EhcKE1FVQUxJVFlfVU5TUEVD",
- "SUZJRUQQABIQCgxRVUFMSVRZX0dPT0QQARIVChFRVUFMSVRZX1VOQ0VSVEFJ",
- "ThACEg8KC1FVQUxJVFlfQkFEEAMqXQoOQWxhcm1TdGF0ZUVudW0SGwoXQUxB",
- "Uk1fU1RBVEVfVU5TUEVDSUZJRUQQABIWChJBTEFSTV9TVEFURV9OT1JNQUwQ",
- "ARIWChJBTEFSTV9TVEFURV9BQ1RJVkUQAiqFAQoOQWxhcm1MZXZlbEVudW0S",
- "FAoQQUxBUk1fTEVWRUxfTk9ORRAAEhMKD0FMQVJNX0xFVkVMX0xPVxABEhcK",
- "E0FMQVJNX0xFVkVMX0xPV19MT1cQAhIUChBBTEFSTV9MRVZFTF9ISUdIEAMS",
- "GQoVQUxBUk1fTEVWRUxfSElHSF9ISUdIEAQy4QIKEVNpdGVTdHJlYW1TZXJ2",
- "aWNlElUKEVN1YnNjcmliZUluc3RhbmNlEiEuc2l0ZXN0cmVhbS5JbnN0YW5j",
- "ZVN0cmVhbVJlcXVlc3QaGy5zaXRlc3RyZWFtLlNpdGVTdHJlYW1FdmVudDAB",
- "EkcKEUluZ2VzdEF1ZGl0RXZlbnRzEhsuc2l0ZXN0cmVhbS5BdWRpdEV2ZW50",
- "QmF0Y2gaFS5zaXRlc3RyZWFtLkluZ2VzdEFjaxJQChVJbmdlc3RDYWNoZWRU",
- "ZWxlbWV0cnkSIC5zaXRlc3RyZWFtLkNhY2hlZFRlbGVtZXRyeUJhdGNoGhUu",
- "c2l0ZXN0cmVhbS5Jbmdlc3RBY2sSWgoPUHVsbEF1ZGl0RXZlbnRzEiIuc2l0",
- "ZXN0cmVhbS5QdWxsQXVkaXRFdmVudHNSZXF1ZXN0GiMuc2l0ZXN0cmVhbS5Q",
- "dWxsQXVkaXRFdmVudHNSZXNwb25zZUIfqgIcU2NhZGFMaW5rLkNvbW11bmlj",
- "YXRpb24uR3JwY2IGcHJvdG8z"));
+ "Y3V0aW9uX2lkGBQgASgJEhsKE3BhcmVudF9leGVjdXRpb25faWQYFSABKAkS",
+ "EwoLc291cmNlX25vZGUYFiABKAkiPAoPQXVkaXRFdmVudEJhdGNoEikKBmV2",
+ "ZW50cxgBIAMoCzIZLnNpdGVzdHJlYW0uQXVkaXRFdmVudER0byInCglJbmdl",
+ "c3RBY2sSGgoSYWNjZXB0ZWRfZXZlbnRfaWRzGAEgAygJIokDChZTaXRlQ2Fs",
+ "bE9wZXJhdGlvbmFsRHRvEhwKFHRyYWNrZWRfb3BlcmF0aW9uX2lkGAEgASgJ",
+ "Eg8KB2NoYW5uZWwYAiABKAkSDgoGdGFyZ2V0GAMgASgJEhMKC3NvdXJjZV9z",
+ "aXRlGAQgASgJEg4KBnN0YXR1cxgFIAEoCRITCgtyZXRyeV9jb3VudBgGIAEo",
+ "BRISCgpsYXN0X2Vycm9yGAcgASgJEjAKC2h0dHBfc3RhdHVzGAggASgLMhsu",
+ "Z29vZ2xlLnByb3RvYnVmLkludDMyVmFsdWUSMgoOY3JlYXRlZF9hdF91dGMY",
+ "CSABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEjIKDnVwZGF0ZWRf",
+ "YXRfdXRjGAogASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIzCg90",
+ "ZXJtaW5hbF9hdF91dGMYCyABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0",
+ "YW1wEhMKC3NvdXJjZV9ub2RlGAwgASgJIoABChVDYWNoZWRUZWxlbWV0cnlQ",
+ "YWNrZXQSLgoLYXVkaXRfZXZlbnQYASABKAsyGS5zaXRlc3RyZWFtLkF1ZGl0",
+ "RXZlbnREdG8SNwoLb3BlcmF0aW9uYWwYAiABKAsyIi5zaXRlc3RyZWFtLlNp",
+ "dGVDYWxsT3BlcmF0aW9uYWxEdG8iSgoUQ2FjaGVkVGVsZW1ldHJ5QmF0Y2gS",
+ "MgoHcGFja2V0cxgBIAMoCzIhLnNpdGVzdHJlYW0uQ2FjaGVkVGVsZW1ldHJ5",
+ "UGFja2V0IlsKFlB1bGxBdWRpdEV2ZW50c1JlcXVlc3QSLQoJc2luY2VfdXRj",
+ "GAEgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBISCgpiYXRjaF9z",
+ "aXplGAIgASgFIlwKF1B1bGxBdWRpdEV2ZW50c1Jlc3BvbnNlEikKBmV2ZW50",
+ "cxgBIAMoCzIZLnNpdGVzdHJlYW0uQXVkaXRFdmVudER0bxIWCg5tb3JlX2F2",
+ "YWlsYWJsZRgCIAEoCCpcCgdRdWFsaXR5EhcKE1FVQUxJVFlfVU5TUEVDSUZJ",
+ "RUQQABIQCgxRVUFMSVRZX0dPT0QQARIVChFRVUFMSVRZX1VOQ0VSVEFJThAC",
+ "Eg8KC1FVQUxJVFlfQkFEEAMqXQoOQWxhcm1TdGF0ZUVudW0SGwoXQUxBUk1f",
+ "U1RBVEVfVU5TUEVDSUZJRUQQABIWChJBTEFSTV9TVEFURV9OT1JNQUwQARIW",
+ "ChJBTEFSTV9TVEFURV9BQ1RJVkUQAiqFAQoOQWxhcm1MZXZlbEVudW0SFAoQ",
+ "QUxBUk1fTEVWRUxfTk9ORRAAEhMKD0FMQVJNX0xFVkVMX0xPVxABEhcKE0FM",
+ "QVJNX0xFVkVMX0xPV19MT1cQAhIUChBBTEFSTV9MRVZFTF9ISUdIEAMSGQoV",
+ "QUxBUk1fTEVWRUxfSElHSF9ISUdIEAQy4QIKEVNpdGVTdHJlYW1TZXJ2aWNl",
+ "ElUKEVN1YnNjcmliZUluc3RhbmNlEiEuc2l0ZXN0cmVhbS5JbnN0YW5jZVN0",
+ "cmVhbVJlcXVlc3QaGy5zaXRlc3RyZWFtLlNpdGVTdHJlYW1FdmVudDABEkcK",
+ "EUluZ2VzdEF1ZGl0RXZlbnRzEhsuc2l0ZXN0cmVhbS5BdWRpdEV2ZW50QmF0",
+ "Y2gaFS5zaXRlc3RyZWFtLkluZ2VzdEFjaxJQChVJbmdlc3RDYWNoZWRUZWxl",
+ "bWV0cnkSIC5zaXRlc3RyZWFtLkNhY2hlZFRlbGVtZXRyeUJhdGNoGhUuc2l0",
+ "ZXN0cmVhbS5Jbmdlc3RBY2sSWgoPUHVsbEF1ZGl0RXZlbnRzEiIuc2l0ZXN0",
+ "cmVhbS5QdWxsQXVkaXRFdmVudHNSZXF1ZXN0GiMuc2l0ZXN0cmVhbS5QdWxs",
+ "QXVkaXRFdmVudHNSZXNwb25zZUIfqgIcU2NhZGFMaW5rLkNvbW11bmljYXRp",
+ "b24uR3JwY2IGcHJvdG8z"));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
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[] {
@@ -97,10 +98,10 @@ namespace ScadaLink.Communication.Grpc {
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.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", "ExecutionId", "ParentExecutionId" }, 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", "ExecutionId", "ParentExecutionId", "SourceNode" }, 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),
- new pbr::GeneratedClrTypeInfo(typeof(global::ScadaLink.Communication.Grpc.SiteCallOperationalDto), global::ScadaLink.Communication.Grpc.SiteCallOperationalDto.Parser, new[]{ "TrackedOperationId", "Channel", "Target", "SourceSite", "Status", "RetryCount", "LastError", "HttpStatus", "CreatedAtUtc", "UpdatedAtUtc", "TerminalAtUtc" }, null, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::ScadaLink.Communication.Grpc.SiteCallOperationalDto), global::ScadaLink.Communication.Grpc.SiteCallOperationalDto.Parser, new[]{ "TrackedOperationId", "Channel", "Target", "SourceSite", "Status", "RetryCount", "LastError", "HttpStatus", "CreatedAtUtc", "UpdatedAtUtc", "TerminalAtUtc", "SourceNode" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::ScadaLink.Communication.Grpc.CachedTelemetryPacket), global::ScadaLink.Communication.Grpc.CachedTelemetryPacket.Parser, new[]{ "AuditEvent", "Operational" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::ScadaLink.Communication.Grpc.CachedTelemetryBatch), global::ScadaLink.Communication.Grpc.CachedTelemetryBatch.Parser, new[]{ "Packets" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::ScadaLink.Communication.Grpc.PullAuditEventsRequest), global::ScadaLink.Communication.Grpc.PullAuditEventsRequest.Parser, new[]{ "SinceUtc", "BatchSize" }, null, null, null, null),
@@ -1594,6 +1595,7 @@ namespace ScadaLink.Communication.Grpc {
extra_ = other.extra_;
executionId_ = other.executionId_;
parentExecutionId_ = other.parentExecutionId_;
+ sourceNode_ = other.sourceNode_;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
@@ -1871,6 +1873,21 @@ namespace ScadaLink.Communication.Grpc {
}
}
+ /// Field number for the "source_node" field.
+ public const int SourceNodeFieldNumber = 22;
+ private string sourceNode_ = "";
+ ///
+ /// empty string represents null
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public string SourceNode {
+ get { return sourceNode_; }
+ set {
+ sourceNode_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override bool Equals(object other) {
@@ -1907,6 +1924,7 @@ namespace ScadaLink.Communication.Grpc {
if (Extra != other.Extra) return false;
if (ExecutionId != other.ExecutionId) return false;
if (ParentExecutionId != other.ParentExecutionId) return false;
+ if (SourceNode != other.SourceNode) return false;
return Equals(_unknownFields, other._unknownFields);
}
@@ -1935,6 +1953,7 @@ namespace ScadaLink.Communication.Grpc {
if (Extra.Length != 0) hash ^= Extra.GetHashCode();
if (ExecutionId.Length != 0) hash ^= ExecutionId.GetHashCode();
if (ParentExecutionId.Length != 0) hash ^= ParentExecutionId.GetHashCode();
+ if (SourceNode.Length != 0) hash ^= SourceNode.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
@@ -2035,6 +2054,10 @@ namespace ScadaLink.Communication.Grpc {
output.WriteRawTag(170, 1);
output.WriteString(ParentExecutionId);
}
+ if (SourceNode.Length != 0) {
+ output.WriteRawTag(178, 1);
+ output.WriteString(SourceNode);
+ }
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
@@ -2127,6 +2150,10 @@ namespace ScadaLink.Communication.Grpc {
output.WriteRawTag(170, 1);
output.WriteString(ParentExecutionId);
}
+ if (SourceNode.Length != 0) {
+ output.WriteRawTag(178, 1);
+ output.WriteString(SourceNode);
+ }
if (_unknownFields != null) {
_unknownFields.WriteTo(ref output);
}
@@ -2200,6 +2227,9 @@ namespace ScadaLink.Communication.Grpc {
if (ParentExecutionId.Length != 0) {
size += 2 + pb::CodedOutputStream.ComputeStringSize(ParentExecutionId);
}
+ if (SourceNode.Length != 0) {
+ size += 2 + pb::CodedOutputStream.ComputeStringSize(SourceNode);
+ }
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
@@ -2282,6 +2312,9 @@ namespace ScadaLink.Communication.Grpc {
if (other.ParentExecutionId.Length != 0) {
ParentExecutionId = other.ParentExecutionId;
}
+ if (other.SourceNode.Length != 0) {
+ SourceNode = other.SourceNode;
+ }
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
@@ -2394,6 +2427,10 @@ namespace ScadaLink.Communication.Grpc {
ParentExecutionId = input.ReadString();
break;
}
+ case 178: {
+ SourceNode = input.ReadString();
+ break;
+ }
}
}
#endif
@@ -2506,6 +2543,10 @@ namespace ScadaLink.Communication.Grpc {
ParentExecutionId = input.ReadString();
break;
}
+ case 178: {
+ SourceNode = input.ReadString();
+ break;
+ }
}
}
}
@@ -2939,6 +2980,7 @@ namespace ScadaLink.Communication.Grpc {
createdAtUtc_ = other.createdAtUtc_ != null ? other.createdAtUtc_.Clone() : null;
updatedAtUtc_ = other.updatedAtUtc_ != null ? other.updatedAtUtc_.Clone() : null;
terminalAtUtc_ = other.terminalAtUtc_ != null ? other.terminalAtUtc_.Clone() : null;
+ sourceNode_ = other.sourceNode_;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
@@ -3097,6 +3139,21 @@ namespace ScadaLink.Communication.Grpc {
}
}
+ /// Field number for the "source_node" field.
+ public const int SourceNodeFieldNumber = 12;
+ private string sourceNode_ = "";
+ ///
+ /// empty string represents null
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public string SourceNode {
+ get { return sourceNode_; }
+ set {
+ sourceNode_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override bool Equals(object other) {
@@ -3123,6 +3180,7 @@ namespace ScadaLink.Communication.Grpc {
if (!object.Equals(CreatedAtUtc, other.CreatedAtUtc)) return false;
if (!object.Equals(UpdatedAtUtc, other.UpdatedAtUtc)) return false;
if (!object.Equals(TerminalAtUtc, other.TerminalAtUtc)) return false;
+ if (SourceNode != other.SourceNode) return false;
return Equals(_unknownFields, other._unknownFields);
}
@@ -3141,6 +3199,7 @@ namespace ScadaLink.Communication.Grpc {
if (createdAtUtc_ != null) hash ^= CreatedAtUtc.GetHashCode();
if (updatedAtUtc_ != null) hash ^= UpdatedAtUtc.GetHashCode();
if (terminalAtUtc_ != null) hash ^= TerminalAtUtc.GetHashCode();
+ if (SourceNode.Length != 0) hash ^= SourceNode.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
@@ -3202,6 +3261,10 @@ namespace ScadaLink.Communication.Grpc {
output.WriteRawTag(90);
output.WriteMessage(TerminalAtUtc);
}
+ if (SourceNode.Length != 0) {
+ output.WriteRawTag(98);
+ output.WriteString(SourceNode);
+ }
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
@@ -3255,6 +3318,10 @@ namespace ScadaLink.Communication.Grpc {
output.WriteRawTag(90);
output.WriteMessage(TerminalAtUtc);
}
+ if (SourceNode.Length != 0) {
+ output.WriteRawTag(98);
+ output.WriteString(SourceNode);
+ }
if (_unknownFields != null) {
_unknownFields.WriteTo(ref output);
}
@@ -3298,6 +3365,9 @@ namespace ScadaLink.Communication.Grpc {
if (terminalAtUtc_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(TerminalAtUtc);
}
+ if (SourceNode.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(SourceNode);
+ }
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
@@ -3354,6 +3424,9 @@ namespace ScadaLink.Communication.Grpc {
}
TerminalAtUtc.MergeFrom(other.TerminalAtUtc);
}
+ if (other.SourceNode.Length != 0) {
+ SourceNode = other.SourceNode;
+ }
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
@@ -3429,6 +3502,10 @@ namespace ScadaLink.Communication.Grpc {
input.ReadMessage(TerminalAtUtc);
break;
}
+ case 98: {
+ SourceNode = input.ReadString();
+ break;
+ }
}
}
#endif
@@ -3504,6 +3581,10 @@ namespace ScadaLink.Communication.Grpc {
input.ReadMessage(TerminalAtUtc);
break;
}
+ case 98: {
+ SourceNode = input.ReadString();
+ break;
+ }
}
}
}
diff --git a/tests/ScadaLink.AuditLog.Tests/Integration/Infrastructure/CombinedTelemetryDispatcher.cs b/tests/ScadaLink.AuditLog.Tests/Integration/Infrastructure/CombinedTelemetryDispatcher.cs
index 77c40aa..a18a2fc 100644
--- a/tests/ScadaLink.AuditLog.Tests/Integration/Infrastructure/CombinedTelemetryDispatcher.cs
+++ b/tests/ScadaLink.AuditLog.Tests/Integration/Infrastructure/CombinedTelemetryDispatcher.cs
@@ -100,6 +100,7 @@ public sealed class CombinedTelemetryDispatcher : ICachedCallTelemetryForwarder
Channel = op.Channel,
Target = op.Target,
SourceSite = op.SourceSite,
+ SourceNode = op.SourceNode ?? string.Empty,
Status = op.Status,
RetryCount = op.RetryCount,
LastError = op.LastError ?? string.Empty,
diff --git a/tests/ScadaLink.Communication.Tests/AuditEventDtoMapperTests.cs b/tests/ScadaLink.Communication.Tests/AuditEventDtoMapperTests.cs
index 06d1239..caf9e99 100644
--- a/tests/ScadaLink.Communication.Tests/AuditEventDtoMapperTests.cs
+++ b/tests/ScadaLink.Communication.Tests/AuditEventDtoMapperTests.cs
@@ -34,6 +34,7 @@ public class AuditEventDtoMapperTests
ExecutionId = executionId,
ParentExecutionId = parentExecutionId,
SourceSiteId = "site-1",
+ SourceNode = "node-a",
SourceInstanceId = "Pump01",
SourceScript = "OnDemand",
Actor = "design-key",
@@ -61,6 +62,7 @@ public class AuditEventDtoMapperTests
Assert.Equal(original.ExecutionId, roundTripped.ExecutionId);
Assert.Equal(original.ParentExecutionId, roundTripped.ParentExecutionId);
Assert.Equal(original.SourceSiteId, roundTripped.SourceSiteId);
+ Assert.Equal(original.SourceNode, roundTripped.SourceNode);
Assert.Equal(original.SourceInstanceId, roundTripped.SourceInstanceId);
Assert.Equal(original.SourceScript, roundTripped.SourceScript);
Assert.Equal(original.Actor, roundTripped.Actor);
@@ -99,6 +101,7 @@ public class AuditEventDtoMapperTests
Assert.Equal(string.Empty, dto.ExecutionId);
Assert.Equal(string.Empty, dto.ParentExecutionId);
Assert.Equal(string.Empty, dto.SourceSiteId);
+ Assert.Equal(string.Empty, dto.SourceNode);
Assert.Equal(string.Empty, dto.SourceInstanceId);
Assert.Equal(string.Empty, dto.SourceScript);
Assert.Equal(string.Empty, dto.Actor);
@@ -124,6 +127,7 @@ public class AuditEventDtoMapperTests
ExecutionId = string.Empty,
ParentExecutionId = string.Empty,
SourceSiteId = string.Empty,
+ SourceNode = string.Empty,
SourceInstanceId = string.Empty,
SourceScript = string.Empty,
Actor = string.Empty,
@@ -141,6 +145,7 @@ public class AuditEventDtoMapperTests
Assert.Null(evt.ExecutionId);
Assert.Null(evt.ParentExecutionId);
Assert.Null(evt.SourceSiteId);
+ Assert.Null(evt.SourceNode);
Assert.Null(evt.SourceInstanceId);
Assert.Null(evt.SourceScript);
Assert.Null(evt.Actor);
@@ -232,4 +237,52 @@ public class AuditEventDtoMapperTests
Assert.Equal("ApiCallCached", dto.Kind);
Assert.Equal("Parked", dto.Status);
}
+
+ [Fact]
+ public void AuditEventDto_round_trip_preserves_SourceNode()
+ {
+ var evt = new AuditEvent
+ {
+ EventId = Guid.NewGuid(),
+ OccurredAtUtc = DateTime.UtcNow,
+ Channel = AuditChannel.ApiOutbound,
+ Kind = AuditKind.ApiCall,
+ Status = AuditStatus.Delivered,
+ SourceNode = "node-a"
+ };
+
+ var dto = AuditEventDtoMapper.ToDto(evt);
+
+ // Wire form: empty-string-means-null convention; populated value
+ // travels verbatim.
+ Assert.Equal("node-a", dto.SourceNode);
+
+ var roundTripped = AuditEventDtoMapper.FromDto(dto);
+
+ Assert.Equal("node-a", roundTripped.SourceNode);
+ }
+
+ [Fact]
+ public void AuditEventDto_round_trip_preserves_null_SourceNode()
+ {
+ var evt = new AuditEvent
+ {
+ EventId = Guid.NewGuid(),
+ OccurredAtUtc = DateTime.UtcNow,
+ Channel = AuditChannel.ApiOutbound,
+ Kind = AuditKind.ApiCall,
+ Status = AuditStatus.Delivered,
+ SourceNode = null
+ };
+
+ var dto = AuditEventDtoMapper.ToDto(evt);
+
+ // ToDto collapses null → empty on the wire…
+ Assert.Equal(string.Empty, dto.SourceNode);
+
+ var roundTripped = AuditEventDtoMapper.FromDto(dto);
+
+ // …and FromDto rehydrates empty → null.
+ Assert.Null(roundTripped.SourceNode);
+ }
}
diff --git a/tests/ScadaLink.Communication.Tests/Protos/AuditEventProtoTests.cs b/tests/ScadaLink.Communication.Tests/Protos/AuditEventProtoTests.cs
index 4cd0d48..632c8b5 100644
--- a/tests/ScadaLink.Communication.Tests/Protos/AuditEventProtoTests.cs
+++ b/tests/ScadaLink.Communication.Tests/Protos/AuditEventProtoTests.cs
@@ -25,6 +25,7 @@ public class AuditEventProtoTests
Kind = "ApiCall",
CorrelationId = Guid.NewGuid().ToString(),
SourceSiteId = "site-1",
+ SourceNode = "node-a",
SourceInstanceId = "Pump01",
SourceScript = "OnDemand",
Actor = "design-key",
@@ -49,6 +50,7 @@ public class AuditEventProtoTests
Assert.Equal(original.Kind, deserialized.Kind);
Assert.Equal(original.CorrelationId, deserialized.CorrelationId);
Assert.Equal(original.SourceSiteId, deserialized.SourceSiteId);
+ Assert.Equal(original.SourceNode, deserialized.SourceNode);
Assert.Equal(original.SourceInstanceId, deserialized.SourceInstanceId);
Assert.Equal(original.SourceScript, deserialized.SourceScript);
Assert.Equal(original.Actor, deserialized.Actor);
diff --git a/tests/ScadaLink.Communication.Tests/Protos/CachedTelemetryProtoTests.cs b/tests/ScadaLink.Communication.Tests/Protos/CachedTelemetryProtoTests.cs
index 4405768..10d9e9b 100644
--- a/tests/ScadaLink.Communication.Tests/Protos/CachedTelemetryProtoTests.cs
+++ b/tests/ScadaLink.Communication.Tests/Protos/CachedTelemetryProtoTests.cs
@@ -39,6 +39,7 @@ public class CachedTelemetryProtoTests
Channel = "ApiOutbound",
Target = "ERP.GetOrder",
SourceSite = "site-melbourne",
+ SourceNode = "node-a",
Status = "Delivered",
RetryCount = 3,
LastError = "transient 503",
@@ -55,6 +56,7 @@ public class CachedTelemetryProtoTests
Assert.Equal(original.Channel, deserialized.Channel);
Assert.Equal(original.Target, deserialized.Target);
Assert.Equal(original.SourceSite, deserialized.SourceSite);
+ Assert.Equal(original.SourceNode, deserialized.SourceNode);
Assert.Equal(original.Status, deserialized.Status);
Assert.Equal(original.RetryCount, deserialized.RetryCount);
Assert.Equal(original.LastError, deserialized.LastError);
diff --git a/tests/ScadaLink.Communication.Tests/SiteCallDtoMapperTests.cs b/tests/ScadaLink.Communication.Tests/SiteCallDtoMapperTests.cs
index 4de1d37..d9aa0bc 100644
--- a/tests/ScadaLink.Communication.Tests/SiteCallDtoMapperTests.cs
+++ b/tests/ScadaLink.Communication.Tests/SiteCallDtoMapperTests.cs
@@ -1,3 +1,4 @@
+using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ScadaLink.Communication.Grpc;
@@ -28,6 +29,7 @@ public class SiteCallDtoMapperTests
Channel = "ApiOutbound",
Target = "ERP.GetOrder",
SourceSite = "site-melbourne",
+ SourceNode = "node-a",
Status = "Delivered",
RetryCount = 3,
LastError = "transient 503",
@@ -43,6 +45,7 @@ public class SiteCallDtoMapperTests
Assert.Equal("ApiOutbound", entity.Channel);
Assert.Equal("ERP.GetOrder", entity.Target);
Assert.Equal("site-melbourne", entity.SourceSite);
+ Assert.Equal("node-a", entity.SourceNode);
Assert.Equal("Delivered", entity.Status);
Assert.Equal(3, entity.RetryCount);
Assert.Equal("transient 503", entity.LastError);
@@ -121,6 +124,40 @@ public class SiteCallDtoMapperTests
Assert.Throws(() => SiteCallDtoMapper.FromDto(null!));
}
+ [Fact]
+ public void SiteCallOperationalDto_round_trip_preserves_SourceNode()
+ {
+ // Populated SourceNode travels verbatim across the wire and through
+ // the DTO→entity mapper.
+ var dto = NewMinimalDto();
+ dto.SourceNode = "node-a";
+
+ var bytes = dto.ToByteArray();
+ var onWire = SiteCallOperationalDto.Parser.ParseFrom(bytes);
+ Assert.Equal("node-a", onWire.SourceNode);
+
+ var entity = SiteCallDtoMapper.FromDto(onWire);
+
+ Assert.Equal("node-a", entity.SourceNode);
+ }
+
+ [Fact]
+ public void SiteCallOperationalDto_round_trip_preserves_null_SourceNode()
+ {
+ // The DTO uses an empty-string-means-null convention on the wire;
+ // FromDto rehydrates that back to a true null on the entity.
+ var dto = NewMinimalDto();
+ // SourceNode left at proto default (empty string) — semantically null.
+
+ var bytes = dto.ToByteArray();
+ var onWire = SiteCallOperationalDto.Parser.ParseFrom(bytes);
+ Assert.Equal(string.Empty, onWire.SourceNode);
+
+ var entity = SiteCallDtoMapper.FromDto(onWire);
+
+ Assert.Null(entity.SourceNode);
+ }
+
private static SiteCallOperationalDto NewMinimalDto() => new()
{
TrackedOperationId = Guid.NewGuid().ToString(),