# 通知設計書 19-MessagePort通知

## 概要

本ドキュメントは、BunにおけるMessagePort経由でのメッセージ送受信通知の設計を記載する。MessagePortを使用してスレッド間や異なるコンテキスト間でメッセージを送受信する機能である。

### 本通知の処理概要

MessagePort通知は、MessageChannelで作成されたポートペアを使用して、異なる実行コンテキスト間でメッセージを双方向に送受信する機能である。ポートは転送可能で、WorkerやIframeに渡して通信チャネルを確立できる。

**業務上の目的・背景**：Worker APIのpostMessageは1対1の通信に限定されるが、MessageChannelを使用することで複数の通信チャネルを確立できる。また、ポートを転送することで、直接接続されていないコンテキスト間でも通信が可能になる。これにより、複雑なマルチスレッドアーキテクチャを構築できる。

**通知の送信タイミング**：`port.postMessage()`が呼び出されると、メッセージはシリアライズされ、entangledされた相手ポートのメッセージキューに追加される。相手ポートが`start()`されている場合、`notifyMessageAvailable()`が呼ばれてメッセージの配信処理がスケジュールされる。

**通知の受信者**：entangled（ペアリング）された相手のMessagePort。受信側は`message`イベントとしてハンドラに渡される。

**通知内容の概要**：SerializedScriptValueでシリアライズされたJavaScript値と、オプションで転送されるMessagePortの配列。

**期待されるアクション**：受信側のMessagePortの`message`イベントハンドラが発火し、MessageEventオブジェクトを通じてデシリアライズされたデータにアクセスできる。

## 通知種別

スレッド間通信（MessagePort経由）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（メッセージキュー経由） |
| 優先度 | 中 |
| リトライ | なし |

### 送信先決定ロジック

entangled（ペアリング）された相手ポートに対して送信。ポートはMessageChannelで作成された時点でペアリングされ、m_remoteIdentifierで相手を識別する。

## 通知テンプレート

### MessagePort通知の場合

| 項目 | 内容 |
|-----|------|
| プロトコル | MessagePortChannelProvider経由 |
| シリアライズ形式 | SerializedScriptValue |
| 転送可能オブジェクト | ArrayBuffer, MessagePort, etc. |

### メッセージ構造

```cpp
MessageWithMessagePorts {
    RefPtr<SerializedScriptValue> message,
    Vector<TransferredMessagePort> transferredPorts
}
```

### 添付ファイル

なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| messageValue | 送信するJavaScript値 | postMessage()の第1引数 | Yes |
| transfer | 転送するオブジェクトの配列 | StructuredSerializeOptions.transfer | No |
| m_identifier | 自身のポート識別子 | MessagePort内部 | Yes |
| m_remoteIdentifier | 相手ポート識別子 | MessagePort内部 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| API呼び出し | port.postMessage() | ポートがentangledされている | メッセージ送信 |
| 内部通知 | notifyMessageAvailable() | メッセージが利用可能 | 受信側への通知 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| ポート未entangled | isEntangled()がfalseの場合、メッセージは破棄 |
| ポートclosed | m_isDetachedがtrueの場合 |
| 自身のポートを転送 | DataCloneErrorをスロー |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[port.postMessage呼び出し] --> B[SerializedScriptValue.create]
    B --> C{シリアライズ成功?}
    C -->|No| D[DataCloneError]
    C -->|Yes| E{ポートがentangled?}
    E -->|No| F[メッセージ破棄]
    E -->|Yes| G{ポート転送あり?}
    G -->|Yes| H{自身のポートを転送?}
    H -->|Yes| D
    H -->|No| I[MessagePort.disentanglePorts]
    G -->|No| J[MessageWithMessagePorts作成]
    I --> J
    J --> K[MessagePortChannelProvider.postMessageToRemote]
    K --> L[相手ポートのキューに追加]
    L --> M[notifyMessageAvailable]
```

### 受信フロー

```mermaid
flowchart TD
    A[notifyMessageAvailable] --> B[ScriptExecutionContext.ensureOnContextThread]
    B --> C[messageAvailable呼び出し]
    C --> D{ポートがstart済み?}
    D -->|No| E[保留]
    D -->|Yes| F[dispatchMessages]
    F --> G[MessagePortChannelProvider.takeAllMessagesForPort]
    G --> H[各メッセージをデシリアライズ]
    H --> I[MessageEvent作成]
    I --> J[dispatchEvent]
