Add XCode skills for entity caching, ORM, and sharding ETL
|
---
name: pipeline-handler-model
description: >
设计或使用 IPipeline/IPipelineHandler 管é“处ç†å™¨æ¨¡åž‹ï¼Œå°†ç¼–è§£ç ã€åР坆ã€åŽ‹ç¼©ã€æ—¥å¿—ç‰æ¨ªåˆ‡é€»è¾‘
拆分为独立的åŒå‘链å¼å¤„ç†å™¨èŠ‚ç‚¹ï¼Œåœ¨ç½‘ç»œæˆ–æ¶ˆæ¯åœºæ™¯ä¸å®žçްå¯ç»„åˆçš„责任链。
适用于网络åè®®æ ˆè®¾è®¡ã€æ¶ˆæ¯ç¼–è§£ç ã€ä¸é—´ä»¶é“¾è·¯æž„建与管é“代ç 审查任务。
argument-hint: >
è¯´æ˜Žä½ çš„ç®¡é“使用场景:网络收å‘粘包处ç†è¿˜æ˜¯æ¶ˆæ¯ç¼–è§£ç ï¼›
是å¦éœ€è¦åР坆/压缩处ç†å™¨ï¼›æ˜¯å¦éœ€è¦ä¸ºæ¯ä¸ªè¿žæŽ¥ç‹¬ç«‹çжæ€ï¼ˆæœ‰çжæ€å¤„ç†å™¨ï¼‰ï¼›
是å¦åŸºäºŽ NetServer/NetClient 集æˆè¿˜æ˜¯ç‹¬ç«‹ç®¡é“。
---
# 管é“处ç†å™¨æ¨¡åž‹æŠ€èƒ½
## 适用场景
- 设计网络åè®®æ ˆï¼Œéœ€è¦å°†ç²˜åŒ…/拆包ã€åР坆/解密ã€åºåˆ—化/ååºåˆ—化拆分为独立节点。
- 多个业务å议共用相åŒçš„底层编解ç 层(如 LengthFieldCodecï¼‰ï¼Œåªæ›¿æ¢ä¸Šå±‚应用处ç†å™¨ã€‚
- 需è¦åœ¨ `NetServer`/`NetClient` 䏿³¨å…¥è‡ªå®šä¹‰å¤„ç†å™¨ï¼ˆæ—¥å¿—ã€é‰´æƒã€é™æµï¼‰ã€‚
- 代ç 审查:检查处ç†å™¨é¡ºåºæ˜¯å¦åˆç†ã€æœ‰çжæ€å¤„ç†å™¨æ˜¯å¦æ£ç¡®éš”离ã€é“¾è·¯æˆªæ–æ—¶èµ„æºæ˜¯å¦é‡Šæ”¾ã€‚
## æ ¸å¿ƒåŽŸåˆ™
1. **进站æ£åºã€å‡ºç«™é€†åº**:`Read`(收包)从 `Head` 顺åºä¼ å‘ `Tail`ï¼›`Write`(å‘包)从 `Tail` 逆åºä¼ å‘ `Head`。生命周期事件:`Open`/`Error` æ£å‘ä¼ æ’,`Close` 逆å‘ä¼ æ’。
2. **å¿…é¡»ä¼ é€’/截æ–选一**:æ¯ä¸ªå¤„ç†å™¨è¦ä¹ˆè°ƒç”¨ `base.Read/Write` ç»§ç»ä¼ 递,è¦ä¹ˆæœ‰æ„截æ–ï¼›æˆªæ–æ—¶å¿…é¡»é‡Šæ”¾æŒæœ‰çš„ `IPacket` 或资æºã€‚
3. **有状æ€å¤„ç†å™¨å¿…须按连接实例化**ï¼šæŒæœ‰è§£æžç¼“冲区ã€åŠ å¯†çŠ¶æ€ç‰å†…部状æ€çš„处ç†å™¨ï¼Œä¸èƒ½è·¨è¿žæŽ¥å…±äº«â€”â€”æ¯æ¬¡ `NewSession` å¿…é¡» `new` 新实例。
4. **顺åºå†³å®šè¡Œä¸º**:拆包器(`LengthFieldCodec`)必须在解ç 器(`StandardCodec`)å‰é¢ï¼›é¡ºåºé”™è¯¯ä¼šå¯¼è‡´æ®‹åŒ…æˆ–æ— æ³•è¯†åˆ«çš„æ¶ˆæ¯ã€‚
5. **上下文(`IHandlerContext`)贯穿整链**:æºå¸¦ä¼šè¯ã€ç®¡é“ã€Owner ç‰ä¿¡æ¯ï¼›åœ¨é“¾è·¯æœ«ç«¯ç”¨ `context.FireRead(message)` å‘业务层投递消æ¯ã€‚
## æ•°æ®æµæ–¹å‘
```
收包(Read,Head → Tail æ£å‘):
Socket → Handler[0].Read → Handler[1].Read → … → Handler[n] → context.FireRead(msg) → 业务层
å‘包(Write,Tail → Head 逆å‘):
业务层.WriteAsync → Handler[n].Write → … → Handler[0].Write → Socket.Send(pk)
Open / Error(æ£å‘) Close(逆å‘)
```
## 执行æ¥éª¤
### 一ã€ç»„装管é“
```csharp
var pipeline = new Pipeline();
// 1. æ‹†åŒ…å™¨ï¼ˆå¤„ç† TCP 粘包)
pipeline.Add(new LengthFieldCodec { Size = 4 }); // 4å—èŠ‚å¤´éƒ¨é•¿åº¦å—æ®µ
// 2. 消æ¯ç¼–è§£ç 器
pipeline.Add(new StandardCodec());
// 3. å¯é€‰ï¼šè‡ªå®šä¹‰æ¨ªåˆ‡å¤„ç†å™¨ï¼ˆæ—¥å¿—ã€é‰´æƒç‰ï¼‰
pipeline.Add(new LogHandler());
```
### 二ã€å®žçŽ°è‡ªå®šä¹‰åªè¯»å¤„ç†å™¨
```csharp
// 适用场景:拦截读å–的消æ¯ï¼Œåšæ—¥å¿—/统计åŽç»§ç»ä¼ 递
public class LogHandler : Handler
{
public override Object? Read(IHandlerContext context, Object message)
{
XTrace.WriteLine("收包: {0}", message);
return base.Read(context, message); // ↠必须继ç»ä¼ 递
}
public override Object? Write(IHandlerContext context, Object message)
{
XTrace.WriteLine("å‘包: {0}", message);
return base.Write(context, message); // ↠必须继ç»ä¼ 递
}
}
```
### 三ã€å®žçŽ°æœ‰è½¬æ¢é€»è¾‘的处ç†å™¨
```csharp
// é€‚ç”¨åœºæ™¯ï¼šåŠ è§£å¯†ï¼Œè¾“å…¥/输出类型å‡ä¸º IPacket
public class AesHandler : Handler
{
private readonly Byte[] _key;
public AesHandler(Byte[] key) => _key = key;
public override Object? Read(IHandlerContext context, Object message)
{
if (message is not IPacket pk) return base.Read(context, message);
var decrypted = AesDecrypt(pk.GetSpan(), _key);
return base.Read(context, new ArrayPacket(decrypted)); // ä¼ é€’è§£å¯†åŽçš„包
}
public override Object? Write(IHandlerContext context, Object message)
{
if (message is not IPacket pk) return base.Write(context, message);
var encrypted = AesEncrypt(pk.GetSpan(), _key);
return base.Write(context, new ArrayPacket(encrypted));
}
}
```
### å››ã€å¤„ç†ä¸€è¿›å¤šå‡ºï¼ˆç²˜åŒ…场景)
```csharp
// 当一个原始包包å«å¤šæ¡ä¸šåŠ¡æ¶ˆæ¯æ—¶ï¼š
public override Object? Read(IHandlerContext context, Object message)
{
// è§£æžå‡ºå¤šæ¡æ¶ˆæ¯
foreach (var msg in ParseMessages(message))
{
// å¯¹æ¯æ¡æ¶ˆæ¯ç‹¬ç«‹ä¼ 递给链路下游,并投递到业务层
Next?.Read(context, msg);
}
return null; // 返回 null 表示已处ç†å¤šæ¡ï¼Œä¸Šå±‚æ— éœ€å†å¤„ç†
}
```
### 五ã€ä¸Ž NetServer 集æˆ
```csharp
var server = new NetServer { Port = 9000 };
server.NewSession += (sender, e) =>
{
// æ¯æ¡è¿žæŽ¥ç‹¬ç«‹çš„管é“实例
var pipeline = e.Session.Host.Pipeline;
pipeline.Add(new LengthFieldCodec { Size = 4 }); // 有状æ€ï¼Œæ¯è¿žæŽ¥æ–°å»º
pipeline.Add(new AesHandler(sharedKey)); // æ— çŠ¶æ€ï¼Œå¯å…±äº«
pipeline.Add(new MyProtocolCodec());
};
server.Start();
```
### å…ã€Open/Close/Error 生命周期
```csharp
public class AuthHandler : Handler
{
public override Boolean Open(IHandlerContext context)
{
// æ£å‘ä¼ æ’(先自己处ç†å†ä¼ 下去)
// ... åˆå§‹åŒ–鉴æƒçжæ€
return base.Open(context);
}
public override Boolean Close(IHandlerContext context, String reason)
{
// 逆å‘ä¼ æ’ï¼ˆå…ˆä¼ ä¸‹åŽ»å†è‡ªå·±å¤„ç†ï¼‰
var result = base.Close(context, reason);
// ... 清ç†é‰´æƒçжæ€
return result;
}
}
```
## é‡ç‚¹æ£€æŸ¥é¡¹
- [ ] 处ç†å™¨æ·»åŠ é¡ºåºæ˜¯å¦æ£ç¡®ï¼ˆæ‹†åŒ… → è§£ç → 业务,而éžé¢ 倒)?
- [ ] 有状æ€å¤„ç†å™¨ï¼ˆæŒæœ‰ç¼“冲区/状æ€ï¼‰æ˜¯å¦ä¸ºæ¯ä¸ªè¿žæŽ¥åˆ›å»ºç‹¬ç«‹å®žä¾‹ï¼Ÿ
- [ ] 截æ–é“¾è·¯å‰æ˜¯å¦é‡Šæ”¾äº†æŒæœ‰çš„ `IPacket` 或托管资æºï¼ˆé˜²å†…å˜æ³„æ¼ï¼‰ï¼Ÿ
- [ ] `Read` è¿”å›žå¤šæ¶ˆæ¯æ—¶æ˜¯å¦æ£ç¡®è¿”回 `null` 并调用 `Next.Read` 多次?
- [ ] `Open`/`Close`/`Error` 䏿˜¯å¦ä¹Ÿè°ƒç”¨äº† `base.*` 以ä¿è¯äº‹ä»¶ç»§ç»ä¼ æ’?
## è¾“å‡ºè¦æ±‚
- **接å£**:`IPipeline`(管é“)ã€`IPipelineHandler`(处ç†å™¨èŠ‚ç‚¹ï¼‰ã€`IHandlerContext`(上下文)。
- **基类**:`Handler` æä¾›é»˜è®¤ pass-through 实现;业务类继承åŽåªè¦†å†™å…³å¿ƒçš„æ–¹æ³•。
- **内置处ç†å™¨**:`LengthFieldCodec`ï¼ˆé•¿åº¦å—æ®µæ‹†åŒ…)ã€`StandardCodec`ï¼ˆæ ‡å‡†æ¶ˆæ¯ç¼–è§£ç )。
- **测试**:å¯è„±ç¦» `NetServer` 独立测试管é“:手动 `new Pipeline()`,手动 `pipeline.Read(ctx, msg)` 验è¯è¾“出。
## å‚考资料
å‚考示例与模å¼è¯æ®è§ `references/newlife-pipeline-patterns.md`。
|