using System.Buffers;
using NewLife.Data;
namespace NewLife.Messaging;
/// <summary>æ ‡å‡†æ¶ˆæ¯ SRMP ç¼–è§£ç å™¨ã€‚å¸§æ ¼å¼ï¼š1 Flag + 1 Sequence + 2 Length + N Payloadï¼›Length=0xFFFF æ—¶ 8 å—节扩展头</summary>
/// <remarks>
/// <para>æ— çŠ¶æ€ã€å¯è·¨è¿žæŽ¥å…±äº«ã€‚长度分界与 <see cref="DefaultMessage"/> å¸§æ ¼å¼ä¸€è‡´ï¼šè´Ÿè½½é•¿åº¦ < 0xFFFF 用 4 å—节头,å¦åˆ™ 8 å—节扩展头(0xFFFF æ ‡è®° + 4 å—节å°ç«¯æ£å¼é•¿åº¦ï¼‰ã€‚</para>
/// <para>è§£æžäº§å‡º <see cref="DefaultMessage"/> 消æ¯å®žä¾‹ï¼›æž„å»ºæŽ¥å— <see cref="DefaultMessage"/>。
/// åè®®å—æ®µï¼ˆFlag/Sequence/Kind 与扩展头判定)的读写由 <see cref="DefaultMessage"/> 自身承担,本类负责帧层装é…与åºåˆ—å·é…对。</para>
/// </remarks>
/// <example>
/// <code>
/// var codec = new SrmpCodec();
///
/// // å‘é€ï¼šæ•´å¸§æž„建
/// var msg = new DefaultMessage { Sequence = 1 };
/// msg.SetBody(data);
/// var frame = codec.Build(msg);
///
/// // æŽ¥æ”¶ï¼šå®šç•Œå¹¶æž„é€ æ¶ˆæ¯ï¼ˆä½“由帧层绑定)
/// if (codec.TryParse(buffer) is { } rs) { var m = rs.Message; }
/// </code>
/// </example>
public class SrmpCodec : IMessageCodec, IMessageMatcher
{
#region 方法
/// <summary>å®šç•Œå¹¶æž„é€ æ¶ˆæ¯ã€‚è§£æžå¤´éƒ¨ï¼ˆ4 或 8 å—èŠ‚ï¼‰ï¼Œæž„é€ å¤´éƒ¨å—æ®µå°±ä½çš„ <see cref="DefaultMessage"/></summary>
/// <param name="buffer">帧首窗å£ï¼ˆåªè¯»åºåˆ—,å¯è·¨æ®µï¼‰</param>
/// <returns>è§£æžç»“果;头部ä¸è¶³è¿”回 nullï¼ˆä¸æ¶ˆè´¹ã€ä¸äº§ç”Ÿå¯¹è±¡ï¼‰ï¼›æŸå帧返回 <see cref="ParseResult.Invalid"/> 结果</returns>
/// <remarks>在åªè¯»åºåˆ—上顺åºè¯»å–ï¼Œä¸æ‹¼è¯»ã€ä¸ç‰©åŒ–;扩展长度读出负数(åè®®ä¸Šé™ Int32.MaxValue)视为æŸå帧。</remarks>
public ParseResult? TryParse(ReadOnlySequence<Byte> buffer)
{
// åè®®å—æ®µç”±æ¶ˆæ¯ç±»è‡ªè¡Œè§£æžï¼ˆæ¶ˆæ¯å®šä¹‰å³å议),帧层åªè´Ÿè´£è£…é…
var message = new DefaultMessage();
if (!message.TryParse(buffer, out var bodyLength, out var headerSize, out var invalid))
{
// å¤´éƒ¨å·²å®Œæ•´ä½†é•¿åº¦éžæ³•:æŸå帧交由帧层按å议错误处置(æµå¼å…³é—è¿žæŽ¥ã€æ•°æ®æŠ¥ä¸¢åŒ…);
// åªæœ‰æ•°æ®ä¸è¶³æ‰è¿”回 null 进入ç‰å¾…
return invalid ? new ParseResult { Invalid = true } : null;
}
return new ParseResult { Message = message, HeaderSize = headerSize, BodyLength = bodyLength };
}
/// <summary>整帧构建(头 + 内å˜ä½“ï¼‰ã€‚æž„å»ºä¸æ¶ˆè´¹æ¶ˆæ¯è´Ÿè½½</summary>
/// <param name="message">æ ‡å‡†æ¶ˆæ¯</param>
/// <returns>æ•´å¸§æ‹¥æœ‰å¥æŸ„,调用方负责 Dispose</returns>
/// <remarks>
/// <para>已预留的负载零拷è´å€Ÿä½å…±äº«ï¼ˆå¸§å¤´è½åœ¨é¢„留区);其余以新头节点挂接负载链。两ç§ç–ç•¥éƒ½ä¸æ”¹åŠ¨æ¶ˆæ¯è´Ÿè½½ã€‚</para>
/// <para><b>时效</b>:结果å¯èƒ½å¼•用消æ¯è´Ÿè½½ç¼“冲,帧å‘é€å®Œæˆå‰ä¸å¾—å¤ç”¨æˆ–改写。</para>
/// </remarks>
/// <exception cref="ArgumentException">消æ¯ç±»åž‹ä¸æ˜¯ <see cref="DefaultMessage"/></exception>
/// <exception cref="InvalidOperationException">消æ¯ä½“为æµå¼æ¨¡å¼ï¼ˆè¯·ä½¿ç”¨ BuildHeader + æµå¼å‘é€ï¼‰</exception>
public IOwnerPacket? Build(IMessage message)
{
if (message == null) throw new ArgumentNullException(nameof(message));
if (message is not DefaultMessage msg) throw new ArgumentException($"消æ¯ç±»åž‹ [{message.GetType().FullName}] 䏿”¯æŒæ ‡å‡†æ¶ˆæ¯å¸§æ ¼å¼", nameof(message));
if (msg.Body is { IsStreaming: true }) throw new InvalidOperationException("æµå¼æ¶ˆæ¯ä½“æ— æ³•æ•´å¸§æž„å»ºï¼Œè¯·ä½¿ç”¨ BuildHeader + æµå¼å‘é€");
var body = msg.Payload;
var len = 0;
if (body != null) len = body.Total;
// å¢žåŠ åè®®å¤´ï¼šå·²é¢„ç•™çš„æ‹¥æœ‰å¥æŸ„é›¶æ‹·è´å€Ÿä½å…±äº«ï¼Œå…¶ä½™æ–°å¤´èŠ‚ç‚¹æŒ‚æŽ¥è´Ÿè½½é“¾
var size = len < 0xFFFF ? 4 : 8;
var pk = body.PrepareHeader(size);
msg.WriteHeader(pk.GetSpan(), len);
return pk;
}
/// <summary>仅构建头部数æ®åŒ…,声明消æ¯ä½“长度(头 + æµå¼ä½“å‘é€ï¼‰</summary>
/// <param name="message">æ ‡å‡†æ¶ˆæ¯</param>
/// <param name="bodyLength">消æ¯ä½“å—节数(0 ~ 2147483647)</param>
/// <returns>头部数æ®åŒ…,调用方负责 Dispose</returns>
/// <remarks>负载长度 < 0xFFFF 用 4 å—节头,å¦åˆ™ç”¨ 8 å—节扩展头,与整帧构建长度分界一致。</remarks>
/// <exception cref="ArgumentException">消æ¯ç±»åž‹ä¸æ˜¯ <see cref="DefaultMessage"/></exception>
/// <exception cref="ArgumentOutOfRangeException">长度为负或超过 32 ä½å议上é™</exception>
public IOwnerPacket BuildHeader(IMessage message, Int64 bodyLength)
{
if (message == null) throw new ArgumentNullException(nameof(message));
if (message is not DefaultMessage msg) throw new ArgumentException($"消æ¯ç±»åž‹ [{message.GetType().FullName}] 䏿”¯æŒæ ‡å‡†æ¶ˆæ¯å¸§æ ¼å¼", nameof(message));
if (bodyLength < 0) throw new ArgumentOutOfRangeException(nameof(bodyLength), "Body length must be non-negative.");
if (bodyLength > Int32.MaxValue) throw new ArgumentOutOfRangeException(nameof(bodyLength), "Body length exceeds the 32-bit protocol limit.");
var size = bodyLength < 0xFFFF ? 4 : 8;
var pk = new OwnerPacket(size);
msg.WriteHeader(pk.GetSpan(), bodyLength);
return pk;
}
/// <summary>判æ–å“应是å¦åŒ¹é…è¯·æ±‚ã€‚æ ‡å‡†æ¶ˆæ¯æŒ‰åºåˆ—å·è¾ƒä½Ž8ä½é…对</summary>
/// <param name="request">挂起的请求消æ¯</param>
/// <param name="response">收到的å“应消æ¯</param>
/// <returns>是å¦é…对</returns>
/// <remarks>
/// <para>çº¿æ ¼å¼çš„åºåˆ—å·åªæœ‰ 1 å—èŠ‚ï¼ˆè§ <see cref="DefaultMessage.WriteHeader"/>ï¼‰ï¼Œå¯¹ç«¯å›žæ˜¾çš„ä¹Ÿåªæ˜¯ä½Ž 8 ä½ï¼›
/// 请求侧若用自增 Int32 计数器,比较完整 32 ä½ä¼šæ’ä¸ç›¸ç‰ï¼Œåªèƒ½ç‰é…对超时。</para>
/// <para>åŒä¸€è¿žæŽ¥ä¸Šå¹¶å‘数超过 256 时,低 8 ä½ä¼šé‡å¤ï¼Œæ¤æ—¶ä»Žæœ€è¿‘入队的请求开始é…对,与队列的æœç´¢æ–¹å‘一致。</para>
/// </remarks>
public Boolean Match(IMessage request, IMessage response)
{
if (request is not DefaultMessage rq || response is not DefaultMessage rs) return false;
// 仅应ç”类消æ¯å‚与é…对(å“应识别下放åè®® matcherï¼Œæ— æ–¹å‘åè®®å¯ç”¨æ’真 matcher)
if (!rs.Reply) return false;
return (rq.Sequence & 0xFF) == (rs.Sequence & 0xFF);
}
#endregion
}
|