mcpField
W
websocket-implementation

websocket-implementation

github.com/secondsky開発242434 回インストール5 週間前に更新
リポジトリ

websocket-implementation について

リアルタイムアプリケーションを構築する開発者向けの、WebSocket 実装スキルです。Socket.IO、React 連携、スケーリング、運用監視を扱います。

主な機能

  1. 01Socket.IO サーバーとクライアントの実装例
  2. 02React WebSocket フックの例
  3. 03メッセージプロトコルの設計
  4. 04Redis によるスケーリング指針
  5. 05接続監視エンドポイント

活用シーン

  1. 01リアルタイムメッセージ機能の構築
  2. 02認証済み WebSocket 接続の管理
  3. 03Redis を使ったデプロイの拡張
  4. 04アクティブな接続とルームの追跡

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/secondsky/claude-skills --skill websocket-implementation

インストール後、Claude Code で/websocket-implementationを入力して読み込まれたか確認します。

同梱ファイルreferences/python-websocket.md

詳細

WebSocket の実装

適切な接続管理により、スケーラブルなリアルタイム通信システムを構築します。

サーバーの実装(Socket.IO)

const { Server } = require('socket.io');
const { createAdapter } = require('@socket.io/redis-adapter');
const { createClient } = require('redis');

const io = new Server(server, {
  cors: { origin: process.env.CLIENT_URL, credentials: true }
});

// Redis adapter for horizontal scaling
const pubClient = createClient({ url: process.env.REDIS_URL });
const subClient = pubClient.duplicate();
Promise.all([pubClient.connect(), subClient.connect()]).then(() => {
  io.adapter(createAdapter(pubClient, subClient));
});

// Connection management
const users = new Map();

io.use((socket, next) => {
  const token = socket.handshake.auth.token;
  try {
    socket.user = verifyToken(token);
    next();
  } catch (err) {
    next(new Error('Authentication failed'));
  }
});

io.on('connection', (socket) => {
  users.set(socket.user.id, socket.id);
  console.log(`User ${socket.user.id} connected`);

  socket.on('join-room', (roomId) => {
    socket.join(roomId);
    socket.to(roomId).emit('user-joined', socket.user);
  });

  socket.on('message', ({ roomId, content }) => {
    io.to(roomId).emit('message', {
      userId: socket.user.id,
      content,
      timestamp: Date.now()
    });
  });

  socket.on('disconnect', () => {
    users.delete(socket.user.id);
  });
});

// Utility methods for message distribution
function broadcastUserUpdate(userId, data) {
  io.to(`user:${userId}`).emit('user-update', data);
}

function notifyRoom(roomId, event, data) {
  io.to(`room:${roomId}`).emit(event, data);
}

function sendDirectMessage(userId, message) {
  const socketId = users.get(userId);
  if (socketId) {
    io.to(socketId).emit('direct-message', message);
  }
}

クライアントの実装

import { io } from 'socket.io-client';

class WebSocketClient {
  constructor(url, token) {
    this.socket = io(url, {
      auth: { token },
      reconnection: true,
      reconnectionDelay: 1000,
      reconnectionAttempts: 5
    });

    this.messageQueue = [];
    this.setupListeners();
  }

  setupListeners() {
    this.socket.on('connect', () => {
      console.log('Connected');
      this.flushQueue();
    });

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

    this.socket.on('message', (msg) => {
      this.onMessage?.(msg);
    });
  }

  joinRoom(roomId) {
    this.socket.emit('join-room', roomId);
  }

  send(roomId, content) {
    if (this.socket.connected) {
      this.socket.emit('message', { roomId, content });
    } else {
      this.messageQueue.push({ roomId, content });
    }
  }

  flushQueue() {
    while (this.messageQueue.length > 0) {
      const msg = this.messageQueue.shift();
      this.socket.emit('message', msg);
    }
  }
}

React フック

function useWebSocket(url) {
  const [socket, setSocket] = useState(null);
  const [connected, setConnected] = useState(false);
  const [messages, setMessages] = useState([]);

  useEffect(() => {
    // getToken() is a user-supplied helper that returns the current auth token
    // Example implementations:
    // - From localStorage: () => localStorage.getItem('authToken')
    // - From context: () => authContext.token
    // - From cookie: () => document.cookie.split('token=')[1]
    const ws = io(url, { auth: { token: getToken() } });

    ws.on('connect', () => setConnected(true));
    ws.on('disconnect', () => setConnected(false));
    ws.on('message', (msg) => {
      setMessages(prev => [...prev, msg]);
    });

    setSocket(ws);
    return () => ws.disconnect();
  }, [url]);

  const send = useCallback((roomId, content) => {
    socket?.emit('message', { roomId, content });
  }, [socket]);

  return { connected, messages, send };
}

メッセージプロトコル

interface Message {
  type: 'message' | 'typing' | 'presence';
  roomId: string;
  userId: string;
  content?: string;
  timestamp: number;
}

// Acknowledge delivery
socket.emit('message', data, (ack) => {
  if (ack.success) console.log('Delivered');
});

その他の実装

references/python-websocket.md を参照してください。内容は以下のとおりです。

  • Python aiohttp WebSocket サーバー
  • FastAPI WebSocket エンドポイント
  • 非同期接続処理

スケーリングに関する考慮事項

接続数アーキテクチャ
<10K単一サーバー
10K-100KRedis pub/sub
>100Kシャーディングされた Redis + ロードバランサー

監視エンドポイント

// Express endpoints for operational visibility
app.get('/api/ws/stats', (req, res) => {
  res.json({
    activeConnections: io.sockets.sockets.size,
    rooms: [...io.sockets.adapter.rooms.keys()],
    users: users.size
  });
});

app.get('/api/ws/health', (req, res) => {
  res.json({
    status: 'healthy',
    uptime: process.uptime(),
    memoryUsage: process.memoryUsage()
  });
});

ベストプラクティス

  • 操作を許可する前に認証します
  • 指数バックオフによる再接続を実装します
  • 対象を絞ったブロードキャストにはルームとチャネルを使用します
  • 接続の健全性を確認するため、ハートビート/ping を追加します
  • 重要なメッセージをデータベースに永続化します
  • アクティブな接続数を監視します
  • ユーザーのプレゼンス/対応状況を表示します
  • 受信メッセージにレート制限を実装します
  • メッセージ配信を確認するため、確認応答を使用します
  • 分散デプロイには Redis を活用します
  • 包括的なエラー処理を実装します

絶対に避けること

  • 機密データを暗号化せずに送信する
  • メモリ内にメッセージを無制限に保存する
  • ルームへの参加時に認可を省略する
  • 接続エラーの処理を無視する
  • ルームの登録数に上限を設けない
  • 切断されたユーザーデータのクリーンアップを怠る
  • 頻繁に過大なメッセージペイロードを送信する
  • 認証情報をメッセージ本文に含める
  • セキュリティ検証なしでデプロイする
  • 接続が制御不能に蓄積することを許す
  • スケーラビリティを考慮せずに構築する

コメント