> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rheel.net/llms.txt
> Use this file to discover all available pages before exploring further.

# WebSocket接続

> リアルタイム通信の実装方法

## WebSocket接続について

Rheel Chat APIは、Socket.IOを使用したリアルタイム双方向通信をサポートしています。
これにより、メッセージの即時受信や各種イベント通知をリアルタイムで実現できます。

## 接続エンドポイント

```
wss://<application_id>.chat.rheel.net/v1/ws
```

## 認証

WebSocket接続には、セッショントークンによる認証が必要です。

### 接続パラメータ

| パラメータ   | 必須  | 説明                           |
| ------- | --- | ---------------------------- |
| `token` | Yes | セッショントークン発行APIで取得したセッショントークン |

## 接続の実装

```javascript theme={null}
import { io } from 'socket.io-client';

const socket = io('wss://<application_id>.chat.rheel.net', {
  path: '/v1/ws',
  auth: {
    token: '<SESSION_TOKEN>'
  },
  transports: ['websocket', 'polling'],
  reconnection: true
});

// 接続成功
socket.on('connect', () => {
  console.log('Connected to Rheel Chat');
  console.log('Socket ID:', socket.id);
});

// 接続エラー
socket.on('connect_error', (error) => {
  console.error('Connection error:', error.message);

  if (error.message.includes('authentication') || error.message.includes('unauthorized')) {
    console.error('認証エラー: トークンが無効または期限切れです');
  }
});

// 切断
socket.on('disconnect', (reason) => {
  console.log('Disconnected:', reason);
});

// エラーハンドリング
socket.on('error', (error) => {
  console.error('Socket error:', error);
});
```

## チャンネルへの自動参加

WebSocket接続が確立されると、ユーザーが所属している全チャンネルに自動的に参加します。

```javascript theme={null}
// 接続成功
socket.on('connect', () => {
  console.log('Connected to Rheel Chat');
  console.log('Socket ID:', socket.id);
  // この時点で、所属している全チャンネルに自動参加済み
});
```

<Note>
  接続後、ユーザーが所属している全チャンネルのメッセージやイベントをリアルタイムで受信できます。
</Note>

## イベントの受信

WebSocket接続を通じて、以下のイベントをリアルタイムで受信できます。

### メッセージイベント

```javascript theme={null}
// 新規メッセージ作成
socket.on('messages:created', (data) => {
  console.log('メッセージが作成されました:', data);
  // data = {
  //   id: "msg_123",
  //   channel_id: "ch_456",
  //   user_id: "user_789",
  //   text: "こんにちは",
  //   created_at: "2025-03-21T10:00:00Z",
  //   ...
  // }
});

// メッセージ更新
socket.on('messages:updated', (data) => {
  console.log('メッセージが更新されました:', data);
});

// メッセージ削除
socket.on('messages:deleted', (data) => {
  console.log('メッセージが削除されました:', data);
  // data = {
  //   message_id: "msg_123",
  //   channel_id: "ch_456",
  //   ...
  // }
});
```

### リアクションイベント

```javascript theme={null}
// リアクション追加
socket.on('reactions:added', (data) => {
  console.log('リアクションが追加されました:', data);
  // data = {
  //   message_id: "msg_123",
  //   user_id: "user_789",
  //   emoji: "👍",
  //   ...
  // }
});

// リアクション削除
socket.on('reactions:removed', (data) => {
  console.log('リアクションが削除されました:', data);
});
```

### 既読イベント

```javascript theme={null}
// 既読状態更新
socket.on('readReceipts:updated', (data) => {
  console.log('既読状態が更新されました:', data);
  // data = {
  //   channel_id: "ch_456",
  //   user_id: "user_789",
  //   message_id: "msg_123",
  //   read_at: "2025-03-21T10:00:00Z",
  //   ...
  // }
});
```

### 添付ファイルイベント

```javascript theme={null}
// 添付ファイル削除
socket.on('attachments:deleted', (data) => {
  console.log('添付ファイルが削除されました:', data);
  // data = {
  //   attachment_id: "att_123",
  //   message_id: "msg_456",
  //   ...
  // }
});
```

## 実装例

以下は、チャンネルに参加してメッセージを送受信する完全な実装例です。