```

## データベース参照・更新仕様

### 参照テーブル一覧

本通知はデータベースを使用しない。インメモリのポートレジストリを使用。

| データ構造 | 用途 | 備考 |
|-----------|------|------|
| allMessagePorts | 全ポートの弱参照マップ | MessagePortIdentifier → ThreadSafeWeakPtr |
| portToContextIdentifier | ポートとコンテキストのマップ | スレッド安全な配信のため |
| MessagePortChannelRegistry | ポートチャネル管理 | グローバルレジストリ |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| DataCloneError | シリアライズ不可能な値 | 例外をスロー |
| DataCloneError | 自身のポートを転送 | 例外をスロー |
| ポート未開始 | start()未呼び出し | メッセージを保留 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0 |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | なし |
| 1日あたり上限 | なし |

### 配信時間帯

プロセス稼働中は常時送信可能

## セキュリティ考慮事項

- MessagePortは転送可能だが、一度転送されると元のコンテキストでは使用不可（neutered）
- ポートのクローズにより通信チャネルを明示的に終了可能
- 同一プロセス内でのみ有効（クロスプロセス通信には使用不可）

## 備考

- Web標準のMessageChannel/MessagePort APIに準拠
- BroadcastChannelとは異なり、1対1の通信チャネル
- start()を呼ばないとメッセージが配信されない（onmessage設定時は自動でstart）

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | MessagePort.h | `src/bun.js/bindings/webcore/MessagePort.h` | MessagePort構造体、m_identifier/m_remoteIdentifier |
| 1-2 | MessagePortChannel.h | `src/bun.js/bindings/webcore/MessagePortChannel.h` | チャネル管理構造 |
| 1-3 | MessagePortChannelProvider.h | `src/bun.js/bindings/webcore/MessagePortChannelProvider.h` | プロバイダーインターフェース |

**読解のコツ**: MessagePortIdentifierがポートを一意に識別するキー。entangle/disentangleの概念を理解することが重要。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | MessagePort.cpp | `src/bun.js/bindings/webcore/MessagePort.cpp` | postMessage関数（157-188行目） |

**主要処理フロー**:
1. **161-163行目**: SerializedScriptValue.create呼び出し
2. **166-167行目**: isEntangled()チェック
3. **172-181行目**: ポート転送処理
4. **186行目**: postMessageToRemote呼び出し

#### Step 3: 通知処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | MessagePort.cpp | `src/bun.js/bindings/webcore/MessagePort.cpp` | notifyMessageAvailable静的関数（86-102行目） |
| 3-2 | MessagePort.cpp | `src/bun.js/bindings/webcore/MessagePort.cpp` | dispatchMessages関数（246-295行目） |

**主要処理フロー**:
- **86-102行目**: スレッド安全な通知処理
- **256-291行目**: メッセージのデシリアライズとイベント発火

### プログラム呼び出し階層図

```
port.postMessage(data, transfer)
    │
    └─ MessagePort::postMessage()
           │
           ├─ SerializedScriptValue::create()
           │      └─ シリアライズ + 転送処理
           │
           ├─ isEntangled()チェック
           │      └─ false → 空のExceptionOr返却
           │
           ├─ MessagePort::disentanglePorts()
           │      └─ ポートの切り離し
           │
           └─ MessagePortChannelProvider::postMessageToRemote()
                  │
                  └─ MessagePortChannelProviderImpl
                         │
                         └─ 相手ポートのキューに追加
                                │
                                └─ notifyMessageAvailable()
                                       │
                                       └─ ScriptExecutionContext::ensureOnContextThread()
                                              │
                                              └─ messageAvailable()
                                                     │
                                                     └─ processMessageWithMessagePortsSoon()
                                                            │
                                                            └─ dispatchMessages()
                                                                   │
                                                                   └─ dispatchEvent(MessageEvent)
```

### データフロー図

```
[送信側]                  [チャネル]                    [受信側]

port1.postMessage() ───▶ シリアライズ ───▶ キュー ───▶ port2.onmessage
    │                        │               │              │
    │                        │               │              │
    └─ data                  └─ SSV          └─ MPCP        └─ MessageEvent
       + transfer               + ports         Registry       + data
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| MessagePort.cpp | `src/bun.js/bindings/webcore/MessagePort.cpp` | ソース | MessagePort実装 |
| MessagePort.h | `src/bun.js/bindings/webcore/MessagePort.h` | ヘッダー | MessagePort定義 |
| JSMessagePort.cpp | `src/bun.js/bindings/webcore/JSMessagePort.cpp` | ソース | JSバインディング |
| MessagePortChannel.cpp | `src/bun.js/bindings/webcore/MessagePortChannel.cpp` | ソース | チャネル管理 |
| MessagePortChannelProvider.h | `src/bun.js/bindings/webcore/MessagePortChannelProvider.h` | ヘッダー | プロバイダーIF |
| MessagePortChannelProviderImpl.cpp | `src/bun.js/bindings/webcore/MessagePortChannelProviderImpl.cpp` | ソース | Bun実装 |
| MessagePortChannelRegistry.cpp | `src/bun.js/bindings/webcore/MessagePortChannelRegistry.cpp` | ソース | グローバルレジストリ |
