Merge branch 'grpc-event-batching' — additive site-stream event batching, negotiated, 100ev/25ms window (residual #3 / R2)
This commit is contained in:
@@ -93,6 +93,20 @@ public static class ScadaBridgeTelemetry
|
||||
Meter.CreateCounter<long>("scadabridge.site.stream.events_dropped", unit: "1",
|
||||
description: "Events evicted from a site gRPC stream's bounded send channel, tagged by stream kind.");
|
||||
|
||||
// ---------------- Histograms ----------------
|
||||
|
||||
/// <summary>
|
||||
/// Distribution of how many events each site→central stream frame carried (R2 — gRPC
|
||||
/// event batching), tagged by stream kind. Recorded ONLY for subscriptions that
|
||||
/// negotiated batching, so the series' very existence says "this central speaks the
|
||||
/// batched wire". A distribution pinned at 1 means the coalescing window never sees a
|
||||
/// backlog (the site is quiet, or the window is too small to be earning anything);
|
||||
/// mass at the size cap means the cap, not the window, is the binding constraint.
|
||||
/// </summary>
|
||||
private static readonly Histogram<int> _siteStreamBatchSize =
|
||||
Meter.CreateHistogram<int>("scadabridge.site.stream.batch_size", unit: "1",
|
||||
description: "Events per site gRPC stream frame (1 = unbatched frame), tagged by stream kind.");
|
||||
|
||||
// ---------------- Observable gauges ----------------
|
||||
|
||||
/// <summary>Current count of open site connections, mutated via <see cref="Interlocked"/>.</summary>
|
||||
@@ -178,6 +192,16 @@ public static class ScadaBridgeTelemetry
|
||||
public static void RecordSiteStreamEventDropped(string streamKind) =>
|
||||
_siteStreamEventDrops.Add(1, new KeyValuePair<string, object?>("stream", streamKind));
|
||||
|
||||
/// <summary>
|
||||
/// Records how many events one site gRPC stream frame carried. Called once per emitted
|
||||
/// frame on a batching-negotiated subscription (never on an un-negotiated one, where it
|
||||
/// would degenerate into a per-event instrument on the hottest path in the product).
|
||||
/// </summary>
|
||||
/// <param name="streamKind">Stream kind tag (<c>instance</c> or <c>site-alarms</c>).</param>
|
||||
/// <param name="events">Events packed into the frame; 1 for a plain unbatched frame.</param>
|
||||
public static void RecordSiteStreamBatchSize(string streamKind, int events) =>
|
||||
_siteStreamBatchSize.Record(events, new KeyValuePair<string, object?>("stream", streamKind));
|
||||
|
||||
/// <summary>
|
||||
/// Registers the provider the StoreAndForward queue-depth gauge reads on each observation.
|
||||
/// A later task supplies a provider that reads the real StoreAndForward depth. A null
|
||||
|
||||
@@ -152,6 +152,26 @@ public class CommunicationOptions
|
||||
/// </summary>
|
||||
public int GrpcSiteAlarmStreamChannelCapacity { get; set; } = 20_000;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum events coalesced into one site→central stream frame (R2 — gRPC event
|
||||
/// batching). At target scale a site emits ~37.5k events/s and every one of them used to
|
||||
/// cost its own gRPC message; batching amortises that framing overhead. Set to 1 to
|
||||
/// disable batching on this node without a wire change (every frame then carries exactly
|
||||
/// one event, which is also what an un-negotiated subscription gets).
|
||||
/// </summary>
|
||||
public int GrpcStreamBatchMaxEvents { get; set; } = 100;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum time the site lingers accumulating a stream batch once a backlog has been
|
||||
/// observed. Deliberately small: the target-scale load test measures end-to-end event
|
||||
/// latency against a 250 ms P99 threshold (measured P99 4.57 ms), and this window is the
|
||||
/// only latency batching can add — so it is validated strictly below that threshold.
|
||||
/// A lone event on a quiet stream is never delayed by it (see
|
||||
/// <c>SiteStreamEventBatcher</c>); the window applies only after a backlog is proven.
|
||||
/// <see cref="TimeSpan.Zero"/> means "pack only what is already queued, never wait".
|
||||
/// </summary>
|
||||
public TimeSpan GrpcStreamBatchWindow { get; set; } = TimeSpan.FromMilliseconds(25);
|
||||
|
||||
/// <summary>Akka.Remote transport heartbeat interval.</summary>
|
||||
public TimeSpan TransportHeartbeatInterval { get; set; } = TimeSpan.FromSeconds(5);
|
||||
|
||||
|
||||
@@ -12,6 +12,14 @@ namespace ZB.MOM.WW.ScadaBridge.Communication;
|
||||
/// </summary>
|
||||
public sealed class CommunicationOptionsValidator : OptionsValidatorBase<CommunicationOptions>
|
||||
{
|
||||
/// <summary>
|
||||
/// Exclusive upper bound on <see cref="CommunicationOptions.GrpcStreamBatchWindow"/> —
|
||||
/// the end-to-end site→central event latency budget the target-scale load test asserts
|
||||
/// a P99 against. The coalescing window is the only latency batching introduces, so it
|
||||
/// must stay strictly inside that budget rather than consuming it whole.
|
||||
/// </summary>
|
||||
internal static readonly TimeSpan StreamBatchWindowCeiling = TimeSpan.FromMilliseconds(250);
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Validate(ValidationBuilder builder, CommunicationOptions options)
|
||||
{
|
||||
@@ -75,6 +83,23 @@ public sealed class CommunicationOptionsValidator : OptionsValidatorBase<Communi
|
||||
builder.RequireThat(options.GrpcMaxConcurrentStreams > 0,
|
||||
$"ScadaBridge:Communication:GrpcMaxConcurrentStreams must be positive (was {options.GrpcMaxConcurrentStreams}).");
|
||||
|
||||
// ── Site→central stream event batching (R2) ─────────────────────────────
|
||||
// 1 is legal and means "disabled" (one event per frame, the un-negotiated shape).
|
||||
builder.RequireThat(options.GrpcStreamBatchMaxEvents > 0,
|
||||
$"ScadaBridge:Communication:GrpcStreamBatchMaxEvents must be positive — 1 disables "
|
||||
+ $"batching (was {options.GrpcStreamBatchMaxEvents}).");
|
||||
|
||||
// The coalescing window is the ONLY latency batching can add, and the target-scale
|
||||
// load test holds end-to-end event latency to a 250 ms P99. Validate it strictly
|
||||
// below that so a misconfigured window cannot silently spend the entire budget.
|
||||
builder.RequireThat(
|
||||
options.GrpcStreamBatchWindow >= TimeSpan.Zero
|
||||
&& options.GrpcStreamBatchWindow < StreamBatchWindowCeiling,
|
||||
$"ScadaBridge:Communication:GrpcStreamBatchWindow must be non-negative and strictly "
|
||||
+ $"below {StreamBatchWindowCeiling.TotalMilliseconds:0} ms (the end-to-end stream "
|
||||
+ $"latency budget the coalescing window spends from); zero means \"pack only what is "
|
||||
+ $"already queued\" (was {options.GrpcStreamBatchWindow}).");
|
||||
|
||||
// The gRPC site→central transport needs at least one central endpoint to dial. gRPC is now
|
||||
// the only site→central transport (ClusterClient was removed in the migration's Phase 4), so
|
||||
// every site node must declare its central endpoints — there is no Akka fallback to ignore
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Channels;
|
||||
|
||||
namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc;
|
||||
|
||||
/// <summary>
|
||||
/// Per-subscriber coalescing pump that drains a stream's bounded send channel and writes
|
||||
/// it to the gRPC response stream, optionally packing several consecutive events into one
|
||||
/// <see cref="SiteStreamEventBatch"/> frame (R2 — gRPC event batching).
|
||||
///
|
||||
/// <para>
|
||||
/// <b>Where this sits.</b> Strictly DOWNSTREAM of <c>StreamRelayActor</c>'s bounded
|
||||
/// <c>DropOldest</c> channel, and one instance per subscriber. It therefore changes only
|
||||
/// how many gRPC frames a given set of events costs — it does <em>not</em> change the
|
||||
/// site's burst ceiling, which is set by the shared publish stage upstream of the
|
||||
/// BroadcastHub (deferred-work register row 31) and by the per-subscriber channel capacity.
|
||||
/// Events dropped by that channel are dropped before the batcher ever sees them.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// <b>Latency contract.</b> The pump never delays a lone event. It takes the first event,
|
||||
/// drains whatever is <em>already queued</em> behind it (which costs no time at all), and
|
||||
/// only then — having proven a backlog exists — lingers up to
|
||||
/// <paramref name="maxWindow"/> for more. A quiet stream is therefore byte-identical and
|
||||
/// latency-identical to the pre-batching wire: one plain
|
||||
/// <c>attribute_changed</c>/<c>alarm_changed</c> frame, emitted immediately. A saturated
|
||||
/// stream pays at most one window per batch, which is why the window is validated well
|
||||
/// under the 250 ms end-to-end latency threshold the target-scale load test measures
|
||||
/// against.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// <b>Ordering.</b> Events are emitted in the exact order they were read; a batch preserves
|
||||
/// that order inside <c>SiteStreamEventBatch.events</c>, and the client unpacks in order.
|
||||
/// Nothing is reordered or coalesced away — batching is purely a framing change.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
internal static class SiteStreamEventBatcher
|
||||
{
|
||||
/// <summary>
|
||||
/// Drains <paramref name="reader"/> until it completes or <paramref name="ct"/> is
|
||||
/// cancelled, writing frames through <paramref name="writeAsync"/>.
|
||||
///
|
||||
/// <para>
|
||||
/// Pass <paramref name="maxBatchEvents"/> = 1 to get the exact pre-batching behaviour
|
||||
/// (one frame per event, no window, no metric) — that is what an un-negotiated
|
||||
/// subscription uses, so an old central never sees a frame shape it cannot parse.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// When the channel writer completes with events still buffered, the buffered events
|
||||
/// are flushed as a final frame before the pump returns. Cancellation is deliberately
|
||||
/// NOT flushed: the token is cancelled precisely when the client is gone or the site is
|
||||
/// shutting down, so the write would fail anyway; the
|
||||
/// <see cref="OperationCanceledException"/> propagates to the caller exactly as the
|
||||
/// pre-batching <c>await foreach</c> did.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="reader">The subscriber's bounded send-channel reader.</param>
|
||||
/// <param name="correlationId">Correlation id stamped on an emitted batch frame.</param>
|
||||
/// <param name="maxBatchEvents">Hard cap on events per frame; 1 disables batching entirely.</param>
|
||||
/// <param name="maxWindow">Maximum time to linger accumulating a batch once a backlog is observed.</param>
|
||||
/// <param name="writeAsync">Writes one frame to the gRPC response stream.</param>
|
||||
/// <param name="onFrameEmitted">Optional observer of each emitted frame's event count (the batch-size histogram).</param>
|
||||
/// <param name="ct">Cancels the pump (client disconnect, duplicate replacement, shutdown, stream lifetime).</param>
|
||||
/// <returns>A task that completes when the channel is drained and closed.</returns>
|
||||
internal static async Task PumpAsync(
|
||||
ChannelReader<SiteStreamEvent> reader,
|
||||
string correlationId,
|
||||
int maxBatchEvents,
|
||||
TimeSpan maxWindow,
|
||||
Func<SiteStreamEvent, CancellationToken, Task> writeAsync,
|
||||
Action<int>? onFrameEmitted,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var buffer = new List<SiteStreamEvent>(Math.Max(1, Math.Min(maxBatchEvents, 256)));
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (!await reader.WaitToReadAsync(ct).ConfigureAwait(false))
|
||||
{
|
||||
// Writer completed and the channel is empty — normal end of stream.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!reader.TryRead(out var first))
|
||||
{
|
||||
// Raced another reader (there is only one, but WaitToReadAsync can also
|
||||
// wake on completion); loop round and re-evaluate.
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer.Clear();
|
||||
buffer.Add(first);
|
||||
|
||||
var writerCompleted = false;
|
||||
|
||||
if (maxBatchEvents > 1)
|
||||
{
|
||||
// Free drain: everything already sitting in the channel costs no latency.
|
||||
while (buffer.Count < maxBatchEvents && reader.TryRead(out var queued))
|
||||
{
|
||||
buffer.Add(queued);
|
||||
}
|
||||
|
||||
// Linger ONLY when a real backlog was observed. A single event on an
|
||||
// otherwise idle stream is emitted immediately — the window must never
|
||||
// become a floor on latency for the quiet case.
|
||||
if (buffer.Count > 1 && buffer.Count < maxBatchEvents && maxWindow > TimeSpan.Zero)
|
||||
{
|
||||
writerCompleted = await LingerAsync(
|
||||
reader, buffer, maxBatchEvents, maxWindow, ct).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
await EmitAsync(buffer, correlationId, writeAsync, onFrameEmitted, ct).ConfigureAwait(false);
|
||||
|
||||
if (writerCompleted)
|
||||
{
|
||||
// Flush-on-close: the buffered events above were the tail of the stream.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Accumulates further events into <paramref name="buffer"/> for at most
|
||||
/// <paramref name="maxWindow"/> from the moment the backlog was observed, or until the
|
||||
/// size cap is reached.
|
||||
/// </summary>
|
||||
/// <param name="reader">The subscriber's send-channel reader.</param>
|
||||
/// <param name="buffer">Batch under construction; appended to in arrival order.</param>
|
||||
/// <param name="maxBatchEvents">Hard cap on events per frame.</param>
|
||||
/// <param name="maxWindow">Maximum lingering time for this batch.</param>
|
||||
/// <param name="ct">Cancels the pump.</param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> when the channel writer completed while lingering (the caller
|
||||
/// must emit the buffer and then stop), otherwise <see langword="false"/>.
|
||||
/// </returns>
|
||||
private static async Task<bool> LingerAsync(
|
||||
ChannelReader<SiteStreamEvent> reader,
|
||||
List<SiteStreamEvent> buffer,
|
||||
int maxBatchEvents,
|
||||
TimeSpan maxWindow,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var started = Stopwatch.GetTimestamp();
|
||||
|
||||
while (buffer.Count < maxBatchEvents)
|
||||
{
|
||||
var remaining = maxWindow - Stopwatch.GetElapsedTime(started);
|
||||
if (remaining <= TimeSpan.Zero)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
using var lingerCts = CancellationTokenSource.CreateLinkedTokenSource(ct);
|
||||
lingerCts.CancelAfter(remaining);
|
||||
|
||||
bool more;
|
||||
try
|
||||
{
|
||||
more = await reader.WaitToReadAsync(lingerCts.Token).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException) when (!ct.IsCancellationRequested)
|
||||
{
|
||||
// The window elapsed — close the batch with what we have.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!more)
|
||||
{
|
||||
// Writer completed with the buffer non-empty: flush it, then stop.
|
||||
return true;
|
||||
}
|
||||
|
||||
while (buffer.Count < maxBatchEvents && reader.TryRead(out var queued))
|
||||
{
|
||||
buffer.Add(queued);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes <paramref name="buffer"/> as a single frame: a plain event frame when the
|
||||
/// buffer holds exactly one event (identical to the pre-batching wire), otherwise a
|
||||
/// <see cref="SiteStreamEventBatch"/> frame carrying them in order.
|
||||
/// </summary>
|
||||
/// <param name="buffer">Events to emit, in arrival order. Never empty.</param>
|
||||
/// <param name="correlationId">Correlation id for the enclosing batch frame.</param>
|
||||
/// <param name="writeAsync">Writes one frame to the gRPC response stream.</param>
|
||||
/// <param name="onFrameEmitted">Optional observer of the emitted frame's event count.</param>
|
||||
/// <param name="ct">Cancels the write.</param>
|
||||
/// <returns>A task that completes when the frame has been written.</returns>
|
||||
private static async Task EmitAsync(
|
||||
List<SiteStreamEvent> buffer,
|
||||
string correlationId,
|
||||
Func<SiteStreamEvent, CancellationToken, Task> writeAsync,
|
||||
Action<int>? onFrameEmitted,
|
||||
CancellationToken ct)
|
||||
{
|
||||
if (buffer.Count == 1)
|
||||
{
|
||||
await writeAsync(buffer[0], ct).ConfigureAwait(false);
|
||||
onFrameEmitted?.Invoke(1);
|
||||
return;
|
||||
}
|
||||
|
||||
var batch = new SiteStreamEventBatch();
|
||||
foreach (var evt in buffer)
|
||||
{
|
||||
// The enclosing frame carries the correlation id once for the whole batch;
|
||||
// clearing it on the inner events is the byte saving batching exists for.
|
||||
// No consumer reads the inner value (see SiteStreamGrpcClient.ForEachEvent).
|
||||
evt.CorrelationId = string.Empty;
|
||||
batch.Events.Add(evt);
|
||||
}
|
||||
|
||||
await writeAsync(
|
||||
new SiteStreamEvent { CorrelationId = correlationId, Batch = batch }, ct).ConfigureAwait(false);
|
||||
onFrameEmitted?.Invoke(buffer.Count);
|
||||
}
|
||||
}
|
||||
@@ -199,19 +199,25 @@ public class SiteStreamGrpcClient : IAsyncDisposable, IDisposable
|
||||
var request = new InstanceStreamRequest
|
||||
{
|
||||
CorrelationId = correlationId,
|
||||
InstanceUniqueName = instanceUniqueName
|
||||
InstanceUniqueName = instanceUniqueName,
|
||||
// R2 batch negotiation. Declaring support is safe against ANY site: one that
|
||||
// predates batching ignores the unknown field and keeps sending per-event
|
||||
// frames, which ForEachEvent handles as the single-event case.
|
||||
BatchingSupported = true
|
||||
};
|
||||
|
||||
void Deliver(SiteStreamEvent single)
|
||||
{
|
||||
var domainEvent = ConvertToDomainEvent(single);
|
||||
if (domainEvent != null)
|
||||
onEvent(domainEvent);
|
||||
}
|
||||
|
||||
await ConsumeStreamAsync(
|
||||
correlationId,
|
||||
cts,
|
||||
() => _client.SubscribeInstance(request, cancellationToken: cts.Token),
|
||||
evt =>
|
||||
{
|
||||
var domainEvent = ConvertToDomainEvent(evt);
|
||||
if (domainEvent != null)
|
||||
onEvent(domainEvent);
|
||||
},
|
||||
frame => ForEachEvent(frame, Deliver),
|
||||
onError,
|
||||
onCompleted);
|
||||
}
|
||||
@@ -270,19 +276,23 @@ public class SiteStreamGrpcClient : IAsyncDisposable, IDisposable
|
||||
|
||||
var request = new SiteStreamRequest
|
||||
{
|
||||
CorrelationId = correlationId
|
||||
CorrelationId = correlationId,
|
||||
// R2 batch negotiation — see SubscribeAsync.
|
||||
BatchingSupported = true
|
||||
};
|
||||
|
||||
void Deliver(SiteStreamEvent single)
|
||||
{
|
||||
// Site-wide stream is alarm-only by contract; defensively ignore anything else.
|
||||
if (ConvertToAlarmEvent(single) is { } alarm)
|
||||
onAlarmEvent(alarm);
|
||||
}
|
||||
|
||||
await ConsumeStreamAsync(
|
||||
correlationId,
|
||||
cts,
|
||||
() => _client.SubscribeSite(request, cancellationToken: cts.Token),
|
||||
evt =>
|
||||
{
|
||||
// Site-wide stream is alarm-only by contract; defensively ignore anything else.
|
||||
if (ConvertToAlarmEvent(evt) is { } alarm)
|
||||
onAlarmEvent(alarm);
|
||||
},
|
||||
frame => ForEachEvent(frame, Deliver),
|
||||
onError,
|
||||
onCompleted,
|
||||
onConnected);
|
||||
@@ -451,6 +461,39 @@ public class SiteStreamGrpcClient : IAsyncDisposable, IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks one wire frame into the per-event pipeline (R2 — gRPC event batching).
|
||||
/// A plain <c>attribute_changed</c>/<c>alarm_changed</c> frame is delivered as-is; a
|
||||
/// <see cref="SiteStreamEventBatch"/> frame is unpacked <b>in order</b> into the same
|
||||
/// callback, so every downstream consumer (<c>SiteAlarmAggregatorActor</c>,
|
||||
/// <c>DebugStreamBridgeActor</c>, the consumer-keepalive/orphan logic, per-event
|
||||
/// <c>Timestamp</c> fidelity) sees no difference between a batched and an unbatched site.
|
||||
/// <para>
|
||||
/// Unpacking is deliberately NON-RECURSIVE: the server never nests a batch inside a
|
||||
/// batch, and a nested or unknown inner case from a malformed peer is skipped rather
|
||||
/// than followed. Internal for testability.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="frame">The wire frame received from the site.</param>
|
||||
/// <param name="handler">Invoked once per contained event, in arrival order.</param>
|
||||
internal static void ForEachEvent(SiteStreamEvent frame, Action<SiteStreamEvent> handler)
|
||||
{
|
||||
if (frame.EventCase != SiteStreamEvent.EventOneofCase.Batch)
|
||||
{
|
||||
handler(frame);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var inner in frame.Batch.Events)
|
||||
{
|
||||
if (inner.EventCase is SiteStreamEvent.EventOneofCase.AttributeChanged
|
||||
or SiteStreamEvent.EventOneofCase.AlarmChanged)
|
||||
{
|
||||
handler(inner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a proto SiteStreamEvent to the corresponding domain message.
|
||||
/// Internal for testability.
|
||||
|
||||
@@ -29,6 +29,8 @@ public class SiteStreamGrpcServer : SiteStreamService.SiteStreamServiceBase
|
||||
private readonly TimeSpan _maxStreamLifetime;
|
||||
private readonly int _instanceChannelCapacity;
|
||||
private readonly int _siteAlarmChannelCapacity;
|
||||
private readonly int _streamBatchMaxEvents;
|
||||
private readonly TimeSpan _streamBatchWindow;
|
||||
private volatile bool _ready;
|
||||
// Flipped by CancelAllStreams() when the host enters
|
||||
// CoordinatedShutdown so SubscribeInstance refuses new streams with
|
||||
@@ -75,7 +77,8 @@ public class SiteStreamGrpcServer : SiteStreamService.SiteStreamServiceBase
|
||||
ILogger<SiteStreamGrpcServer> logger,
|
||||
int maxConcurrentStreams = 100)
|
||||
: this(streamSubscriber, logger, maxConcurrentStreams, TimeSpan.FromHours(4),
|
||||
DefaultInstanceChannelCapacity, DefaultSiteAlarmChannelCapacity)
|
||||
DefaultInstanceChannelCapacity, DefaultSiteAlarmChannelCapacity,
|
||||
DefaultStreamBatchMaxEvents, DefaultStreamBatchWindow)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -85,6 +88,12 @@ public class SiteStreamGrpcServer : SiteStreamService.SiteStreamServiceBase
|
||||
/// <summary>Fallback site-wide alarm send-channel capacity when no options are bound.</summary>
|
||||
internal const int DefaultSiteAlarmChannelCapacity = 20_000;
|
||||
|
||||
/// <summary>Fallback stream-batch size cap when no options are bound (R2).</summary>
|
||||
internal const int DefaultStreamBatchMaxEvents = 100;
|
||||
|
||||
/// <summary>Fallback stream-batch coalescing window when no options are bound (R2).</summary>
|
||||
internal static readonly TimeSpan DefaultStreamBatchWindow = TimeSpan.FromMilliseconds(25);
|
||||
|
||||
/// <summary>
|
||||
/// DI constructor — binds <see cref="CommunicationOptions.GrpcMaxConcurrentStreams"/>
|
||||
/// and <see cref="CommunicationOptions.GrpcMaxStreamLifetime"/> so the documented
|
||||
@@ -102,7 +111,9 @@ public class SiteStreamGrpcServer : SiteStreamService.SiteStreamServiceBase
|
||||
options.Value.GrpcMaxConcurrentStreams,
|
||||
options.Value.GrpcMaxStreamLifetime,
|
||||
options.Value.GrpcInstanceStreamChannelCapacity,
|
||||
options.Value.GrpcSiteAlarmStreamChannelCapacity)
|
||||
options.Value.GrpcSiteAlarmStreamChannelCapacity,
|
||||
options.Value.GrpcStreamBatchMaxEvents,
|
||||
options.Value.GrpcStreamBatchWindow)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -112,7 +123,9 @@ public class SiteStreamGrpcServer : SiteStreamService.SiteStreamServiceBase
|
||||
int maxConcurrentStreams,
|
||||
TimeSpan maxStreamLifetime,
|
||||
int instanceChannelCapacity,
|
||||
int siteAlarmChannelCapacity)
|
||||
int siteAlarmChannelCapacity,
|
||||
int streamBatchMaxEvents,
|
||||
TimeSpan streamBatchWindow)
|
||||
{
|
||||
_streamSubscriber = streamSubscriber;
|
||||
_logger = logger;
|
||||
@@ -120,6 +133,11 @@ public class SiteStreamGrpcServer : SiteStreamService.SiteStreamServiceBase
|
||||
_maxStreamLifetime = maxStreamLifetime;
|
||||
_instanceChannelCapacity = Math.Max(1, instanceChannelCapacity);
|
||||
_siteAlarmChannelCapacity = Math.Max(1, siteAlarmChannelCapacity);
|
||||
// Floored/clamped rather than thrown on: CommunicationOptionsValidator already
|
||||
// fails the boot on a bad value, and a degenerate one must not blow up deep
|
||||
// inside a live RPC on a host composed without validation (tests, embedded use).
|
||||
_streamBatchMaxEvents = Math.Max(1, streamBatchMaxEvents);
|
||||
_streamBatchWindow = streamBatchWindow < TimeSpan.Zero ? TimeSpan.Zero : streamBatchWindow;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -230,6 +248,12 @@ public class SiteStreamGrpcServer : SiteStreamService.SiteStreamServiceBase
|
||||
/// <summary>Effective site-wide alarm send-channel capacity. Exposed for tests.</summary>
|
||||
internal int SiteAlarmChannelCapacity => _siteAlarmChannelCapacity;
|
||||
|
||||
/// <summary>Effective stream-batch size cap (R2). Exposed for tests.</summary>
|
||||
internal int StreamBatchMaxEvents => _streamBatchMaxEvents;
|
||||
|
||||
/// <summary>Effective stream-batch coalescing window (R2). Exposed for tests.</summary>
|
||||
internal TimeSpan StreamBatchWindow => _streamBatchWindow;
|
||||
|
||||
/// <summary>
|
||||
/// Total events evicted from stream send channels on this node since start (both stream
|
||||
/// kinds). Exported as <c>scadabridge.site.stream.events_dropped</c>; exposed here so a
|
||||
@@ -251,7 +275,10 @@ public class SiteStreamGrpcServer : SiteStreamService.SiteStreamServiceBase
|
||||
relay => _streamSubscriber.Subscribe(request.InstanceUniqueName, relay),
|
||||
request.InstanceUniqueName,
|
||||
_instanceChannelCapacity,
|
||||
streamKind: "instance");
|
||||
streamKind: "instance",
|
||||
// R2 batch negotiation: proto3 defaults this to false, so a central built
|
||||
// before batching existed keeps getting one frame per event.
|
||||
batchingSupported: request.BatchingSupported);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task SubscribeSite(
|
||||
@@ -271,7 +298,8 @@ public class SiteStreamGrpcServer : SiteStreamService.SiteStreamServiceBase
|
||||
// DropOldest meant an alarm burst during a WAN stall silently evicted operator-
|
||||
// visible transitions to make room for diagnostics traffic.
|
||||
_siteAlarmChannelCapacity,
|
||||
streamKind: "site-alarms");
|
||||
streamKind: "site-alarms",
|
||||
batchingSupported: request.BatchingSupported);
|
||||
|
||||
/// <summary>
|
||||
/// Shared streaming pipeline behind <see cref="SubscribeInstance"/> and
|
||||
@@ -289,6 +317,12 @@ public class SiteStreamGrpcServer : SiteStreamService.SiteStreamServiceBase
|
||||
/// <param name="description">Human-readable subscription description for logging.</param>
|
||||
/// <param name="channelCapacity">Send-channel capacity for this stream kind.</param>
|
||||
/// <param name="streamKind">Telemetry tag for this stream kind (<c>instance</c>/<c>site-alarms</c>).</param>
|
||||
/// <param name="batchingSupported">
|
||||
/// Whether the SUBSCRIBING CLIENT declared it understands the <c>SiteStreamEventBatch</c>
|
||||
/// oneof case (R2). False — the proto3 default an older central necessarily sends —
|
||||
/// pins this stream to one event per frame, so a peer that predates batching can never
|
||||
/// receive a frame case its generated code drops on the floor.
|
||||
/// </param>
|
||||
private async Task RunSubscriptionStreamAsync(
|
||||
string correlationId,
|
||||
IServerStreamWriter<SiteStreamEvent> responseStream,
|
||||
@@ -296,7 +330,8 @@ public class SiteStreamGrpcServer : SiteStreamService.SiteStreamServiceBase
|
||||
Func<IActorRef, string> subscribe,
|
||||
string description,
|
||||
int channelCapacity,
|
||||
string streamKind)
|
||||
string streamKind,
|
||||
bool batchingSupported)
|
||||
{
|
||||
if (!_ready)
|
||||
throw new RpcException(new GrpcStatus(StatusCode.Unavailable, "Server not ready"));
|
||||
@@ -318,11 +353,29 @@ public class SiteStreamGrpcServer : SiteStreamService.SiteStreamServiceBase
|
||||
StatusCode.InvalidArgument, "correlation_id is missing or not a valid identifier"));
|
||||
}
|
||||
|
||||
// Duplicate prevention -- cancel existing stream for this correlationId
|
||||
// Duplicate prevention -- cancel existing stream for this correlationId.
|
||||
//
|
||||
// CANCEL ONLY, never Dispose. The replaced stream's CTS belongs to its own
|
||||
// handler's `using var streamCts`, which is still running and still reads
|
||||
// `streamCts.Token` (at the pump call below, and previously at the
|
||||
// `ReadAllAsync(streamCts.Token)` it replaced). Disposing it from here raced that
|
||||
// read and surfaced as an unhandled ObjectDisposedException escaping the RPC —
|
||||
// observed as a full-suite-load-only failure of
|
||||
// GrpcStreamIntegrationTests.Pipeline_DuplicateCorrelationId_ReplacesStream, and a
|
||||
// pre-existing hazard (the same Dispose + the same first-token-read relationship
|
||||
// exist unchanged before R2). Cancellation alone is what replacement needs; the
|
||||
// owning handler's `using` still disposes it exactly once on every exit path.
|
||||
if (_activeStreams.TryRemove(correlationId, out var existingEntry))
|
||||
{
|
||||
existingEntry.Cts.Cancel();
|
||||
existingEntry.Cts.Dispose();
|
||||
try
|
||||
{
|
||||
existingEntry.Cts.Cancel();
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
// Its owner finished and disposed it between the TryRemove and here —
|
||||
// already terminal, nothing to cancel. Mirrors CancelAllStreams().
|
||||
}
|
||||
}
|
||||
|
||||
// Check max concurrent streams after duplicate removal.
|
||||
@@ -422,10 +475,24 @@ public class SiteStreamGrpcServer : SiteStreamService.SiteStreamServiceBase
|
||||
ScadaBridgeTelemetry.SiteConnectionOpened();
|
||||
try
|
||||
{
|
||||
await foreach (var evt in channel.Reader.ReadAllAsync(streamCts.Token))
|
||||
{
|
||||
await responseStream.WriteAsync(evt, streamCts.Token);
|
||||
}
|
||||
// R2 — event batching. The pump replaces the old per-event
|
||||
// `await foreach (…) WriteAsync(evt)` loop and is byte-for-byte identical to
|
||||
// it when maxBatchEvents == 1, which is exactly what an un-negotiated
|
||||
// subscription gets. It sits DOWNSTREAM of the bounded DropOldest channel
|
||||
// above, so it changes framing only — never the site's burst ceiling.
|
||||
await SiteStreamEventBatcher.PumpAsync(
|
||||
channel.Reader,
|
||||
correlationId,
|
||||
maxBatchEvents: batchingSupported ? _streamBatchMaxEvents : 1,
|
||||
maxWindow: _streamBatchWindow,
|
||||
(evt, token) => responseStream.WriteAsync(evt, token),
|
||||
// Recorded only on a negotiated stream: on an un-negotiated one every
|
||||
// frame carries exactly one event, so the histogram would degenerate
|
||||
// into a per-event instrument on the product's hottest path.
|
||||
batchingSupported
|
||||
? size => ScadaBridgeTelemetry.RecordSiteStreamBatchSize(streamKind, size)
|
||||
: null,
|
||||
streamCts.Token);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
|
||||
@@ -20,6 +20,14 @@ service SiteStreamService {
|
||||
message InstanceStreamRequest {
|
||||
string correlation_id = 1;
|
||||
string instance_unique_name = 2;
|
||||
// Client-declared BATCH NEGOTIATION (R2, event batching). When true the client
|
||||
// understands the SiteStreamEventBatch oneof case and the server may coalesce
|
||||
// consecutive events into one frame. proto3 defaults this to false, so an OLD
|
||||
// central that never sets it keeps receiving one frame per event — that default
|
||||
// IS the negotiation, and it is what makes new-site↔old-central safe. A NEW
|
||||
// central sets it against an OLD site, which ignores the unknown field and
|
||||
// keeps sending per-event frames the new client also accepts. Additive-only.
|
||||
bool batching_supported = 3;
|
||||
}
|
||||
|
||||
// Request for the site-wide, alarm-only SubscribeSite stream. Unlike
|
||||
@@ -27,6 +35,8 @@ message InstanceStreamRequest {
|
||||
// transitions for every instance on the site.
|
||||
message SiteStreamRequest {
|
||||
string correlation_id = 1;
|
||||
// See InstanceStreamRequest.batching_supported. Additive-only.
|
||||
bool batching_supported = 2;
|
||||
}
|
||||
|
||||
message SiteStreamEvent {
|
||||
@@ -34,9 +44,26 @@ message SiteStreamEvent {
|
||||
oneof event {
|
||||
AttributeValueUpdate attribute_changed = 2;
|
||||
AlarmStateUpdate alarm_changed = 3;
|
||||
// Coalesced frame (R2). Emitted ONLY when the subscription request set
|
||||
// batching_supported = true. A batch is never nested inside a batch, and a
|
||||
// single event is always sent as a plain attribute_changed/alarm_changed
|
||||
// frame — so a quiet stream's wire shape is byte-identical to before.
|
||||
SiteStreamEventBatch batch = 4;
|
||||
}
|
||||
}
|
||||
|
||||
// Coalesced carrier for several consecutive stream events (R2). Ordering is
|
||||
// significant: events appear in the exact order the site produced them, and the
|
||||
// client unpacks them in order into the same per-event pipeline, so per-event
|
||||
// Timestamp fidelity and downstream sequencing are unchanged.
|
||||
//
|
||||
// The inner events deliberately leave correlation_id EMPTY — the enclosing
|
||||
// SiteStreamEvent carries it once for the whole frame, which is the byte saving
|
||||
// batching exists for. No consumer reads the inner correlation_id.
|
||||
message SiteStreamEventBatch {
|
||||
repeated SiteStreamEvent events = 1;
|
||||
}
|
||||
|
||||
enum Quality {
|
||||
QUALITY_UNSPECIFIED = 0;
|
||||
QUALITY_GOOD = 1;
|
||||
|
||||
@@ -26,97 +26,102 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
string.Concat(
|
||||
"ChdQcm90b3Mvc2l0ZXN0cmVhbS5wcm90bxIKc2l0ZXN0cmVhbRofZ29vZ2xl",
|
||||
"L3Byb3RvYnVmL3RpbWVzdGFtcC5wcm90bxoeZ29vZ2xlL3Byb3RvYnVmL3dy",
|
||||
"YXBwZXJzLnByb3RvIk0KFUluc3RhbmNlU3RyZWFtUmVxdWVzdBIWCg5jb3Jy",
|
||||
"YXBwZXJzLnByb3RvImkKFUluc3RhbmNlU3RyZWFtUmVxdWVzdBIWCg5jb3Jy",
|
||||
"ZWxhdGlvbl9pZBgBIAEoCRIcChRpbnN0YW5jZV91bmlxdWVfbmFtZRgCIAEo",
|
||||
"CSIrChFTaXRlU3RyZWFtUmVxdWVzdBIWCg5jb3JyZWxhdGlvbl9pZBgBIAEo",
|
||||
"CSKoAQoPU2l0ZVN0cmVhbUV2ZW50EhYKDmNvcnJlbGF0aW9uX2lkGAEgASgJ",
|
||||
"Ej0KEWF0dHJpYnV0ZV9jaGFuZ2VkGAIgASgLMiAuc2l0ZXN0cmVhbS5BdHRy",
|
||||
"aWJ1dGVWYWx1ZVVwZGF0ZUgAEjUKDWFsYXJtX2NoYW5nZWQYAyABKAsyHC5z",
|
||||
"aXRlc3RyZWFtLkFsYXJtU3RhdGVVcGRhdGVIAEIHCgVldmVudCLIAQoUQXR0",
|
||||
"cmlidXRlVmFsdWVVcGRhdGUSHAoUaW5zdGFuY2VfdW5pcXVlX25hbWUYASAB",
|
||||
"KAkSFgoOYXR0cmlidXRlX3BhdGgYAiABKAkSFgoOYXR0cmlidXRlX25hbWUY",
|
||||
"AyABKAkSDQoFdmFsdWUYBCABKAkSJAoHcXVhbGl0eRgFIAEoDjITLnNpdGVz",
|
||||
"dHJlYW0uUXVhbGl0eRItCgl0aW1lc3RhbXAYBiABKAsyGi5nb29nbGUucHJv",
|
||||
"dG9idWYuVGltZXN0YW1wIq8FChBBbGFybVN0YXRlVXBkYXRlEhwKFGluc3Rh",
|
||||
"bmNlX3VuaXF1ZV9uYW1lGAEgASgJEhIKCmFsYXJtX25hbWUYAiABKAkSKQoF",
|
||||
"c3RhdGUYAyABKA4yGi5zaXRlc3RyZWFtLkFsYXJtU3RhdGVFbnVtEhAKCHBy",
|
||||
"aW9yaXR5GAQgASgFEi0KCXRpbWVzdGFtcBgFIAEoCzIaLmdvb2dsZS5wcm90",
|
||||
"b2J1Zi5UaW1lc3RhbXASKQoFbGV2ZWwYBiABKA4yGi5zaXRlc3RyZWFtLkFs",
|
||||
"YXJtTGV2ZWxFbnVtEg8KB21lc3NhZ2UYByABKAkSDAoEa2luZBgIIAEoCRIO",
|
||||
"CgZhY3RpdmUYCSABKAgSFAoMYWNrbm93bGVkZ2VkGAogASgIEhEKCWNvbmZp",
|
||||
"cm1lZBgLIAEoCBIUCgxzaGVsdmVfc3RhdGUYDCABKAkSEgoKc3VwcHJlc3Nl",
|
||||
"ZBgNIAEoCBIYChBzb3VyY2VfcmVmZXJlbmNlGA4gASgJEhcKD2FsYXJtX3R5",
|
||||
"cGVfbmFtZRgPIAEoCRIQCghjYXRlZ29yeRgQIAEoCRIVCg1vcGVyYXRvcl91",
|
||||
"c2VyGBEgASgJEhgKEG9wZXJhdG9yX2NvbW1lbnQYEiABKAkSNwoTb3JpZ2lu",
|
||||
"YWxfcmFpc2VfdGltZRgTIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3Rh",
|
||||
"bXASFQoNY3VycmVudF92YWx1ZRgUIAEoCRITCgtsaW1pdF92YWx1ZRgVIAEo",
|
||||
"CRIkChxuYXRpdmVfc291cmNlX2Nhbm9uaWNhbF9uYW1lGBYgASgJEiEKGWlz",
|
||||
"X2NvbmZpZ3VyZWRfcGxhY2Vob2xkZXIYFyABKAgSLAoIYWNrX3RpbWUYGCAB",
|
||||
"KAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wIr0ECg1BdWRpdEV2ZW50",
|
||||
"RHRvEhAKCGV2ZW50X2lkGAEgASgJEjMKD29jY3VycmVkX2F0X3V0YxgCIAEo",
|
||||
"CzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASDwoHY2hhbm5lbBgDIAEo",
|
||||
"CRIMCgRraW5kGAQgASgJEhYKDmNvcnJlbGF0aW9uX2lkGAUgASgJEhYKDnNv",
|
||||
"dXJjZV9zaXRlX2lkGAYgASgJEhoKEnNvdXJjZV9pbnN0YW5jZV9pZBgHIAEo",
|
||||
"CRIVCg1zb3VyY2Vfc2NyaXB0GAggASgJEg0KBWFjdG9yGAkgASgJEg4KBnRh",
|
||||
"cmdldBgKIAEoCRIOCgZzdGF0dXMYCyABKAkSMAoLaHR0cF9zdGF0dXMYDCAB",
|
||||
"KAsyGy5nb29nbGUucHJvdG9idWYuSW50MzJWYWx1ZRIwCgtkdXJhdGlvbl9t",
|
||||
"cxgNIAEoCzIbLmdvb2dsZS5wcm90b2J1Zi5JbnQzMlZhbHVlEhUKDWVycm9y",
|
||||
"X21lc3NhZ2UYDiABKAkSFAoMZXJyb3JfZGV0YWlsGA8gASgJEhcKD3JlcXVl",
|
||||
"c3Rfc3VtbWFyeRgQIAEoCRIYChByZXNwb25zZV9zdW1tYXJ5GBEgASgJEhkK",
|
||||
"EXBheWxvYWRfdHJ1bmNhdGVkGBIgASgIEg0KBWV4dHJhGBMgASgJEhQKDGV4",
|
||||
"ZWN1dGlvbl9pZBgUIAEoCRIbChNwYXJlbnRfZXhlY3V0aW9uX2lkGBUgASgJ",
|
||||
"EhMKC3NvdXJjZV9ub2RlGBYgASgJIjwKD0F1ZGl0RXZlbnRCYXRjaBIpCgZl",
|
||||
"dmVudHMYASADKAsyGS5zaXRlc3RyZWFtLkF1ZGl0RXZlbnREdG8iJwoJSW5n",
|
||||
"ZXN0QWNrEhoKEmFjY2VwdGVkX2V2ZW50X2lkcxgBIAMoCSKJAwoWU2l0ZUNh",
|
||||
"bGxPcGVyYXRpb25hbER0bxIcChR0cmFja2VkX29wZXJhdGlvbl9pZBgBIAEo",
|
||||
"CRIPCgdjaGFubmVsGAIgASgJEg4KBnRhcmdldBgDIAEoCRITCgtzb3VyY2Vf",
|
||||
"c2l0ZRgEIAEoCRIOCgZzdGF0dXMYBSABKAkSEwoLcmV0cnlfY291bnQYBiAB",
|
||||
"KAUSEgoKbGFzdF9lcnJvchgHIAEoCRIwCgtodHRwX3N0YXR1cxgIIAEoCzIb",
|
||||
"Lmdvb2dsZS5wcm90b2J1Zi5JbnQzMlZhbHVlEjIKDmNyZWF0ZWRfYXRfdXRj",
|
||||
"GAkgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIyCg51cGRhdGVk",
|
||||
"X2F0X3V0YxgKIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASMwoP",
|
||||
"dGVybWluYWxfYXRfdXRjGAsgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVz",
|
||||
"dGFtcBITCgtzb3VyY2Vfbm9kZRgMIAEoCSKAAQoVQ2FjaGVkVGVsZW1ldHJ5",
|
||||
"UGFja2V0Ei4KC2F1ZGl0X2V2ZW50GAEgASgLMhkuc2l0ZXN0cmVhbS5BdWRp",
|
||||
"dEV2ZW50RHRvEjcKC29wZXJhdGlvbmFsGAIgASgLMiIuc2l0ZXN0cmVhbS5T",
|
||||
"aXRlQ2FsbE9wZXJhdGlvbmFsRHRvIkoKFENhY2hlZFRlbGVtZXRyeUJhdGNo",
|
||||
"EjIKB3BhY2tldHMYASADKAsyIS5zaXRlc3RyZWFtLkNhY2hlZFRlbGVtZXRy",
|
||||
"eVBhY2tldCJtChZQdWxsQXVkaXRFdmVudHNSZXF1ZXN0Ei0KCXNpbmNlX3V0",
|
||||
"YxgBIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASEgoKYmF0Y2hf",
|
||||
"c2l6ZRgCIAEoBRIQCghhZnRlcl9pZBgDIAEoCSJcChdQdWxsQXVkaXRFdmVu",
|
||||
"dHNSZXNwb25zZRIpCgZldmVudHMYASADKAsyGS5zaXRlc3RyZWFtLkF1ZGl0",
|
||||
"RXZlbnREdG8SFgoObW9yZV9hdmFpbGFibGUYAiABKAgiawoUUHVsbFNpdGVD",
|
||||
"YWxsc1JlcXVlc3QSLQoJc2luY2VfdXRjGAEgASgLMhouZ29vZ2xlLnByb3Rv",
|
||||
"YnVmLlRpbWVzdGFtcBISCgpiYXRjaF9zaXplGAIgASgFEhAKCGFmdGVyX2lk",
|
||||
"GAMgASgJImkKFVB1bGxTaXRlQ2FsbHNSZXNwb25zZRI4CgxvcGVyYXRpb25h",
|
||||
"bHMYASADKAsyIi5zaXRlc3RyZWFtLlNpdGVDYWxsT3BlcmF0aW9uYWxEdG8S",
|
||||
"FgoObW9yZV9hdmFpbGFibGUYAiABKAgqXAoHUXVhbGl0eRIXChNRVUFMSVRZ",
|
||||
"X1VOU1BFQ0lGSUVEEAASEAoMUVVBTElUWV9HT09EEAESFQoRUVVBTElUWV9V",
|
||||
"TkNFUlRBSU4QAhIPCgtRVUFMSVRZX0JBRBADKl0KDkFsYXJtU3RhdGVFbnVt",
|
||||
"EhsKF0FMQVJNX1NUQVRFX1VOU1BFQ0lGSUVEEAASFgoSQUxBUk1fU1RBVEVf",
|
||||
"Tk9STUFMEAESFgoSQUxBUk1fU1RBVEVfQUNUSVZFEAIqhQEKDkFsYXJtTGV2",
|
||||
"ZWxFbnVtEhQKEEFMQVJNX0xFVkVMX05PTkUQABITCg9BTEFSTV9MRVZFTF9M",
|
||||
"T1cQARIXChNBTEFSTV9MRVZFTF9MT1dfTE9XEAISFAoQQUxBUk1fTEVWRUxf",
|
||||
"SElHSBADEhkKFUFMQVJNX0xFVkVMX0hJR0hfSElHSBAEMoYEChFTaXRlU3Ry",
|
||||
"ZWFtU2VydmljZRJVChFTdWJzY3JpYmVJbnN0YW5jZRIhLnNpdGVzdHJlYW0u",
|
||||
"SW5zdGFuY2VTdHJlYW1SZXF1ZXN0Ghsuc2l0ZXN0cmVhbS5TaXRlU3RyZWFt",
|
||||
"RXZlbnQwARJNCg1TdWJzY3JpYmVTaXRlEh0uc2l0ZXN0cmVhbS5TaXRlU3Ry",
|
||||
"ZWFtUmVxdWVzdBobLnNpdGVzdHJlYW0uU2l0ZVN0cmVhbUV2ZW50MAESRwoR",
|
||||
"SW5nZXN0QXVkaXRFdmVudHMSGy5zaXRlc3RyZWFtLkF1ZGl0RXZlbnRCYXRj",
|
||||
"aBoVLnNpdGVzdHJlYW0uSW5nZXN0QWNrElAKFUluZ2VzdENhY2hlZFRlbGVt",
|
||||
"ZXRyeRIgLnNpdGVzdHJlYW0uQ2FjaGVkVGVsZW1ldHJ5QmF0Y2gaFS5zaXRl",
|
||||
"c3RyZWFtLkluZ2VzdEFjaxJaCg9QdWxsQXVkaXRFdmVudHMSIi5zaXRlc3Ry",
|
||||
"ZWFtLlB1bGxBdWRpdEV2ZW50c1JlcXVlc3QaIy5zaXRlc3RyZWFtLlB1bGxB",
|
||||
"dWRpdEV2ZW50c1Jlc3BvbnNlElQKDVB1bGxTaXRlQ2FsbHMSIC5zaXRlc3Ry",
|
||||
"ZWFtLlB1bGxTaXRlQ2FsbHNSZXF1ZXN0GiEuc2l0ZXN0cmVhbS5QdWxsU2l0",
|
||||
"ZUNhbGxzUmVzcG9uc2VCK6oCKFpCLk1PTS5XVy5TY2FkYUJyaWRnZS5Db21t",
|
||||
"dW5pY2F0aW9uLkdycGNiBnByb3RvMw=="));
|
||||
"CRIaChJiYXRjaGluZ19zdXBwb3J0ZWQYAyABKAgiRwoRU2l0ZVN0cmVhbVJl",
|
||||
"cXVlc3QSFgoOY29ycmVsYXRpb25faWQYASABKAkSGgoSYmF0Y2hpbmdfc3Vw",
|
||||
"cG9ydGVkGAIgASgIItsBCg9TaXRlU3RyZWFtRXZlbnQSFgoOY29ycmVsYXRp",
|
||||
"b25faWQYASABKAkSPQoRYXR0cmlidXRlX2NoYW5nZWQYAiABKAsyIC5zaXRl",
|
||||
"c3RyZWFtLkF0dHJpYnV0ZVZhbHVlVXBkYXRlSAASNQoNYWxhcm1fY2hhbmdl",
|
||||
"ZBgDIAEoCzIcLnNpdGVzdHJlYW0uQWxhcm1TdGF0ZVVwZGF0ZUgAEjEKBWJh",
|
||||
"dGNoGAQgASgLMiAuc2l0ZXN0cmVhbS5TaXRlU3RyZWFtRXZlbnRCYXRjaEgA",
|
||||
"QgcKBWV2ZW50IkMKFFNpdGVTdHJlYW1FdmVudEJhdGNoEisKBmV2ZW50cxgB",
|
||||
"IAMoCzIbLnNpdGVzdHJlYW0uU2l0ZVN0cmVhbUV2ZW50IsgBChRBdHRyaWJ1",
|
||||
"dGVWYWx1ZVVwZGF0ZRIcChRpbnN0YW5jZV91bmlxdWVfbmFtZRgBIAEoCRIW",
|
||||
"Cg5hdHRyaWJ1dGVfcGF0aBgCIAEoCRIWCg5hdHRyaWJ1dGVfbmFtZRgDIAEo",
|
||||
"CRINCgV2YWx1ZRgEIAEoCRIkCgdxdWFsaXR5GAUgASgOMhMuc2l0ZXN0cmVh",
|
||||
"bS5RdWFsaXR5Ei0KCXRpbWVzdGFtcBgGIAEoCzIaLmdvb2dsZS5wcm90b2J1",
|
||||
"Zi5UaW1lc3RhbXAirwUKEEFsYXJtU3RhdGVVcGRhdGUSHAoUaW5zdGFuY2Vf",
|
||||
"dW5pcXVlX25hbWUYASABKAkSEgoKYWxhcm1fbmFtZRgCIAEoCRIpCgVzdGF0",
|
||||
"ZRgDIAEoDjIaLnNpdGVzdHJlYW0uQWxhcm1TdGF0ZUVudW0SEAoIcHJpb3Jp",
|
||||
"dHkYBCABKAUSLQoJdGltZXN0YW1wGAUgASgLMhouZ29vZ2xlLnByb3RvYnVm",
|
||||
"LlRpbWVzdGFtcBIpCgVsZXZlbBgGIAEoDjIaLnNpdGVzdHJlYW0uQWxhcm1M",
|
||||
"ZXZlbEVudW0SDwoHbWVzc2FnZRgHIAEoCRIMCgRraW5kGAggASgJEg4KBmFj",
|
||||
"dGl2ZRgJIAEoCBIUCgxhY2tub3dsZWRnZWQYCiABKAgSEQoJY29uZmlybWVk",
|
||||
"GAsgASgIEhQKDHNoZWx2ZV9zdGF0ZRgMIAEoCRISCgpzdXBwcmVzc2VkGA0g",
|
||||
"ASgIEhgKEHNvdXJjZV9yZWZlcmVuY2UYDiABKAkSFwoPYWxhcm1fdHlwZV9u",
|
||||
"YW1lGA8gASgJEhAKCGNhdGVnb3J5GBAgASgJEhUKDW9wZXJhdG9yX3VzZXIY",
|
||||
"ESABKAkSGAoQb3BlcmF0b3JfY29tbWVudBgSIAEoCRI3ChNvcmlnaW5hbF9y",
|
||||
"YWlzZV90aW1lGBMgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIV",
|
||||
"Cg1jdXJyZW50X3ZhbHVlGBQgASgJEhMKC2xpbWl0X3ZhbHVlGBUgASgJEiQK",
|
||||
"HG5hdGl2ZV9zb3VyY2VfY2Fub25pY2FsX25hbWUYFiABKAkSIQoZaXNfY29u",
|
||||
"ZmlndXJlZF9wbGFjZWhvbGRlchgXIAEoCBIsCghhY2tfdGltZRgYIAEoCzIa",
|
||||
"Lmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXAivQQKDUF1ZGl0RXZlbnREdG8S",
|
||||
"EAoIZXZlbnRfaWQYASABKAkSMwoPb2NjdXJyZWRfYXRfdXRjGAIgASgLMhou",
|
||||
"Z29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIPCgdjaGFubmVsGAMgASgJEgwK",
|
||||
"BGtpbmQYBCABKAkSFgoOY29ycmVsYXRpb25faWQYBSABKAkSFgoOc291cmNl",
|
||||
"X3NpdGVfaWQYBiABKAkSGgoSc291cmNlX2luc3RhbmNlX2lkGAcgASgJEhUK",
|
||||
"DXNvdXJjZV9zY3JpcHQYCCABKAkSDQoFYWN0b3IYCSABKAkSDgoGdGFyZ2V0",
|
||||
"GAogASgJEg4KBnN0YXR1cxgLIAEoCRIwCgtodHRwX3N0YXR1cxgMIAEoCzIb",
|
||||
"Lmdvb2dsZS5wcm90b2J1Zi5JbnQzMlZhbHVlEjAKC2R1cmF0aW9uX21zGA0g",
|
||||
"ASgLMhsuZ29vZ2xlLnByb3RvYnVmLkludDMyVmFsdWUSFQoNZXJyb3JfbWVz",
|
||||
"c2FnZRgOIAEoCRIUCgxlcnJvcl9kZXRhaWwYDyABKAkSFwoPcmVxdWVzdF9z",
|
||||
"dW1tYXJ5GBAgASgJEhgKEHJlc3BvbnNlX3N1bW1hcnkYESABKAkSGQoRcGF5",
|
||||
"bG9hZF90cnVuY2F0ZWQYEiABKAgSDQoFZXh0cmEYEyABKAkSFAoMZXhlY3V0",
|
||||
"aW9uX2lkGBQgASgJEhsKE3BhcmVudF9leGVjdXRpb25faWQYFSABKAkSEwoL",
|
||||
"c291cmNlX25vZGUYFiABKAkiPAoPQXVkaXRFdmVudEJhdGNoEikKBmV2ZW50",
|
||||
"cxgBIAMoCzIZLnNpdGVzdHJlYW0uQXVkaXRFdmVudER0byInCglJbmdlc3RB",
|
||||
"Y2sSGgoSYWNjZXB0ZWRfZXZlbnRfaWRzGAEgAygJIokDChZTaXRlQ2FsbE9w",
|
||||
"ZXJhdGlvbmFsRHRvEhwKFHRyYWNrZWRfb3BlcmF0aW9uX2lkGAEgASgJEg8K",
|
||||
"B2NoYW5uZWwYAiABKAkSDgoGdGFyZ2V0GAMgASgJEhMKC3NvdXJjZV9zaXRl",
|
||||
"GAQgASgJEg4KBnN0YXR1cxgFIAEoCRITCgtyZXRyeV9jb3VudBgGIAEoBRIS",
|
||||
"CgpsYXN0X2Vycm9yGAcgASgJEjAKC2h0dHBfc3RhdHVzGAggASgLMhsuZ29v",
|
||||
"Z2xlLnByb3RvYnVmLkludDMyVmFsdWUSMgoOY3JlYXRlZF9hdF91dGMYCSAB",
|
||||
"KAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEjIKDnVwZGF0ZWRfYXRf",
|
||||
"dXRjGAogASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIzCg90ZXJt",
|
||||
"aW5hbF9hdF91dGMYCyABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1w",
|
||||
"EhMKC3NvdXJjZV9ub2RlGAwgASgJIoABChVDYWNoZWRUZWxlbWV0cnlQYWNr",
|
||||
"ZXQSLgoLYXVkaXRfZXZlbnQYASABKAsyGS5zaXRlc3RyZWFtLkF1ZGl0RXZl",
|
||||
"bnREdG8SNwoLb3BlcmF0aW9uYWwYAiABKAsyIi5zaXRlc3RyZWFtLlNpdGVD",
|
||||
"YWxsT3BlcmF0aW9uYWxEdG8iSgoUQ2FjaGVkVGVsZW1ldHJ5QmF0Y2gSMgoH",
|
||||
"cGFja2V0cxgBIAMoCzIhLnNpdGVzdHJlYW0uQ2FjaGVkVGVsZW1ldHJ5UGFj",
|
||||
"a2V0Im0KFlB1bGxBdWRpdEV2ZW50c1JlcXVlc3QSLQoJc2luY2VfdXRjGAEg",
|
||||
"ASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBISCgpiYXRjaF9zaXpl",
|
||||
"GAIgASgFEhAKCGFmdGVyX2lkGAMgASgJIlwKF1B1bGxBdWRpdEV2ZW50c1Jl",
|
||||
"c3BvbnNlEikKBmV2ZW50cxgBIAMoCzIZLnNpdGVzdHJlYW0uQXVkaXRFdmVu",
|
||||
"dER0bxIWCg5tb3JlX2F2YWlsYWJsZRgCIAEoCCJrChRQdWxsU2l0ZUNhbGxz",
|
||||
"UmVxdWVzdBItCglzaW5jZV91dGMYASABKAsyGi5nb29nbGUucHJvdG9idWYu",
|
||||
"VGltZXN0YW1wEhIKCmJhdGNoX3NpemUYAiABKAUSEAoIYWZ0ZXJfaWQYAyAB",
|
||||
"KAkiaQoVUHVsbFNpdGVDYWxsc1Jlc3BvbnNlEjgKDG9wZXJhdGlvbmFscxgB",
|
||||
"IAMoCzIiLnNpdGVzdHJlYW0uU2l0ZUNhbGxPcGVyYXRpb25hbER0bxIWCg5t",
|
||||
"b3JlX2F2YWlsYWJsZRgCIAEoCCpcCgdRdWFsaXR5EhcKE1FVQUxJVFlfVU5T",
|
||||
"UEVDSUZJRUQQABIQCgxRVUFMSVRZX0dPT0QQARIVChFRVUFMSVRZX1VOQ0VS",
|
||||
"VEFJThACEg8KC1FVQUxJVFlfQkFEEAMqXQoOQWxhcm1TdGF0ZUVudW0SGwoX",
|
||||
"QUxBUk1fU1RBVEVfVU5TUEVDSUZJRUQQABIWChJBTEFSTV9TVEFURV9OT1JN",
|
||||
"QUwQARIWChJBTEFSTV9TVEFURV9BQ1RJVkUQAiqFAQoOQWxhcm1MZXZlbEVu",
|
||||
"dW0SFAoQQUxBUk1fTEVWRUxfTk9ORRAAEhMKD0FMQVJNX0xFVkVMX0xPVxAB",
|
||||
"EhcKE0FMQVJNX0xFVkVMX0xPV19MT1cQAhIUChBBTEFSTV9MRVZFTF9ISUdI",
|
||||
"EAMSGQoVQUxBUk1fTEVWRUxfSElHSF9ISUdIEAQyhgQKEVNpdGVTdHJlYW1T",
|
||||
"ZXJ2aWNlElUKEVN1YnNjcmliZUluc3RhbmNlEiEuc2l0ZXN0cmVhbS5JbnN0",
|
||||
"YW5jZVN0cmVhbVJlcXVlc3QaGy5zaXRlc3RyZWFtLlNpdGVTdHJlYW1FdmVu",
|
||||
"dDABEk0KDVN1YnNjcmliZVNpdGUSHS5zaXRlc3RyZWFtLlNpdGVTdHJlYW1S",
|
||||
"ZXF1ZXN0Ghsuc2l0ZXN0cmVhbS5TaXRlU3RyZWFtRXZlbnQwARJHChFJbmdl",
|
||||
"c3RBdWRpdEV2ZW50cxIbLnNpdGVzdHJlYW0uQXVkaXRFdmVudEJhdGNoGhUu",
|
||||
"c2l0ZXN0cmVhbS5Jbmdlc3RBY2sSUAoVSW5nZXN0Q2FjaGVkVGVsZW1ldHJ5",
|
||||
"EiAuc2l0ZXN0cmVhbS5DYWNoZWRUZWxlbWV0cnlCYXRjaBoVLnNpdGVzdHJl",
|
||||
"YW0uSW5nZXN0QWNrEloKD1B1bGxBdWRpdEV2ZW50cxIiLnNpdGVzdHJlYW0u",
|
||||
"UHVsbEF1ZGl0RXZlbnRzUmVxdWVzdBojLnNpdGVzdHJlYW0uUHVsbEF1ZGl0",
|
||||
"RXZlbnRzUmVzcG9uc2USVAoNUHVsbFNpdGVDYWxscxIgLnNpdGVzdHJlYW0u",
|
||||
"UHVsbFNpdGVDYWxsc1JlcXVlc3QaIS5zaXRlc3RyZWFtLlB1bGxTaXRlQ2Fs",
|
||||
"bHNSZXNwb25zZUIrqgIoWkIuTU9NLldXLlNjYWRhQnJpZGdlLkNvbW11bmlj",
|
||||
"YXRpb24uR3JwY2IGcHJvdG8z"));
|
||||
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::ZB.MOM.WW.ScadaBridge.Communication.Grpc.Quality), typeof(global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.AlarmStateEnum), typeof(global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.AlarmLevelEnum), }, null, new pbr::GeneratedClrTypeInfo[] {
|
||||
new pbr::GeneratedClrTypeInfo(typeof(global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.InstanceStreamRequest), global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.InstanceStreamRequest.Parser, new[]{ "CorrelationId", "InstanceUniqueName" }, null, null, null, null),
|
||||
new pbr::GeneratedClrTypeInfo(typeof(global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SiteStreamRequest), global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SiteStreamRequest.Parser, new[]{ "CorrelationId" }, null, null, null, null),
|
||||
new pbr::GeneratedClrTypeInfo(typeof(global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SiteStreamEvent), global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SiteStreamEvent.Parser, new[]{ "CorrelationId", "AttributeChanged", "AlarmChanged" }, new[]{ "Event" }, null, null, null),
|
||||
new pbr::GeneratedClrTypeInfo(typeof(global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.InstanceStreamRequest), global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.InstanceStreamRequest.Parser, new[]{ "CorrelationId", "InstanceUniqueName", "BatchingSupported" }, null, null, null, null),
|
||||
new pbr::GeneratedClrTypeInfo(typeof(global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SiteStreamRequest), global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SiteStreamRequest.Parser, new[]{ "CorrelationId", "BatchingSupported" }, null, null, null, null),
|
||||
new pbr::GeneratedClrTypeInfo(typeof(global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SiteStreamEvent), global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SiteStreamEvent.Parser, new[]{ "CorrelationId", "AttributeChanged", "AlarmChanged", "Batch" }, new[]{ "Event" }, null, null, null),
|
||||
new pbr::GeneratedClrTypeInfo(typeof(global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SiteStreamEventBatch), global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SiteStreamEventBatch.Parser, new[]{ "Events" }, null, null, null, null),
|
||||
new pbr::GeneratedClrTypeInfo(typeof(global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.AttributeValueUpdate), global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.AttributeValueUpdate.Parser, new[]{ "InstanceUniqueName", "AttributePath", "AttributeName", "Value", "Quality", "Timestamp" }, null, null, null, null),
|
||||
new pbr::GeneratedClrTypeInfo(typeof(global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.AlarmStateUpdate), global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.AlarmStateUpdate.Parser, new[]{ "InstanceUniqueName", "AlarmName", "State", "Priority", "Timestamp", "Level", "Message", "Kind", "Active", "Acknowledged", "Confirmed", "ShelveState", "Suppressed", "SourceReference", "AlarmTypeName", "Category", "OperatorUser", "OperatorComment", "OriginalRaiseTime", "CurrentValue", "LimitValue", "NativeSourceCanonicalName", "IsConfiguredPlaceholder", "AckTime" }, null, null, null, null),
|
||||
new pbr::GeneratedClrTypeInfo(typeof(global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.AuditEventDto), global::ZB.MOM.WW.ScadaBridge.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),
|
||||
@@ -201,6 +206,7 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
public InstanceStreamRequest(InstanceStreamRequest other) : this() {
|
||||
correlationId_ = other.correlationId_;
|
||||
instanceUniqueName_ = other.instanceUniqueName_;
|
||||
batchingSupported_ = other.batchingSupported_;
|
||||
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
|
||||
}
|
||||
|
||||
@@ -234,6 +240,27 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "batching_supported" field.</summary>
|
||||
public const int BatchingSupportedFieldNumber = 3;
|
||||
private bool batchingSupported_;
|
||||
/// <summary>
|
||||
/// Client-declared BATCH NEGOTIATION (R2, event batching). When true the client
|
||||
/// understands the SiteStreamEventBatch oneof case and the server may coalesce
|
||||
/// consecutive events into one frame. proto3 defaults this to false, so an OLD
|
||||
/// central that never sets it keeps receiving one frame per event — that default
|
||||
/// IS the negotiation, and it is what makes new-site↔old-central safe. A NEW
|
||||
/// central sets it against an OLD site, which ignores the unknown field and
|
||||
/// keeps sending per-event frames the new client also accepts. Additive-only.
|
||||
/// </summary>
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public bool BatchingSupported {
|
||||
get { return batchingSupported_; }
|
||||
set {
|
||||
batchingSupported_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public override bool Equals(object other) {
|
||||
@@ -251,6 +278,7 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
}
|
||||
if (CorrelationId != other.CorrelationId) return false;
|
||||
if (InstanceUniqueName != other.InstanceUniqueName) return false;
|
||||
if (BatchingSupported != other.BatchingSupported) return false;
|
||||
return Equals(_unknownFields, other._unknownFields);
|
||||
}
|
||||
|
||||
@@ -260,6 +288,7 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
int hash = 1;
|
||||
if (CorrelationId.Length != 0) hash ^= CorrelationId.GetHashCode();
|
||||
if (InstanceUniqueName.Length != 0) hash ^= InstanceUniqueName.GetHashCode();
|
||||
if (BatchingSupported != false) hash ^= BatchingSupported.GetHashCode();
|
||||
if (_unknownFields != null) {
|
||||
hash ^= _unknownFields.GetHashCode();
|
||||
}
|
||||
@@ -286,6 +315,10 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
output.WriteRawTag(18);
|
||||
output.WriteString(InstanceUniqueName);
|
||||
}
|
||||
if (BatchingSupported != false) {
|
||||
output.WriteRawTag(24);
|
||||
output.WriteBool(BatchingSupported);
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
_unknownFields.WriteTo(output);
|
||||
}
|
||||
@@ -304,6 +337,10 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
output.WriteRawTag(18);
|
||||
output.WriteString(InstanceUniqueName);
|
||||
}
|
||||
if (BatchingSupported != false) {
|
||||
output.WriteRawTag(24);
|
||||
output.WriteBool(BatchingSupported);
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
_unknownFields.WriteTo(ref output);
|
||||
}
|
||||
@@ -320,6 +357,9 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
if (InstanceUniqueName.Length != 0) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeStringSize(InstanceUniqueName);
|
||||
}
|
||||
if (BatchingSupported != false) {
|
||||
size += 1 + 1;
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
size += _unknownFields.CalculateSize();
|
||||
}
|
||||
@@ -338,6 +378,9 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
if (other.InstanceUniqueName.Length != 0) {
|
||||
InstanceUniqueName = other.InstanceUniqueName;
|
||||
}
|
||||
if (other.BatchingSupported != false) {
|
||||
BatchingSupported = other.BatchingSupported;
|
||||
}
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
|
||||
}
|
||||
|
||||
@@ -365,6 +408,10 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
InstanceUniqueName = input.ReadString();
|
||||
break;
|
||||
}
|
||||
case 24: {
|
||||
BatchingSupported = input.ReadBool();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -392,6 +439,10 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
InstanceUniqueName = input.ReadString();
|
||||
break;
|
||||
}
|
||||
case 24: {
|
||||
BatchingSupported = input.ReadBool();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -440,6 +491,7 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public SiteStreamRequest(SiteStreamRequest other) : this() {
|
||||
correlationId_ = other.correlationId_;
|
||||
batchingSupported_ = other.batchingSupported_;
|
||||
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
|
||||
}
|
||||
|
||||
@@ -461,6 +513,21 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "batching_supported" field.</summary>
|
||||
public const int BatchingSupportedFieldNumber = 2;
|
||||
private bool batchingSupported_;
|
||||
/// <summary>
|
||||
/// See InstanceStreamRequest.batching_supported. Additive-only.
|
||||
/// </summary>
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public bool BatchingSupported {
|
||||
get { return batchingSupported_; }
|
||||
set {
|
||||
batchingSupported_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public override bool Equals(object other) {
|
||||
@@ -477,6 +544,7 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
return true;
|
||||
}
|
||||
if (CorrelationId != other.CorrelationId) return false;
|
||||
if (BatchingSupported != other.BatchingSupported) return false;
|
||||
return Equals(_unknownFields, other._unknownFields);
|
||||
}
|
||||
|
||||
@@ -485,6 +553,7 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
public override int GetHashCode() {
|
||||
int hash = 1;
|
||||
if (CorrelationId.Length != 0) hash ^= CorrelationId.GetHashCode();
|
||||
if (BatchingSupported != false) hash ^= BatchingSupported.GetHashCode();
|
||||
if (_unknownFields != null) {
|
||||
hash ^= _unknownFields.GetHashCode();
|
||||
}
|
||||
@@ -507,6 +576,10 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
output.WriteRawTag(10);
|
||||
output.WriteString(CorrelationId);
|
||||
}
|
||||
if (BatchingSupported != false) {
|
||||
output.WriteRawTag(16);
|
||||
output.WriteBool(BatchingSupported);
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
_unknownFields.WriteTo(output);
|
||||
}
|
||||
@@ -521,6 +594,10 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
output.WriteRawTag(10);
|
||||
output.WriteString(CorrelationId);
|
||||
}
|
||||
if (BatchingSupported != false) {
|
||||
output.WriteRawTag(16);
|
||||
output.WriteBool(BatchingSupported);
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
_unknownFields.WriteTo(ref output);
|
||||
}
|
||||
@@ -534,6 +611,9 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
if (CorrelationId.Length != 0) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeStringSize(CorrelationId);
|
||||
}
|
||||
if (BatchingSupported != false) {
|
||||
size += 1 + 1;
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
size += _unknownFields.CalculateSize();
|
||||
}
|
||||
@@ -549,6 +629,9 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
if (other.CorrelationId.Length != 0) {
|
||||
CorrelationId = other.CorrelationId;
|
||||
}
|
||||
if (other.BatchingSupported != false) {
|
||||
BatchingSupported = other.BatchingSupported;
|
||||
}
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
|
||||
}
|
||||
|
||||
@@ -572,6 +655,10 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
CorrelationId = input.ReadString();
|
||||
break;
|
||||
}
|
||||
case 16: {
|
||||
BatchingSupported = input.ReadBool();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -595,6 +682,10 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
CorrelationId = input.ReadString();
|
||||
break;
|
||||
}
|
||||
case 16: {
|
||||
BatchingSupported = input.ReadBool();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -645,6 +736,9 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
case EventOneofCase.AlarmChanged:
|
||||
AlarmChanged = other.AlarmChanged.Clone();
|
||||
break;
|
||||
case EventOneofCase.Batch:
|
||||
Batch = other.Batch.Clone();
|
||||
break;
|
||||
}
|
||||
|
||||
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
|
||||
@@ -692,12 +786,31 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "batch" field.</summary>
|
||||
public const int BatchFieldNumber = 4;
|
||||
/// <summary>
|
||||
/// Coalesced frame (R2). Emitted ONLY when the subscription request set
|
||||
/// batching_supported = true. A batch is never nested inside a batch, and a
|
||||
/// single event is always sent as a plain attribute_changed/alarm_changed
|
||||
/// frame — so a quiet stream's wire shape is byte-identical to before.
|
||||
/// </summary>
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SiteStreamEventBatch Batch {
|
||||
get { return eventCase_ == EventOneofCase.Batch ? (global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SiteStreamEventBatch) event_ : null; }
|
||||
set {
|
||||
event_ = value;
|
||||
eventCase_ = value == null ? EventOneofCase.None : EventOneofCase.Batch;
|
||||
}
|
||||
}
|
||||
|
||||
private object event_;
|
||||
/// <summary>Enum of possible cases for the "event" oneof.</summary>
|
||||
public enum EventOneofCase {
|
||||
None = 0,
|
||||
AttributeChanged = 2,
|
||||
AlarmChanged = 3,
|
||||
Batch = 4,
|
||||
}
|
||||
private EventOneofCase eventCase_ = EventOneofCase.None;
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
@@ -731,6 +844,7 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
if (CorrelationId != other.CorrelationId) return false;
|
||||
if (!object.Equals(AttributeChanged, other.AttributeChanged)) return false;
|
||||
if (!object.Equals(AlarmChanged, other.AlarmChanged)) return false;
|
||||
if (!object.Equals(Batch, other.Batch)) return false;
|
||||
if (EventCase != other.EventCase) return false;
|
||||
return Equals(_unknownFields, other._unknownFields);
|
||||
}
|
||||
@@ -742,6 +856,7 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
if (CorrelationId.Length != 0) hash ^= CorrelationId.GetHashCode();
|
||||
if (eventCase_ == EventOneofCase.AttributeChanged) hash ^= AttributeChanged.GetHashCode();
|
||||
if (eventCase_ == EventOneofCase.AlarmChanged) hash ^= AlarmChanged.GetHashCode();
|
||||
if (eventCase_ == EventOneofCase.Batch) hash ^= Batch.GetHashCode();
|
||||
hash ^= (int) eventCase_;
|
||||
if (_unknownFields != null) {
|
||||
hash ^= _unknownFields.GetHashCode();
|
||||
@@ -773,6 +888,10 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
output.WriteRawTag(26);
|
||||
output.WriteMessage(AlarmChanged);
|
||||
}
|
||||
if (eventCase_ == EventOneofCase.Batch) {
|
||||
output.WriteRawTag(34);
|
||||
output.WriteMessage(Batch);
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
_unknownFields.WriteTo(output);
|
||||
}
|
||||
@@ -795,6 +914,10 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
output.WriteRawTag(26);
|
||||
output.WriteMessage(AlarmChanged);
|
||||
}
|
||||
if (eventCase_ == EventOneofCase.Batch) {
|
||||
output.WriteRawTag(34);
|
||||
output.WriteMessage(Batch);
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
_unknownFields.WriteTo(ref output);
|
||||
}
|
||||
@@ -814,6 +937,9 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
if (eventCase_ == EventOneofCase.AlarmChanged) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeMessageSize(AlarmChanged);
|
||||
}
|
||||
if (eventCase_ == EventOneofCase.Batch) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeMessageSize(Batch);
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
size += _unknownFields.CalculateSize();
|
||||
}
|
||||
@@ -842,6 +968,12 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
}
|
||||
AlarmChanged.MergeFrom(other.AlarmChanged);
|
||||
break;
|
||||
case EventOneofCase.Batch:
|
||||
if (Batch == null) {
|
||||
Batch = new global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SiteStreamEventBatch();
|
||||
}
|
||||
Batch.MergeFrom(other.Batch);
|
||||
break;
|
||||
}
|
||||
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
|
||||
@@ -885,6 +1017,15 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
AlarmChanged = subBuilder;
|
||||
break;
|
||||
}
|
||||
case 34: {
|
||||
global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SiteStreamEventBatch subBuilder = new global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SiteStreamEventBatch();
|
||||
if (eventCase_ == EventOneofCase.Batch) {
|
||||
subBuilder.MergeFrom(Batch);
|
||||
}
|
||||
input.ReadMessage(subBuilder);
|
||||
Batch = subBuilder;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -926,6 +1067,212 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
AlarmChanged = subBuilder;
|
||||
break;
|
||||
}
|
||||
case 34: {
|
||||
global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SiteStreamEventBatch subBuilder = new global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SiteStreamEventBatch();
|
||||
if (eventCase_ == EventOneofCase.Batch) {
|
||||
subBuilder.MergeFrom(Batch);
|
||||
}
|
||||
input.ReadMessage(subBuilder);
|
||||
Batch = subBuilder;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Coalesced carrier for several consecutive stream events (R2). Ordering is
|
||||
/// significant: events appear in the exact order the site produced them, and the
|
||||
/// client unpacks them in order into the same per-event pipeline, so per-event
|
||||
/// Timestamp fidelity and downstream sequencing are unchanged.
|
||||
///
|
||||
/// The inner events deliberately leave correlation_id EMPTY — the enclosing
|
||||
/// SiteStreamEvent carries it once for the whole frame, which is the byte saving
|
||||
/// batching exists for. No consumer reads the inner correlation_id.
|
||||
/// </summary>
|
||||
[global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")]
|
||||
public sealed partial class SiteStreamEventBatch : pb::IMessage<SiteStreamEventBatch>
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
, pb::IBufferMessage
|
||||
#endif
|
||||
{
|
||||
private static readonly pb::MessageParser<SiteStreamEventBatch> _parser = new pb::MessageParser<SiteStreamEventBatch>(() => new SiteStreamEventBatch());
|
||||
private pb::UnknownFieldSet _unknownFields;
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pb::MessageParser<SiteStreamEventBatch> Parser { get { return _parser; } }
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::ZB.MOM.WW.ScadaBridge.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 SiteStreamEventBatch() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
partial void OnConstruction();
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public SiteStreamEventBatch(SiteStreamEventBatch other) : this() {
|
||||
events_ = other.events_.Clone();
|
||||
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public SiteStreamEventBatch Clone() {
|
||||
return new SiteStreamEventBatch(this);
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "events" field.</summary>
|
||||
public const int EventsFieldNumber = 1;
|
||||
private static readonly pb::FieldCodec<global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SiteStreamEvent> _repeated_events_codec
|
||||
= pb::FieldCodec.ForMessage(10, global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SiteStreamEvent.Parser);
|
||||
private readonly pbc::RepeatedField<global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SiteStreamEvent> events_ = new pbc::RepeatedField<global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SiteStreamEvent>();
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public pbc::RepeatedField<global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SiteStreamEvent> 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 SiteStreamEventBatch);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public bool Equals(SiteStreamEventBatch 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(SiteStreamEventBatch 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -948,7 +1295,7 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[3]; }
|
||||
get { return global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[4]; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
@@ -1340,7 +1687,7 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[4]; }
|
||||
get { return global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[5]; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
@@ -2461,7 +2808,7 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[5]; }
|
||||
get { return global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[6]; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
@@ -3476,7 +3823,7 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[6]; }
|
||||
get { return global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[7]; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
@@ -3663,7 +4010,7 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[7]; }
|
||||
get { return global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[8]; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
@@ -3856,7 +4203,7 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[8]; }
|
||||
get { return global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[9]; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
@@ -4514,7 +4861,7 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[9]; }
|
||||
get { return global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[10]; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
@@ -4767,7 +5114,7 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[10]; }
|
||||
get { return global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[11]; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
@@ -4965,7 +5312,7 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[11]; }
|
||||
get { return global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[12]; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
@@ -5257,7 +5604,7 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[12]; }
|
||||
get { return global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[13]; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
@@ -5490,7 +5837,7 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[13]; }
|
||||
get { return global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[14]; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
@@ -5780,7 +6127,7 @@ namespace ZB.MOM.WW.ScadaBridge.Communication.Grpc {
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[14]; }
|
||||
get { return global::ZB.MOM.WW.ScadaBridge.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[15]; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
|
||||
Reference in New Issue
Block a user