# 機能設計書 67-WebSocket

## 概要

本ドキュメントは、Jenkins における WebSocket 通信機能の設計について記述する。

### 本機能の処理概要

WebSocket 機能は、Jenkins とクライアント間で双方向リアルタイム通信を可能にする基盤機能である。サーブレットコンテナに依存しない抽象化レイヤーを提供し、プラグインから利用可能にしている。

**業務上の目的・背景**：従来の HTTP ポーリングでは、ビルドログのストリーミングやリアルタイム通知において効率が悪く、遅延やサーバー負荷の問題があった。WebSocket は、一度接続を確立すると双方向でデータを送受信でき、低レイテンシでリアルタイム性の高い通信を実現する。これにより、ビルドログのリアルタイム表示、エージェント通信、プラグイン間のリアルタイム連携などが効率的に行える。

**機能の利用シーン**：
- ビルドログのリアルタイムストリーミング
- エージェント接続（Inbound Agent Protocol）
- コンソール出力のリアルタイム表示
- プラグインによるリアルタイム通知
- CLI over WebSocket

**主要な処理内容**：
1. WebSocket 接続のアップグレード処理
2. Provider インターフェースによるサーブレットコンテナ抽象化
3. WebSocketSession による接続管理
4. テキスト/バイナリメッセージの送受信
5. 接続維持のための Ping/Pong 処理
6. エラーハンドリングと接続終了処理

**関連システム・外部連携**：
- サーブレットコンテナ（Jetty、Tomcat 等）
- Stapler: Web フレームワーク
- Inbound Agent: エージェント接続

**権限による制御**：WebSocket 接続は Jenkins の認証・認可システムに統合されており、各エンドポイントで適切な権限チェックが必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 15 | コンソール出力 | 補助機能 | ビルドログのリアルタイム表示 |

## 機能種別

通信基盤 / リアルタイム連携

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| HTTP Upgrade | Header | Yes | WebSocket へのアップグレードリクエスト | WebSocket プロトコル準拠 |

### 入力データソース

- HTTP リクエスト（WebSocket ハンドシェイク）
- WebSocket フレーム（テキスト/バイナリ）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 101 Switching Protocols | HTTP | WebSocket アップグレード応答 |
| テキストメッセージ | String | WebSocket テキストフレーム |
| バイナリメッセージ | byte[] | WebSocket バイナリフレーム |

### 出力先

- WebSocket 接続

## 処理フロー

### 処理シーケンス

```
1. WebSocket 接続リクエストの受信
   └─ HTTP Upgrade リクエスト

2. Provider の検索
   └─ ServiceLoader で利用可能な Provider を検索

3. 接続のアップグレード
   └─ Provider.handle() で WebSocket 接続を確立

4. 接続確立コールバック
   └─ Listener.onWebSocketConnect() の呼び出し

5. Ping/Pong の開始
   └─ 接続維持のための定期的な Ping 送信

6. メッセージの送受信
   └─ テキスト/バイナリメッセージの処理

7. 接続終了処理
   └─ Listener.onWebSocketClose() の呼び出し
   └─ Ping/Pong の停止
```

### フローチャート

