Skip to content

Eventos WebSocket

Lista completa de todos os eventos WebSocket disponíveis no CSGOFlip.

Eventos do Servidor → Cliente

Conexão

connected

Emitido quando a conexão WebSocket é estabelecida.

typescript
interface ConnectedEvent {
  message: string;
  userId?: string;      // Presente se autenticado
  room?: string;        // Presente se autenticado (user:{userId})
}

Exemplo (autenticado):

json
{
  "message": "Connected to live drops",
  "userId": "123456789",
  "room": "user:123456789"
}

Exemplo (público):

json
{
  "message": "Connected to live drops (public)"
}

Saldo

balance:updated

Emitido quando o saldo do usuário é atualizado.

Escopo: Privado (sala user:{userId})

typescript
interface BalanceUpdatedEvent {
  balance: number;          // Saldo formatado (ex: 150.50)
  balanceCents: string;     // Saldo em centavos como string
  timestamp: string;        // ISO 8601
}

Exemplo:

json
{
  "balance": 150.50,
  "balanceCents": "15050",
  "timestamp": "2024-01-15T10:30:00.000Z"
}

Live Drops

live:drop

Emitido quando um item é dropado (após animação da roleta).

Escopo: Global (todos os clientes)

typescript
interface LiveDropEvent {
  id: string;
  itemName: string;
  itemImage: string;
  rarity: string;
  valueCents: number;
  userName: string;
  userAvatar: string;
  caseId: string;
  caseName: string;
  isFlip: boolean;
  timestamp: string;
}

Exemplo:

json
{
  "id": "789012345678901234",
  "itemName": "AWP | Dragon Lore",
  "itemImage": "https://cdn.csgoflip.com/items/awp-dragon-lore.png",
  "rarity": "EXTRAORDINARY",
  "valueCents": 250000,
  "userName": "player123",
  "userAvatar": "https://avatars.steamstatic.com/...",
  "caseId": "123",
  "caseName": "Caixa Premium",
  "isFlip": true,
  "timestamp": "2024-01-15T10:30:00.000Z"
}

Batalhas

battle:created

Emitido quando uma nova batalha é criada.

Escopo: Global

typescript
interface BattleCreatedEvent {
  id: string;
  type: string;           // SOLO_1V1, TEAM_3V3
  mode: string;           // NORMAL, INVERTED
  case: {
    id: string;
    name: string;
    imageUrl: string;
    priceCents: number;
  };
  creator: {
    id: string;
    username: string;
    avatarUrl: string;
  };
  entryPriceCents: number;
  roundCount: number;
  maxParticipants: number;
  currentParticipants: number;
}

battle:joined

Emitido quando um jogador entra em uma batalha.

Escopo: Sala da batalha (battle:{battleId})

typescript
interface BattleJoinedEvent {
  battleId: string;
  participant: {
    id: string;
    username: string;
    avatarUrl: string;
    team: number;
    slot: number;
  };
  currentParticipants: number;
  maxParticipants: number;
}

battle:started

Emitido quando a batalha inicia (todos entraram).

Escopo: Sala da batalha

typescript
interface BattleStartedEvent {
  battleId: string;
  countdown: number;      // Segundos até começar
  participants: Array<{
    id: string;
    username: string;
    team: number;
    slot: number;
  }>;
}

battle:round

Emitido após cada rodada da batalha.

Escopo: Sala da batalha

typescript
interface BattleRoundEvent {
  battleId: string;
  roundNumber: number;
  totalRounds: number;
  results: Array<{
    participantId: string;
    roll: number;
    item: {
      id: string;
      name: string;
      imageUrl: string;
      rarity: string;
      valueCents: number;
    };
    isFlip: boolean;
  }>;
  standings: Array<{
    participantId: string;
    totalValueCents: number;
  }>;
}

battle:finished

Emitido quando a batalha termina.

Escopo: Sala da batalha

typescript
interface BattleFinishedEvent {
  battleId: string;
  winnerTeam: number;
  winners: Array<{
    id: string;
    username: string;
    totalValueCents: number;
  }>;
  losers: Array<{
    id: string;
    username: string;
    totalValueCents: number;
  }>;
  settlements: Array<{
    userId: string;
    itemId: string;
    itemName: string;
    type: 'DROPPED' | 'ADDED_FROM_POOL' | 'REMOVED_TO_POOL';
    valueCents: number;
  }>;
  serverSeed: string;     // Revelado para verificação
}

Notificações

notification

Emitido quando o usuário recebe uma notificação.

Escopo: Privado (sala user:{userId})

typescript
interface NotificationEvent {
  id: string;
  type: NotificationType;
  title: string;
  message: string;
  data?: Record<string, any>;
  createdAt: string;
}

enum NotificationType {
  DEPOSIT_CONFIRMED = 'DEPOSIT_CONFIRMED',
  WITHDRAWAL_COMPLETED = 'WITHDRAWAL_COMPLETED',
  WITHDRAWAL_REJECTED = 'WITHDRAWAL_REJECTED',
  BATTLE_INVITE = 'BATTLE_INVITE',
  SWAP_REQUEST = 'SWAP_REQUEST',
  RAFFLE_WON = 'RAFFLE_WON',
  LEVEL_UP = 'LEVEL_UP',
  ACHIEVEMENT = 'ACHIEVEMENT',
}

