# PtyManager 使用文檔
## 概述
`PtyManager` 是一個簡單的偽終端(PTY)I/O 管理器,它使用 `tokio::sync::mpsc` 通道來處理應用程序和 PTY 之間的數據傳輸。
## 結構
```rust
pub struct PtyManager {
tx: mpsc::UnboundedSender<Vec<u8>>, // 發送通道
rx: mpsc::UnboundedReceiver<Vec<u8>>, // 接收通道
}
```
## 特性
- ✅ **異步通道**: 使用 `tokio` 的無界通道
- ✅ **零拷貝傳輸**: 直接傳輸 `Vec<u8>` 引用
- ✅ **線程安全**: 所有操作都是線程安全的
- ✅ **簡單 API**: 只有三個公開方法
## 基本用法
### 1. 創建 PtyManager
```rust
use ratel_rust::pty::PtyManager;
// 方式一:使用 new() 方法
let mut pty = PtyManager::new();
// 方式二:使用 Default trait
let mut pty = PtyManager::default();
```
### 2. 獲取發送器
```rust
// 獲取發送通道(可以用於克隆)
let sender = pty.sender();
// 發送數據到 PTY
let data = b"Hello, PTY!".to_vec();
sender.send(data)?;
```
### 3. 獲取接收器
```rust
// 獲取接收通道的可變引用
let receiver = pty.receiver();
// 在異步任務中接收數據
while let Some(data) = receiver.recv().await {
println!("Received: {:?}", data);
}
```
## 完整示例
### 示例 1: 基本數據傳輸
```rust
use tokio::spawn;
use ratel_rust::pty::PtyManager;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let mut pty = PtyManager::new();
let sender = pty.sender();
// 發送任務
let send_task = spawn(async move {
let data = b"Test message".to_vec();
for i in 0..5 {
let msg = format!("Message {}: {}", i, String::from_utf8_lossy(&data));
sender.send(msg.into_bytes())?;
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
}
Ok::<(), anyhow::Error>(())
});
// 接收任務
let recv_task = spawn(async move {
let receiver = pty.receiver();
while let Some(data) = receiver.recv().await {
println!("Received: {}", String::from_utf8_lossy(&data));
}
});
// 等待任務完成
send_task.await??;
recv_task.abort();
Ok(())
}
```
### 示例 2: 與網絡集成
```rust
use tokio::select;
use ratel_rust::pty::PtyManager;
async fn network_loop(pty: &mut PtyManager, mut stream: TcpStream) -> anyhow::Result<()> {
let sender = pty.sender();
let receiver = pty.receiver();
loop {
tokio::select! {
// 發送 PTY 數據到網絡
Some(data) = receiver.recv() => {
stream.write_all(&data).await?;
}
// 接收網絡數據到 PTY
result = stream.read_buf(&mut buffer) => {
let n = result?;
if n == 0 {
break;
}
let data = buffer.split_to(n).to_vec();
// 處理數據...
}
}
}
Ok(())
}
```
### 示例 3: 多個發送器
```rust
use std::sync::Arc;
use tokio::task::JoinHandle;
use ratel_rust::pty::PtyManager;
async fn multi_sender_example() -> anyhow::Result<()> {
let mut pty = PtyManager::new();
// 共享發送器
let sender = Arc::new(pty.sender());
// 創建多個發送任務
let tasks: Vec<JoinHandle<()>> = (0..3)
.map(|i| {
let sender = Arc::clone(&sender);
spawn(async move {
let msg = format!("Task {} message", i);
let _ = sender.send(msg.into_bytes());
})
})
.collect();
// 等待所有任務
for task in tasks {
task.await?;
}
Ok(())
}
```
## 輔助函數
### `read_line()`
直接從標準輸入讀取一行文本。
```rust
use ratel_rust::pty::read_line;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let line = read_line().await?;
println!("You entered: {}", line);
Ok(())
}
```
**特點:**
- 異步讀取
- 自動去除首尾空白字符
- 返回 `Result<String>`
### `read_key()`
使用 `crossterm` 從終端讀取單個鍵盤事件。
```rust
use ratel_rust::pty::read_key;
use crossterm::event::KeyEvent;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let key = read_key().await?;
println!("Key pressed: {:?}", key);
Ok(())
}
```
**特點:**
- 輪詢間隔: 100ms
- 返回 `Result<KeyEvent>`
- 支持所有 `crossterm` 鍵盤事件
## 注意事項
### 1. 通道類型
使用的是 `Unbounded` 通道,意味著:
- 無容量限制
- 如果生產速度遠大於消費速度,可能導致內存問題
- 適合於生產者和消費者速度相近的場景
### 2. 接收器權限
只有通過 `receiver()` 方法才能獲得接收器:
- 接收器是可變引用,同一時間只有一個消費者
- 發送器可以克隆,支持多個生產者
### 3. 錯誤處理
通道操作返回 `Result`,應該正確處理錯誤:
```rust
match sender.send(data) {
Ok(_) => println!("Sent successfully"),
Err(e) => {
// 接收端已關閉
eprintln!("Failed to send: {:?}", e);
return Err(e.into());
}
}
```
## 性能考慮
### 內存使用
- 每個消息都是 `Vec<u8>`,會在堆上分配
- 大量小消息可能導致內存碎片
- 考慮批量發送以減少分配
### 延遲
- 無界通道在負載高時可能有延遲
- 如果需要低延遲,考慮使用有界通道
## 最佳實踐
### 1. 使用 `tokio::select!`
在網絡應用中,使用 `tokio::select!` 同時處理 PTY 和網絡 I/O:
```rust
tokio::select! {
Some(data) = receiver.recv() => {
// 處理 PTY 數據
}
result = network.receive() => {
// 處理網絡數據
}
}
```
### 2. 優雅地關閉
發送端需要優雅地關閉通道:
```rust
drop(sender); // 關閉發送端
// 接收端會收到 None
while let Some(data) = receiver.recv().await {
// 處理最後的消息
}
```
### 3. 錯誤恢復
在生產環境中,應該有錯誤恢復機制:
```rust
loop {
match receiver.recv().await {
Some(data) => {
if let Err(e) = process_data(data) {
eprintln!("Processing error: {:?}", e);
// 繼續而不是退出
}
}
None => {
println!("Channel closed");
break;
}
}
}
```
## 相關模塊
- `crate::shell`: 使用 `PtyManager` 的主 shell 邏輯
- `crate::network`: 網絡 I/O,可以與 `PtyManager` 配合使用
- `crate::util`: 工具函數
## API 參考
### `PtyManager::new()`
```rust
pub fn new() -> Self
```
創建新的 `PtyManager` 實例。
**返回:** 新的 `PtyManager`
---
### `PtyManager::sender()`
```rust
pub fn sender(&self) -> mpsc::UnboundedSender<Vec<u8>>
```
獲取發送通道的克隆。
**返回:** 發送通道的克隆
---
### `PtyManager::receiver()`
```rust
pub fn receiver(&mut self) -> &mut mpsc::UnboundedReceiver<Vec<u8>>
```
獲取接收通道的可變引用。
**返回:** 接收通道的可變引用
---
### `read_line()`
```rust
pub async fn read_line() -> Result<String>
```
從標準輸入讀取一行文本。
**返回:** 讀取的行(去除空白)
**錯誤:** 讀取失敗時返回錯誤
---
### `read_key()`
```rust
pub async fn read_key() -> Result<KeyEvent>
```
從終端讀取單個鍵盤事件。
**返回:** 鍵盤事件
**錯誤:** 讀取失敗時返回錯誤
## 依賴
- `tokio` - 異步運行時和通道
- `crossterm` - 跨平台終端操作
- `anyhow` - 錯誤處理
## 授權
本模塊是 `ratel-rust` 項目的一部分,遵循相同的許可證。