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.
interface ConnectedEvent {
message: string;
userId?: string; // Presente se autenticado
room?: string; // Presente se autenticado (user:{userId})
}Exemplo (autenticado):
{
"message": "Connected to live drops",
"userId": "123456789",
"room": "user:123456789"
}Exemplo (público):
{
"message": "Connected to live drops (public)"
}Saldo
balance:updated
Emitido quando o saldo do usuário é atualizado.
Escopo: Privado (sala user:{userId})
interface BalanceUpdatedEvent {
balance: number; // Saldo formatado (ex: 150.50)
balanceCents: string; // Saldo em centavos como string
timestamp: string; // ISO 8601
}Exemplo:
{
"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)
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:
{
"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
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})
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
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
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
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})
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:
{
"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
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})
interface RaffleTicketSoldEvent {
raffleId: string;
soldTickets: number;
maxTickets: number;
buyer: {
username: string;
avatarUrl: string;
};
ticketNumbers: number[];
}raffle:result
Emitido quando o sorteio é realizado.
Escopo: Global
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.
// 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.
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.
socket.emit('leave:battle', { battleId: '123' });join:raffle
Inscreve-se para receber eventos de um sorteio.
socket.emit('join:raffle', { raffleId: '456' });leave:raffle
Cancela inscrição de eventos de um sorteio.
socket.emit('leave:raffle', { raffleId: '456' });Códigos de Erro
error
Emitido quando ocorre um erro.
interface ErrorEvent {
code: string;
message: string;
details?: Record<string, any>;
}| Código | Descrição |
|---|---|
AUTH_REQUIRED | Autenticação necessária |
INVALID_SESSION | Sessão inválida |
ROOM_NOT_FOUND | Sala não encontrada |
PERMISSION_DENIED | Sem permissão |
RATE_LIMITED | Muitas requisições |
Exemplo Completo de Uso
// 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>
);
}