```javascript theme={null}
import { io } from 'socket.io-client';

// 接続
const socket = io('wss://<application_id>.chat.rheel.net', {
  path: '/v1/ws',
  auth: {
    token: '<SESSION_TOKEN>'
  },
  transports: ['websocket', 'polling'],
  reconnection: true,
  reconnectionAttempts: 5,
  reconnectionDelay: 1000
});

socket.on('connect', () => {
  console.log('接続成功:', socket.id);
  // 所属している全チャンネルに自動参加済み
});

// メッセージ受信
socket.on('messages:created', (message) => {
  console.log('新規メッセージ:', message.text);
  displayMessage(message);
});

socket.on('messages:updated', (message) => {
  console.log('メッセージ更新:', message);
  updateMessage(message);
});

socket.on('messages:deleted', (data) => {
  console.log('メッセージ削除:', data.message_id);
  removeMessage(data.message_id);
});

// リアクション受信
socket.on('reactions:added', (data) => {
  console.log('リアクション追加:', data);
  addReaction(data);
});

socket.on('reactions:removed', (data) => {
  console.log('リアクション削除:', data);
  removeReaction(data);
});

// 既読受信
socket.on('readReceipts:updated', (data) => {
  console.log('既読更新:', data);
  updateReadReceipt(data);
});

// エラーハンドリング
socket.on('connect_error', (error) => {
  console.error('接続エラー:', error.message);
});

socket.on('error', (error) => {
  console.error('エラー:', error);
});

socket.on('disconnect', (reason) => {
  console.log('切断:', reason);
});

// ヘルパー関数（実装例）
function displayMessage(message) {
  // UIにメッセージを表示
}

function updateMessage(message) {
  // UIのメッセージを更新
}

function removeMessage(messageId) {
  // UIからメッセージを削除
}

function addReaction(data) {
  // UIにリアクションを追加
}

function removeReaction(data) {
  // UIからリアクションを削除
}

function updateReadReceipt(data) {
  // UIの既読状態を更新
}
```

## 再接続戦略

Socket.IOはデフォルトで自動再接続をサポートしています。

```javascript theme={null}
const socket = io('wss://<application_id>.chat.rheel.net', {
  path: '/v1/ws',
  auth: {
    token: '<SESSION_TOKEN>'
  },
  transports: ['websocket', 'polling'],
  // 再接続設定
  reconnection: true,
  reconnectionAttempts: 5,
  reconnectionDelay: 1000,
  reconnectionDelayMax: 5000,
  timeout: 20000
});

// 再接続試行
socket.io.on('reconnect_attempt', (attemptNumber) => {
  console.log(`再接続試行: ${attemptNumber}回目`);
});

// 再接続成功
socket.io.on('reconnect', (attemptNumber) => {
  console.log(`再接続成功: ${attemptNumber}回目の試行後`);
  // 再接続後、自動的に全チャンネルに再参加されます
});

// 再接続失敗
socket.io.on('reconnect_failed', () => {
  console.error('再接続に失敗しました');
});
```

## ベストプラクティス

<AccordionGroup>
  <Accordion title="接続管理">
    * アプリケーション起動時に接続を確立
    * バックグラウンド移行時は切断を検討
    * フォアグラウンド復帰時に再接続
    * 再接続後は自動的に全チャンネルに再参加されます
  </Accordion>

  <Accordion title="メモリ管理">
    * イベントリスナーは適切にクリーンアップ
    * コンポーネント破棄時にリスナーを削除
    * 大量のメッセージ履歴は適切にページング
    * 不要になったら`socket.disconnect()`を呼ぶ
  </Accordion>

  <Accordion title="エラーハンドリング">
    * すべてのイベントでエラーハンドリングを実装
    * トークン期限切れに対応
    * ネットワークエラーを適切に処理
    * `connect_error`と`error`イベントを監視
  </Accordion>

  <Accordion title="パフォーマンス">
    * 不要なイベントリスナーは登録しない
    * メッセージ受信時のUI更新を最適化
    * 大量のイベント受信時はバッチ処理を検討
  </Accordion>
</AccordionGroup>

## トラブルシューティング

<AccordionGroup>
  <Accordion title="接続できない">
    **症状**: `connect_error`イベントが発生する

    **確認事項**:

    * トークンが正しく設定されているか
    * トークンの有効期限が切れていないか
    * エンドポイントURLが正しいか
    * ネットワーク接続が正常か
  </Accordion>

  <Accordion title="メッセージを受信できない">
    **症状**: `messages:created`イベントが発火しない

    **確認事項**:

    * WebSocket接続が正常に確立されているか（`connect`イベントを受信したか）
    * ユーザーがチャンネルに所属しているか（REST APIで確認）
    * 正しいチャンネルでメッセージが送信されているか
  </Accordion>

  <Accordion title="再接続が頻繁に発生する">
    **症状**: 接続が不安定

    **対策**:

    * `transports`の順序を調整（`['websocket', 'polling']`）
    * タイムアウト値を調整
    * ネットワーク環境を確認
  </Accordion>
</AccordionGroup>

## 次のステップ

<CardGroup cols={2}>
  <Card title="メッセージAPI" icon="message" href="/api-reference/endpoint/messages/メッセージの投稿-メッセージの投稿（ファイル付き）">
    REST APIでメッセージを送信する
  </Card>

  <Card title="チャンネルAPI" icon="comments" href="/api-reference/endpoint/channels/チャンネルの作成">
    チャンネルの作成と管理
  </Card>
</CardGroup>
