| | 1 | | // Copyright (c) ZeroC, Inc. |
| | 2 | |
|
| | 3 | | using IceRpc.Internal; |
| | 4 | | using System.IO.Pipelines; |
| | 5 | |
|
| | 6 | | namespace IceRpc; |
| | 7 | |
|
| | 8 | | /// <summary>Represents the base class for outgoing frames.</summary> |
| | 9 | | public abstract class OutgoingFrame |
| | 10 | | { |
| | 11 | | /// <summary>Gets or sets the payload of this frame.</summary> |
| | 12 | | /// <value>The payload of this frame. Defaults to a <see cref="PipeReader" /> that returns an empty |
| | 13 | | /// sequence.</value> |
| | 14 | | /// <remarks>IceRPC completes the payload <see cref="PipeReader" /> with the <see |
| | 15 | | /// cref="PipeReader.Complete(Exception?)" /> method. It never calls <see |
| | 16 | | /// cref="PipeReader.CompleteAsync(Exception?)" />. The implementation of <see |
| | 17 | | /// cref="PipeReader.Complete(Exception?)" /> should not block.</remarks> |
| 46521 | 18 | | public PipeReader Payload { get; set; } = EmptyPipeReader.Instance; |
| | 19 | |
|
| | 20 | | /// <summary>Gets or sets the payload continuation of this frame. The payload continuation is a continuation of <see |
| | 21 | | /// cref="Payload"/>. The receiver cannot distinguish any seam between payload and payload continuation in the <see |
| | 22 | | /// cref="IncomingFrame.Payload" /> it receives.</summary> |
| | 23 | | /// <value>The payload continuation of this frame. Defaults to <see langword="null" /> meaning no |
| | 24 | | /// continuation.</value> |
| | 25 | | /// <remarks>IceRPC completes the payload continuation <see cref="PipeReader" /> with the <see |
| | 26 | | /// cref="PipeReader.Complete(Exception?)" /> method. It never calls <see |
| | 27 | | /// cref="PipeReader.CompleteAsync(Exception?)" />. The implementation of <see |
| | 28 | | /// cref="PipeReader.Complete(Exception?)" /> should not block.</remarks> |
| | 29 | | public PipeReader? PayloadContinuation |
| | 30 | | { |
| 18611 | 31 | | get => _payloadContinuation; |
| | 32 | | set |
| 311 | 33 | | { |
| 311 | 34 | | _payloadContinuation = Protocol.HasPayloadContinuation || value is null ? |
| 311 | 35 | | value : throw new NotSupportedException( |
| 311 | 36 | | $"The '{Protocol}' protocol does not support payload continuation."); |
| 311 | 37 | | } |
| | 38 | | } |
| | 39 | |
|
| | 40 | | /// <summary>Gets the protocol of this frame.</summary> |
| | 41 | | /// <value>The <see cref="IceRpc.Protocol" /> value of this frame.</value> |
| 11573 | 42 | | public Protocol Protocol { get; } |
| | 43 | |
|
| | 44 | | private PipeReader? _payloadContinuation; |
| | 45 | |
|
| | 46 | | private Stack<Func<PipeWriter, PipeWriter>>? _payloadWriterInterceptorStack; |
| | 47 | |
|
| | 48 | | /// <summary>Installs a payload writer interceptor in this outgoing frame. This interceptor is executed just |
| | 49 | | /// before sending <see cref="Payload" />, and is typically used to compress both <see cref="Payload" /> and |
| | 50 | | /// <see cref="PayloadContinuation" />.</summary> |
| | 51 | | /// <param name="payloadWriterInterceptor">The payload writer interceptor to install.</param> |
| | 52 | | /// <returns>This outgoing frame.</returns> |
| | 53 | | /// <remarks>IceRPC completes the payload writer <see cref="PipeWriter" /> with the <see |
| | 54 | | /// cref="PipeWriter.Complete(Exception?)" /> method. It never calls <see |
| | 55 | | /// cref="PipeWriter.CompleteAsync(Exception?)" />. The implementation of <see |
| | 56 | | /// cref="PipeWriter.Complete(Exception?)" /> should not block.</remarks> |
| | 57 | | public OutgoingFrame Use(Func<PipeWriter, PipeWriter> payloadWriterInterceptor) |
| 18 | 58 | | { |
| 18 | 59 | | if (!Protocol.SupportsPayloadWriterInterceptors) |
| 0 | 60 | | { |
| 0 | 61 | | throw new NotSupportedException( |
| 0 | 62 | | $"The '{Protocol}' protocol does not support payload writer interceptors."); |
| | 63 | | } |
| 18 | 64 | | _payloadWriterInterceptorStack ??= new(); |
| 18 | 65 | | _payloadWriterInterceptorStack.Push(payloadWriterInterceptor); |
| 18 | 66 | | return this; |
| 18 | 67 | | } |
| | 68 | |
|
| | 69 | | /// <summary>Returns the payload writer to use when sending the payload.</summary> |
| | 70 | | internal PipeWriter GetPayloadWriter(PipeWriter writer) |
| 3532 | 71 | | { |
| 3532 | 72 | | if (_payloadWriterInterceptorStack is not null) |
| 18 | 73 | | { |
| 90 | 74 | | foreach (Func<PipeWriter, PipeWriter> interceptor in _payloadWriterInterceptorStack) |
| 18 | 75 | | { |
| 18 | 76 | | writer = interceptor(writer); |
| 18 | 77 | | } |
| 18 | 78 | | } |
| 3532 | 79 | | return writer; |
| 3532 | 80 | | } |
| | 81 | |
|
| | 82 | | /// <summary>Constructs an outgoing frame.</summary> |
| | 83 | | /// <param name="protocol">The protocol used to send the frame.</param> |
| 22642 | 84 | | private protected OutgoingFrame(Protocol protocol) => Protocol = protocol; |
| | 85 | | } |