|
42 | 42 | using System.Buffers;
|
43 | 43 | using System.IO;
|
44 | 44 | using System.Net.Sockets;
|
| 45 | +using System.Runtime.CompilerServices; |
45 | 46 | using System.Runtime.ExceptionServices;
|
46 | 47 | using System.Runtime.InteropServices;
|
47 | 48 | using RabbitMQ.Client.Exceptions;
|
48 | 49 | using RabbitMQ.Util;
|
49 | 50 |
|
50 | 51 | namespace RabbitMQ.Client.Impl
|
51 | 52 | {
|
52 |
| - class HeaderOutboundFrame : OutboundFrame |
| 53 | + internal static class Framing |
53 | 54 | {
|
54 |
| - private readonly ContentHeaderBase _header; |
55 |
| - private readonly int _bodyLength; |
56 |
| - |
57 |
| - internal HeaderOutboundFrame(int channel, ContentHeaderBase header, int bodyLength) : base(FrameType.FrameHeader, channel) |
58 |
| - { |
59 |
| - _header = header; |
60 |
| - _bodyLength = bodyLength; |
61 |
| - } |
62 |
| - |
63 |
| - internal override int GetMinimumPayloadBufferSize() |
64 |
| - { |
65 |
| - // ProtocolClassId (2) + header (X bytes) |
66 |
| - return 2 + _header.GetRequiredBufferSize(); |
67 |
| - } |
68 |
| - |
69 |
| - internal override int WritePayload(Span<byte> span) |
70 |
| - { |
71 |
| - // write protocol class id (2 bytes) |
72 |
| - NetworkOrderSerializer.WriteUInt16(span, _header.ProtocolClassId); |
73 |
| - // write header (X bytes) |
74 |
| - int bytesWritten = _header.WriteTo(span.Slice(2), (ulong)_bodyLength); |
75 |
| - return bytesWritten + 2; |
76 |
| - } |
77 |
| - } |
78 |
| - |
79 |
| - class BodySegmentOutboundFrame : OutboundFrame |
80 |
| - { |
81 |
| - private readonly ReadOnlyMemory<byte> _body; |
82 |
| - |
83 |
| - internal BodySegmentOutboundFrame(int channel, ReadOnlyMemory<byte> bodySegment) : base(FrameType.FrameBody, channel) |
84 |
| - { |
85 |
| - _body = bodySegment; |
86 |
| - } |
87 |
| - |
88 |
| - internal override int GetMinimumPayloadBufferSize() |
89 |
| - { |
90 |
| - return _body.Length; |
91 |
| - } |
92 |
| - |
93 |
| - internal override int WritePayload(Span<byte> span) |
94 |
| - { |
95 |
| - _body.Span.CopyTo(span); |
96 |
| - return _body.Length; |
97 |
| - } |
98 |
| - } |
99 |
| - |
100 |
| - class MethodOutboundFrame : OutboundFrame |
101 |
| - { |
102 |
| - private readonly MethodBase _method; |
103 |
| - |
104 |
| - internal MethodOutboundFrame(int channel, MethodBase method) : base(FrameType.FrameMethod, channel) |
105 |
| - { |
106 |
| - _method = method; |
107 |
| - } |
108 |
| - |
109 |
| - internal override int GetMinimumPayloadBufferSize() |
| 55 | + /* +------------+---------+----------------+---------+------------------+ |
| 56 | + * | Frame Type | Channel | Payload length | Payload | Frame End Marker | |
| 57 | + * +------------+---------+----------------+---------+------------------+ |
| 58 | + * | 1 byte | 2 bytes | 4 bytes | x bytes | 1 byte | |
| 59 | + * +------------+---------+----------------+---------+------------------+ */ |
| 60 | + private const int BaseFrameSize = 1 + 2 + 4 + 1; |
| 61 | + private const int StartPayload = 7; |
| 62 | + |
| 63 | + [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| 64 | + private static int WriteBaseFrame(Span<byte> span, FrameType type, ushort channel, int payloadLength) |
110 | 65 | {
|
111 |
| - // class id (2 bytes) + method id (2 bytes) + arguments (X bytes) |
112 |
| - return 4 + _method.GetRequiredBufferSize(); |
| 66 | + const int StartFrameType = 0; |
| 67 | + const int StartChannel = 1; |
| 68 | + const int StartPayloadSize = 3; |
| 69 | + |
| 70 | + span[StartFrameType] = (byte)type; |
| 71 | + NetworkOrderSerializer.WriteUInt16(span.Slice(StartChannel), channel); |
| 72 | + NetworkOrderSerializer.WriteUInt32(span.Slice(StartPayloadSize), (uint)payloadLength); |
| 73 | + span[StartPayload + payloadLength] = Constants.FrameEnd; |
| 74 | + return StartPayload + 1 + payloadLength; |
113 | 75 | }
|
114 | 76 |
|
115 |
| - internal override int WritePayload(Span<byte> span) |
116 |
| - { |
117 |
| - NetworkOrderSerializer.WriteUInt16(span, _method.ProtocolClassId); |
118 |
| - NetworkOrderSerializer.WriteUInt16(span.Slice(2), _method.ProtocolMethodId); |
119 |
| - var argWriter = new MethodArgumentWriter(span.Slice(4)); |
120 |
| - _method.WriteArgumentsTo(ref argWriter); |
121 |
| - return 4 + argWriter.Offset; |
122 |
| - } |
123 |
| - } |
124 |
| - |
125 |
| - class EmptyOutboundFrame : OutboundFrame |
126 |
| - { |
127 |
| - public EmptyOutboundFrame() : base(FrameType.FrameHeartbeat, 0) |
| 77 | + internal static class Method |
128 | 78 | {
|
| 79 | + /* +----------+-----------+-----------+ |
| 80 | + * | Class Id | Method Id | Arguments | |
| 81 | + * +----------+-----------+-----------+ |
| 82 | + * | 2 bytes | 2 bytes | x bytes | |
| 83 | + * +----------+-----------+-----------+ */ |
| 84 | + public const int FrameSize = BaseFrameSize + 2 + 2; |
| 85 | + |
| 86 | + public static int WriteTo(Span<byte> span, ushort channel, MethodBase method) |
| 87 | + { |
| 88 | + const int StartClassId = StartPayload; |
| 89 | + const int StartMethodId = StartPayload + 2; |
| 90 | + const int StartMethodArguments = StartPayload + 4; |
| 91 | + |
| 92 | + NetworkOrderSerializer.WriteUInt16(span.Slice(StartClassId), method.ProtocolClassId); |
| 93 | + NetworkOrderSerializer.WriteUInt16(span.Slice(StartMethodId), method.ProtocolMethodId); |
| 94 | + var argWriter = new MethodArgumentWriter(span.Slice(StartMethodArguments)); |
| 95 | + method.WriteArgumentsTo(ref argWriter); |
| 96 | + return WriteBaseFrame(span, FrameType.FrameMethod, channel, StartMethodArguments - StartPayload + argWriter.Offset); |
| 97 | + } |
129 | 98 | }
|
130 | 99 |
|
131 |
| - internal override int GetMinimumPayloadBufferSize() |
| 100 | + internal static class Header |
132 | 101 | {
|
133 |
| - return 0; |
| 102 | + /* +----------+----------+-------------------+-----------+ |
| 103 | + * | Class Id | (unused) | Total body length | Arguments | |
| 104 | + * +----------+----------+-------------------+-----------+ |
| 105 | + * | 2 bytes | 2 bytes | 8 bytes | x bytes | |
| 106 | + * +----------+----------+-------------------+-----------+ */ |
| 107 | + public const int FrameSize = BaseFrameSize + 2 + 2 + 8; |
| 108 | + |
| 109 | + public static int WriteTo(Span<byte> span, ushort channel, ContentHeaderBase header, int bodyLength) |
| 110 | + { |
| 111 | + const int StartClassId = StartPayload; |
| 112 | + const int StartWeight = StartPayload + 2; |
| 113 | + const int StartBodyLength = StartPayload + 4; |
| 114 | + const int StartHeaderArguments = StartPayload + 12; |
| 115 | + |
| 116 | + NetworkOrderSerializer.WriteUInt16(span.Slice(StartClassId), header.ProtocolClassId); |
| 117 | + NetworkOrderSerializer.WriteUInt16(span.Slice(StartWeight), 0); // Weight - not used |
| 118 | + NetworkOrderSerializer.WriteUInt64(span.Slice(StartBodyLength), (ulong)bodyLength); |
| 119 | + var headerWriter = new ContentHeaderPropertyWriter(span.Slice(StartHeaderArguments)); |
| 120 | + header.WritePropertiesTo(ref headerWriter); |
| 121 | + return WriteBaseFrame(span, FrameType.FrameHeader, channel, StartHeaderArguments - StartPayload + headerWriter.Offset); |
| 122 | + } |
134 | 123 | }
|
135 | 124 |
|
136 |
| - internal override int WritePayload(Span<byte> span) |
| 125 | + internal static class BodySegment |
137 | 126 | {
|
138 |
| - return 0; |
139 |
| - } |
140 |
| - } |
141 |
| - |
142 |
| - internal abstract class OutboundFrame |
143 |
| - { |
144 |
| - public int Channel { get; } |
145 |
| - public FrameType Type { get; } |
| 127 | + /* +--------------+ |
| 128 | + * | Body segment | |
| 129 | + * +--------------+ |
| 130 | + * | x bytes | |
| 131 | + * +--------------+ */ |
| 132 | + public const int FrameSize = BaseFrameSize; |
| 133 | + |
| 134 | + public static int WriteTo(Span<byte> span, ushort channel, ReadOnlySpan<byte> body) |
| 135 | + { |
| 136 | + const int StartBodyArgument = StartPayload; |
146 | 137 |
|
147 |
| - protected OutboundFrame(FrameType type, int channel) |
148 |
| - { |
149 |
| - Type = type; |
150 |
| - Channel = channel; |
| 138 | + body.CopyTo(span.Slice(StartBodyArgument)); |
| 139 | + return WriteBaseFrame(span, FrameType.FrameBody, channel, StartBodyArgument - StartPayload + body.Length); |
| 140 | + } |
151 | 141 | }
|
152 | 142 |
|
153 |
| - internal void WriteTo(Span<byte> span) |
| 143 | + internal static class Heartbeat |
154 | 144 | {
|
155 |
| - span[0] = (byte)Type; |
156 |
| - NetworkOrderSerializer.WriteUInt16(span.Slice(1), (ushort)Channel); |
157 |
| - int bytesWritten = WritePayload(span.Slice(7)); |
158 |
| - NetworkOrderSerializer.WriteUInt32(span.Slice(3), (uint)bytesWritten); |
159 |
| - span[bytesWritten + 7] = Constants.FrameEnd; |
160 |
| - } |
| 145 | + /* Empty frame */ |
| 146 | + public const int FrameSize = BaseFrameSize; |
161 | 147 |
|
162 |
| - internal abstract int WritePayload(Span<byte> span); |
163 |
| - internal abstract int GetMinimumPayloadBufferSize(); |
164 |
| - internal int GetMinimumBufferSize() |
165 |
| - { |
166 |
| - return 8 + GetMinimumPayloadBufferSize(); |
167 |
| - } |
| 148 | + public static Span<byte> Payload => new byte[] |
| 149 | + { |
| 150 | + Constants.FrameHeartbeat, |
| 151 | + 0, 0, // channel |
| 152 | + 0, 0, 0, 0, // payload length |
| 153 | + Constants.FrameEnd |
| 154 | + }; |
168 | 155 |
|
169 |
| - public override string ToString() |
170 |
| - { |
171 |
| - return $"(type={Type}, channel={Channel})"; |
172 | 156 | }
|
173 | 157 | }
|
174 | 158 |
|
|
0 commit comments