```mermaid
flowchart TD
    A[HTTP Upgrade リクエスト] --> B{Provider 利用可能?}
    B -->|No| C[404 エラー]
    B -->|Yes| D[Provider.handle]
    D --> E{接続成功?}
    E -->|No| F[エラーステータス]
    E -->|Yes| G[onWebSocketConnect]
    G --> H[Ping 開始]
    H --> I[メッセージ待機]
    I --> J{メッセージ種別}
    J -->|テキスト| K[onWebSocketText]
    J -->|バイナリ| L[onWebSocketBinary]
    J -->|クローズ| M[onWebSocketClose]
    J -->|エラー| N[onWebSocketError]
    K --> I
    L --> I
    M --> O[Ping 停止]
    N --> O
    O --> P[接続終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-67-01 | Provider 必須 | WebSocket 機能には Provider の実装が必要 | 常時 |
| BR-67-02 | 接続維持 | Ping/Pong で接続を維持 | 接続中 |
| BR-67-03 | エラー時切断 | ClosedChannelException はクローズとして処理 | エラー発生時 |
| BR-67-04 | 非対応時 404 | Provider がない場合は 404 を返す | Provider なし |

### 計算ロジック

該当なし

## データベース操作仕様

### 操作別データベース影響一覧

該当なし（WebSocket 機能はデータベースを直接操作しない）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 404 | Not Found | Provider が利用不可 | エラーステータス設定 |
| 500 | Internal Error | 接続処理中の例外 | ログ出力、エラーステータス設定 |
| ClosedChannelException | 切断 | チャネルが閉じられた | クローズとして処理 |

### リトライ仕様

該当なし（WebSocket 接続はクライアント側でリトライを管理）

## トランザクション仕様

該当なし

## パフォーマンス要件

- 低レイテンシの双方向通信
- 効率的なバッファリングとフレーム処理
- 同時接続数のスケーラビリティ

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

- WebSocket エンドポイントでの認証・認可チェック
- Origin ヘッダーの検証（CSRF 対策）
- セキュアな接続（wss://）の推奨

## 備考

- WebSockets クラスは static メソッドを提供するユーティリティクラス
- Provider は ServiceLoader で検索される SPI
- WebSocketSession を継承してカスタムハンドラーを実装
- isSupported() で WebSocket 対応を確認可能

---

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

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

### 推奨読解順序

#### Step 1: インターフェースを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Provider.java | `websocket/spi/src/main/java/jenkins/websocket/Provider.java` | Provider インターフェースの構造（40-78行目） |

**読解のコツ**: Provider は SPI（Service Provider Interface）として設計されている。handle()、Listener、Handler の3つのインターフェースが定義されている。

#### Step 2: WebSockets クラスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | WebSockets.java | `core/src/main/java/jenkins/websocket/WebSockets.java` | WebSockets クラスの実装（48-149行目） |

**主要処理フロー**:
1. **52-64行目**: findProvider() で ServiceLoader から Provider を検索
2. **68-75行目**: upgrade() - HttpResponse としてアップグレード処理をラップ
3. **81-142行目**: upgradeResponse() - 実際のアップグレード処理
4. **144-146行目**: isSupported() - WebSocket 対応確認

#### Step 3: アップグレード処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | WebSockets.java | `core/src/main/java/jenkins/websocket/WebSockets.java` | upgradeResponse() メソッド（81-142行目） |

**主要処理フロー**:
- **82-85行目**: Provider 不在時の 404 エラー
- **87-134行目**: Provider.Listener の実装
- **91-95行目**: onWebSocketConnect() - 接続確立時の処理
- **103-106行目**: onWebSocketClose() - 接続終了時の処理
- **109-115行目**: onWebSocketError() - エラー時の処理

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

```
WebSocket 操作
    │
    ├─ WebSockets.upgrade(session)
    │      └─ HttpResponse.generateResponse()
    │             └─ upgradeResponse() (72-73行目)
    │
    └─ WebSockets.upgradeResponse(session, req, rsp)
           ├─ provider == null チェック (82-85行目)
           └─ provider.handle(req, rsp, Listener) (87行目)
                  │
                  ├─ Listener.onWebSocketConnect()
                  │      ├─ session.startPings() (93行目)
                  │      └─ session.opened() (94行目)
                  │
                  ├─ Listener.onWebSocketClose()
                  │      ├─ session.stopPings() (104行目)
                  │      └─ session.closed() (105行目)
                  │
                  ├─ Listener.onWebSocketError()
                  │      └─ session.error() (113行目)
                  │
                  ├─ Listener.onWebSocketBinary()
                  │      └─ session.binary() (120行目)
                  │
                  └─ Listener.onWebSocketText()
                         └─ session.text() (129行目)
```

### データフロー図

```
[入力]                      [処理]                           [出力]

HTTP Upgrade ────────▶ WebSockets.upgrade/upgradeResponse
                              │
                              ▼
                       Provider.handle()
                              │
                              ▼
サーブレットコンテナ ──▶ WebSocket 接続確立
                              │
                              ▼
                       Listener コールバック
                              │
                              ▼
WebSocketSession ───▶ メッセージ処理 ────────▶ Handler.sendXxx()
                              │
                              ▼
                       接続終了処理
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Provider.java | `websocket/spi/src/main/java/jenkins/websocket/Provider.java` | ソース | WebSocket Provider SPI |
| WebSockets.java | `core/src/main/java/jenkins/websocket/WebSockets.java` | ソース | WebSocket ユーティリティクラス |
| WebSocketSession.java | `core/src/main/java/jenkins/websocket/WebSocketSession.java` | ソース | WebSocket セッション基底クラス |
| JettyWebSocketProvider.java | `websocket/jetty12/.../JettyWebSocketProvider.java` | ソース | Jetty 12 用 Provider 実装 |