Exemplo:

json
{
  "id": "456789012345678901",
  "type": "DEPOSIT_CONFIRMED",
  "title": "Depósito Confirmado",
  "message": "Seu depósito de R$ 100,00 foi confirmado!",
  "data": {
    "depositId": "123",
    "amountCents": 10000
  },
  "createdAt": "2024-01-15T10:30:00.000Z"
}

Sorteios

raffle:started

Emitido quando um sorteio começa a aceitar tickets.

Escopo: Global

typescript
interface RaffleStartedEvent {
  id: string;
  name: string;
  prize: {
    type: 'ITEM' | 'BALANCE';
    itemName?: string;
    itemImageUrl?: string;
    valueCents: number;
  };
  ticketPriceCents: number;
  maxTickets: number;
  endsAt: string;
}

raffle:ticket-sold

Emitido quando tickets são vendidos.

Escopo: Sala do sorteio (raffle:{raffleId})

typescript
interface RaffleTicketSoldEvent {
  raffleId: string;
  soldTickets: number;
  maxTickets: number;
  buyer: {
    username: string;
    avatarUrl: string;
  };
  ticketNumbers: number[];
}

raffle:result

Emitido quando o sorteio é realizado.

Escopo: Global

typescript
interface RaffleResultEvent {
  raffleId: string;
  winningTicket: number;
  winner: {
    id: string;
    username: string;
    avatarUrl: string;
  };
  prize: {
    type: 'ITEM' | 'BALANCE';
    itemName?: string;
    valueCents: number;
  };
  serverSeed: string;
  clientSeed: string;
}

Eventos do Cliente → Servidor

ping

Verifica se a conexão está ativa.

typescript
// Enviar
socket.emit('ping');

// Receber
socket.on('pong', (data) => {
  console.log('Latency:', Date.now() - data.timestamp);
});

join:battle

Inscreve-se para receber eventos de uma batalha específica.

typescript
socket.emit('join:battle', { battleId: '123' });

// Resposta
socket.on('battle:joined', (data) => {
  console.log('Joined room:', data.room);
});

leave:battle

Cancela inscrição de eventos de uma batalha.

typescript
socket.emit('leave:battle', { battleId: '123' });

join:raffle

Inscreve-se para receber eventos de um sorteio.

typescript
socket.emit('join:raffle', { raffleId: '456' });

leave:raffle

Cancela inscrição de eventos de um sorteio.

typescript
socket.emit('leave:raffle', { raffleId: '456' });

Códigos de Erro

error

Emitido quando ocorre um erro.

typescript
interface ErrorEvent {
  code: string;
  message: string;
  details?: Record<string, any>;
}
CódigoDescrição
AUTH_REQUIREDAutenticação necessária
INVALID_SESSIONSessão inválida
ROOM_NOT_FOUNDSala não encontrada
PERMISSION_DENIEDSem permissão
RATE_LIMITEDMuitas requisições

Exemplo Completo de Uso

tsx
// hooks/useBattleSocket.ts
import { useEffect, useState, useCallback } from 'react';
import { useWebSocket, useSocketEvent } from '../contexts/WebSocketContext';

interface UseBattleSocketOptions {
  battleId: string;
  onRound?: (data: BattleRoundEvent) => void;
  onFinished?: (data: BattleFinishedEvent) => void;
}

export function useBattleSocket({
  battleId,
  onRound,
  onFinished,
}: UseBattleSocketOptions) {
  const { socket, isConnected } = useWebSocket();
  const [isInRoom, setIsInRoom] = useState(false);

  // Entrar na sala ao conectar
  useEffect(() => {
    if (!socket || !isConnected) return;

    socket.emit('join:battle', { battleId });

    const handleJoined = (data: { room: string }) => {
      if (data.room === `battle:${battleId}`) {
        setIsInRoom(true);
      }
    };

    socket.on('battle:joined', handleJoined);

    return () => {
      socket.emit('leave:battle', { battleId });
      socket.off('battle:joined', handleJoined);
      setIsInRoom(false);
    };
  }, [socket, isConnected, battleId]);

  // Listener de rodadas
  useSocketEvent('battle:round', (data: BattleRoundEvent) => {
    if (data.battleId === battleId && onRound) {
      onRound(data);
    }
  });

  // Listener de finalização
  useSocketEvent('battle:finished', (data: BattleFinishedEvent) => {
    if (data.battleId === battleId && onFinished) {
      onFinished(data);
    }
  });

  return { isInRoom };
}

// Uso no componente
function BattlePage({ battleId }: { battleId: string }) {
  const [rounds, setRounds] = useState<BattleRoundEvent[]>([]);
  const [result, setResult] = useState<BattleFinishedEvent | null>(null);

  useBattleSocket({
    battleId,
    onRound: (data) => {
      setRounds((prev) => [...prev, data]);
    },
    onFinished: (data) => {
      setResult(data);
    },
  });

  return (
    <div>
      {/* Renderizar batalha */}
    </div>
  );
}

Documentação Técnica CSGOFlip