feat: Implement initial backend structure with API, WebSocket, core models, services, and documentation, alongside dependency and gitignore updates.
This commit is contained in:
1 parent
f82191dd83
commit
7710be86a6
29 files changed
+3927
-1301
No files matched your search
@@ -0,0 +1,796 @@
|
||||
# Exemplos Práticos de Uso da API - OllaHubBackend
|
||||
|
||||
Este documento contém exemplos práticos e casos de uso comuns para integração com a API do OllaHubBackend.
|
||||
|
||||
---
|
||||
|
||||
## Configuração Inicial
|
||||
|
||||
### TypeScript/JavaScript - Cliente Base
|
||||
|
||||
```typescript
|
||||
// api-client.ts
|
||||
const API_BASE_URL = 'http://127.0.0.1:8080';
|
||||
const WS_BASE_URL = 'ws://127.0.0.1:8080';
|
||||
|
||||
class OllaHubClient {
|
||||
private token: string | null = null;
|
||||
|
||||
constructor(token?: string) {
|
||||
this.token = token || null;
|
||||
}
|
||||
|
||||
setToken(token: string) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
private async request<T>(
|
||||
endpoint: string,
|
||||
options: RequestInit = {}
|
||||
): Promise<T> {
|
||||
const headers: HeadersInit = {
|
||||
'Content-Type': 'application/json',
|
||||
...options.headers,
|
||||
};
|
||||
|
||||
if (this.token) {
|
||||
headers['Authorization'] = `Bearer ${this.token}`;
|
||||
}
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}${endpoint}`, {
|
||||
...options,
|
||||
headers,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw new Error(error.error || `HTTP ${response.status}`);
|
||||
}
|
||||
|
||||
if (response.status === 204) {
|
||||
return null as T;
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
// Health
|
||||
async health(): Promise<{ status: string }> {
|
||||
return this.request('/v2/health');
|
||||
}
|
||||
|
||||
// Modelos
|
||||
async listModels(): Promise<Array<{ name: string; description?: string }>> {
|
||||
return this.request('/v2/api/models');
|
||||
}
|
||||
|
||||
async installModel(name: string): Promise<{ status: string; model: string }> {
|
||||
return this.request('/v2/api/models/install', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ name }),
|
||||
});
|
||||
}
|
||||
|
||||
// Criptografia
|
||||
async setCryptoKey(hexKey: string): Promise<{ ok: boolean }> {
|
||||
return this.request('/v2/api/crypto/set-key', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ hex_key: hexKey }),
|
||||
});
|
||||
}
|
||||
|
||||
async rotateCryptoKey(): Promise<{ key: string }> {
|
||||
return this.request('/v2/api/crypto/rotate-key', {
|
||||
method: 'POST',
|
||||
});
|
||||
}
|
||||
|
||||
async encrypt(data: string): Promise<{ ciphertext: string }> {
|
||||
return this.request('/v2/api/crypto/encrypt', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ data }),
|
||||
});
|
||||
}
|
||||
|
||||
async decrypt(ciphertext: string): Promise<{ plaintext: string }> {
|
||||
return this.request('/v2/api/crypto/decrypt', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ data: ciphertext }),
|
||||
});
|
||||
}
|
||||
|
||||
// Usuários
|
||||
async listUsers(): Promise<Array<{ id: string; name: string; email: string }>> {
|
||||
return this.request('/api/v1/users');
|
||||
}
|
||||
|
||||
async getUser(id: string): Promise<{ id: string; name: string; email: string }> {
|
||||
return this.request(`/api/v1/users/${id}`);
|
||||
}
|
||||
|
||||
async createUser(data: { name: string; email: string }): Promise<{ id: string; name: string; email: string }> {
|
||||
return this.request('/api/v1/users', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
}
|
||||
|
||||
async updateUser(id: string, data: { name?: string; email?: string }): Promise<{ id: string; name: string; email: string }> {
|
||||
return this.request(`/api/v1/users/${id}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
}
|
||||
|
||||
async deleteUser(id: string): Promise<void> {
|
||||
return this.request(`/api/v1/users/${id}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
|
||||
// WebSocket
|
||||
createWebSocket(): WebSocket {
|
||||
return new WebSocket(`${WS_BASE_URL}/v2/ws`);
|
||||
}
|
||||
}
|
||||
|
||||
export default OllaHubClient;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Casos de Uso
|
||||
|
||||
### 1. Verificar Status do Sistema
|
||||
|
||||
```typescript
|
||||
import OllaHubClient from './api-client';
|
||||
|
||||
const client = new OllaHubClient();
|
||||
|
||||
async function checkSystem() {
|
||||
try {
|
||||
const health = await client.health();
|
||||
console.log('Sistema OK:', health);
|
||||
} catch (error) {
|
||||
console.error('Sistema indisponível:', error);
|
||||
}
|
||||
}
|
||||
|
||||
checkSystem();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. Verificar e Instalar Ollama
|
||||
|
||||
```typescript
|
||||
async function checkAndInstallOllama() {
|
||||
try {
|
||||
// Verificar status
|
||||
const response = await fetch('http://127.0.0.1:8080/ollama/install-check');
|
||||
const status = await response.json();
|
||||
|
||||
console.log('Status Ollama:', {
|
||||
instalado: status.installed,
|
||||
rodando: status.service_running,
|
||||
api: status.api_status,
|
||||
});
|
||||
|
||||
if (!status.installed || status.api_status !== 'reachable') {
|
||||
console.log('Iniciando instalação...');
|
||||
|
||||
const installResponse = await fetch('http://127.0.0.1:8080/ollama/install', {
|
||||
method: 'POST',
|
||||
});
|
||||
|
||||
const installResult = await installResponse.json();
|
||||
|
||||
if (installResult.installed && installResult.service_started) {
|
||||
console.log('Ollama instalado e rodando!');
|
||||
} else {
|
||||
console.error('Falha na instalação:', installResult.issues);
|
||||
if (installResult.manual_instructions) {
|
||||
console.log('Instruções manuais:', installResult.manual_instructions);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Erro:', error);
|
||||
}
|
||||
}
|
||||
|
||||
checkAndInstallOllama();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. Listar e Instalar Modelos com Progresso
|
||||
|
||||
```typescript
|
||||
import OllaHubClient from './api-client';
|
||||
|
||||
const client = new OllaHubClient('seu_token_jwt');
|
||||
|
||||
async function installModelWithProgress(modelName: string) {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
// 1. Conectar WebSocket
|
||||
const ws = client.createWebSocket();
|
||||
|
||||
let modelInstalled = false;
|
||||
|
||||
ws.onopen = async () => {
|
||||
console.log('WebSocket conectado');
|
||||
|
||||
// 2. Iniciar instalação
|
||||
try {
|
||||
await client.installModel(modelName);
|
||||
console.log(`Instalação de ${modelName} iniciada`);
|
||||
} catch (error) {
|
||||
console.error('Erro ao iniciar instalação:', error);
|
||||
ws.close();
|
||||
reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
|
||||
switch (data.kind) {
|
||||
case 'Log':
|
||||
console.log('📝', data.message);
|
||||
break;
|
||||
|
||||
case 'Progress':
|
||||
try {
|
||||
const progress = JSON.parse(data.message);
|
||||
console.log('📊 Progresso:', progress);
|
||||
} catch {
|
||||
console.log('📊', data.message);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Done':
|
||||
console.log('✅', data.message);
|
||||
modelInstalled = true;
|
||||
ws.close();
|
||||
resolve();
|
||||
break;
|
||||
|
||||
case 'Error':
|
||||
console.error('❌ Erro:', data.message);
|
||||
ws.close();
|
||||
reject(new Error(data.message));
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
ws.onerror = (error) => {
|
||||
console.error('Erro WebSocket:', error);
|
||||
reject(error);
|
||||
};
|
||||
|
||||
ws.onclose = () => {
|
||||
if (!modelInstalled) {
|
||||
reject(new Error('Conexão WebSocket fechada antes da conclusão'));
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// Uso
|
||||
async function main() {
|
||||
try {
|
||||
// Listar modelos disponíveis
|
||||
const models = await client.listModels();
|
||||
console.log('Modelos disponíveis:', models);
|
||||
|
||||
// Instalar um modelo
|
||||
await installModelWithProgress('llama2:7b');
|
||||
console.log('Modelo instalado com sucesso!');
|
||||
} catch (error) {
|
||||
console.error('Erro:', error);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. Sistema de Criptografia Completo
|
||||
|
||||
```typescript
|
||||
import OllaHubClient from './api-client';
|
||||
|
||||
const client = new OllaHubClient('seu_token_jwt');
|
||||
|
||||
async function cryptoWorkflow() {
|
||||
try {
|
||||
// 1. Gerar nova chave
|
||||
console.log('Gerando nova chave de criptografia...');
|
||||
const { key } = await client.rotateCryptoKey();
|
||||
console.log('Chave gerada:', key);
|
||||
|
||||
// Salvar chave localmente (ex: localStorage, secure storage)
|
||||
localStorage.setItem('crypto_key', key);
|
||||
|
||||
// 2. Criptografar dados sensíveis
|
||||
const sensitiveData = 'senha_super_secreta_123';
|
||||
console.log('Criptografando dados...');
|
||||
const { ciphertext } = await client.encrypt(sensitiveData);
|
||||
console.log('Dados criptografados:', ciphertext);
|
||||
|
||||
// 3. Descriptografar
|
||||
console.log('Descriptografando...');
|
||||
const { plaintext } = await client.decrypt(ciphertext);
|
||||
console.log('Dados descriptografados:', plaintext);
|
||||
|
||||
if (plaintext === sensitiveData) {
|
||||
console.log('✅ Criptografia funcionando corretamente!');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Erro no fluxo de criptografia:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Usar chave existente
|
||||
async function useExistingKey() {
|
||||
const savedKey = localStorage.getItem('crypto_key');
|
||||
|
||||
if (!savedKey) {
|
||||
console.error('Chave não encontrada');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await client.setCryptoKey(savedKey);
|
||||
console.log('Chave configurada com sucesso');
|
||||
} catch (error) {
|
||||
console.error('Erro ao configurar chave:', error);
|
||||
}
|
||||
}
|
||||
|
||||
cryptoWorkflow();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. Gerenciamento Completo de Usuários
|
||||
|
||||
```typescript
|
||||
import OllaHubClient from './api-client';
|
||||
|
||||
const client = new OllaHubClient('seu_token_jwt');
|
||||
|
||||
async function userManagementDemo() {
|
||||
try {
|
||||
// 1. Criar usuários
|
||||
console.log('Criando usuários...');
|
||||
const user1 = await client.createUser({
|
||||
name: 'João Silva',
|
||||
email: '[email protected]',
|
||||
});
|
||||
console.log('Usuário criado:', user1);
|
||||
|
||||
const user2 = await client.createUser({
|
||||
name: 'Maria Santos',
|
||||
email: '[email protected]',
|
||||
});
|
||||
console.log('Usuário criado:', user2);
|
||||
|
||||
// 2. Listar todos
|
||||
console.log('\nListando usuários...');
|
||||
const users = await client.listUsers();
|
||||
console.log('Total de usuários:', users.length);
|
||||
users.forEach(u => console.log(`- ${u.name} (${u.email})`));
|
||||
|
||||
// 3. Obter usuário específico
|
||||
console.log('\nObtendo usuário específico...');
|
||||
const user = await client.getUser(user1.id);
|
||||
console.log('Usuário:', user);
|
||||
|
||||
// 4. Atualizar usuário
|
||||
console.log('\nAtualizando usuário...');
|
||||
const updated = await client.updateUser(user1.id, {
|
||||
name: 'João Silva Atualizado',
|
||||
email: '[email protected]',
|
||||
});
|
||||
console.log('Usuário atualizado:', updated);
|
||||
|
||||
// 5. Deletar usuário
|
||||
console.log('\nDeletando usuário...');
|
||||
await client.deleteUser(user2.id);
|
||||
console.log('Usuário deletado');
|
||||
|
||||
// 6. Verificar lista final
|
||||
const finalUsers = await client.listUsers();
|
||||
console.log('\nUsuários restantes:', finalUsers.length);
|
||||
} catch (error) {
|
||||
console.error('Erro no gerenciamento de usuários:', error);
|
||||
}
|
||||
}
|
||||
|
||||
userManagementDemo();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6. Tratamento de Erros Robusto
|
||||
|
||||
```typescript
|
||||
import OllaHubClient from './api-client';
|
||||
|
||||
const client = new OllaHubClient('seu_token_jwt');
|
||||
|
||||
async function robustRequest<T>(
|
||||
fn: () => Promise<T>,
|
||||
retries = 3
|
||||
): Promise<T> {
|
||||
for (let i = 0; i < retries; i++) {
|
||||
try {
|
||||
return await fn();
|
||||
} catch (error: any) {
|
||||
const isLastAttempt = i === retries - 1;
|
||||
|
||||
if (error.message.includes('401')) {
|
||||
throw new Error('Token JWT inválido. Faça login novamente.');
|
||||
}
|
||||
|
||||
if (error.message.includes('500')) {
|
||||
if (isLastAttempt) {
|
||||
throw new Error('Erro interno do servidor. Tente novamente mais tarde.');
|
||||
}
|
||||
console.warn(`Tentativa ${i + 1} falhou, tentando novamente...`);
|
||||
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
|
||||
continue;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('Número máximo de tentativas excedido');
|
||||
}
|
||||
|
||||
// Uso
|
||||
async function exemploComRetry() {
|
||||
try {
|
||||
const models = await robustRequest(() => client.listModels());
|
||||
console.log('Modelos:', models);
|
||||
} catch (error) {
|
||||
console.error('Erro após retries:', error);
|
||||
}
|
||||
}
|
||||
|
||||
exemploComRetry();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 7. Hook React para WebSocket
|
||||
|
||||
```typescript
|
||||
// useWebSocket.ts
|
||||
import { useEffect, useState, useRef } from 'react';
|
||||
|
||||
interface WsEvent {
|
||||
kind: 'Log' | 'Progress' | 'Done' | 'Error';
|
||||
message: string;
|
||||
}
|
||||
|
||||
export function useWebSocket(url: string) {
|
||||
const [events, setEvents] = useState<WsEvent[]>([]);
|
||||
const [connected, setConnected] = useState(false);
|
||||
const wsRef = useRef<WebSocket | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const ws = new WebSocket(url);
|
||||
wsRef.current = ws;
|
||||
|
||||
ws.onopen = () => {
|
||||
setConnected(true);
|
||||
console.log('WebSocket conectado');
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
const data: WsEvent = JSON.parse(event.data);
|
||||
setEvents(prev => [...prev, data]);
|
||||
};
|
||||
|
||||
ws.onerror = (error) => {
|
||||
console.error('Erro WebSocket:', error);
|
||||
};
|
||||
|
||||
ws.onclose = () => {
|
||||
setConnected(false);
|
||||
console.log('WebSocket desconectado');
|
||||
};
|
||||
|
||||
return () => {
|
||||
ws.close();
|
||||
};
|
||||
}, [url]);
|
||||
|
||||
return { events, connected };
|
||||
}
|
||||
|
||||
// Uso no componente
|
||||
function ModelInstallation() {
|
||||
const { events, connected } = useWebSocket('ws://127.0.0.1:8080/v2/ws');
|
||||
const client = new OllaHubClient('token');
|
||||
|
||||
const handleInstall = async (modelName: string) => {
|
||||
try {
|
||||
await client.installModel(modelName);
|
||||
} catch (error) {
|
||||
console.error('Erro:', error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button onClick={() => handleInstall('llama2:7b')}>
|
||||
Instalar Modelo
|
||||
</button>
|
||||
|
||||
<div>
|
||||
Status: {connected ? 'Conectado' : 'Desconectado'}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{events.map((event, i) => (
|
||||
<div key={i}>
|
||||
<strong>{event.kind}:</strong> {event.message}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 8. Validação de Dados no Frontend
|
||||
|
||||
```typescript
|
||||
// validators.ts
|
||||
export function validateEmail(email: string): boolean {
|
||||
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
return re.test(email);
|
||||
}
|
||||
|
||||
export function validateName(name: string): string | null {
|
||||
if (name.length < 2) {
|
||||
return 'Nome deve ter pelo menos 2 caracteres';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function validateCryptoKey(hexKey: string): string | null {
|
||||
if (!/^[0-9a-fA-F]{64}$/.test(hexKey)) {
|
||||
return 'Chave deve ter 64 caracteres hexadecimais (32 bytes)';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function validateModelName(name: string): string | null {
|
||||
if (!/^[a-zA-Z0-9:._-]+$/.test(name)) {
|
||||
return 'Nome do modelo contém caracteres inválidos';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Uso
|
||||
async function createUserWithValidation(data: { name: string; email: string }) {
|
||||
const nameError = validateName(data.name);
|
||||
if (nameError) {
|
||||
throw new Error(nameError);
|
||||
}
|
||||
|
||||
if (!validateEmail(data.email)) {
|
||||
throw new Error('Email inválido');
|
||||
}
|
||||
|
||||
return client.createUser(data);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 9. Cache de Modelos
|
||||
|
||||
```typescript
|
||||
// model-cache.ts
|
||||
class ModelCache {
|
||||
private cache: Array<{ name: string; description?: string }> | null = null;
|
||||
private cacheTime: number = 0;
|
||||
private readonly TTL = 5 * 60 * 1000; // 5 minutos
|
||||
|
||||
async getModels(client: OllaHubClient, forceRefresh = false): Promise<Array<{ name: string; description?: string }>> {
|
||||
const now = Date.now();
|
||||
|
||||
if (!forceRefresh && this.cache && (now - this.cacheTime) < this.TTL) {
|
||||
return this.cache;
|
||||
}
|
||||
|
||||
try {
|
||||
const models = await client.listModels();
|
||||
this.cache = models;
|
||||
this.cacheTime = now;
|
||||
return models;
|
||||
} catch (error) {
|
||||
if (this.cache) {
|
||||
console.warn('Erro ao atualizar cache, usando cache antigo:', error);
|
||||
return this.cache;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.cache = null;
|
||||
this.cacheTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Uso
|
||||
const cache = new ModelCache();
|
||||
const models = await cache.getModels(client);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 10. Monitoramento de Saúde do Sistema
|
||||
|
||||
```typescript
|
||||
async function monitorSystemHealth(intervalMs = 30000) {
|
||||
const checkHealth = async () => {
|
||||
try {
|
||||
const health = await client.health();
|
||||
console.log('✅ Sistema saudável:', new Date().toISOString());
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('❌ Sistema indisponível:', error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Verificação inicial
|
||||
await checkHealth();
|
||||
|
||||
// Verificações periódicas
|
||||
setInterval(checkHealth, intervalMs);
|
||||
}
|
||||
|
||||
// Monitorar com alertas
|
||||
async function monitorWithAlerts() {
|
||||
let consecutiveFailures = 0;
|
||||
const MAX_FAILURES = 3;
|
||||
|
||||
setInterval(async () => {
|
||||
const isHealthy = await checkHealth();
|
||||
|
||||
if (!isHealthy) {
|
||||
consecutiveFailures++;
|
||||
|
||||
if (consecutiveFailures >= MAX_FAILURES) {
|
||||
console.error('🚨 ALERTA: Sistema indisponível há múltiplas verificações!');
|
||||
// Enviar notificação, email, etc.
|
||||
}
|
||||
} else {
|
||||
consecutiveFailures = 0;
|
||||
}
|
||||
}, 30000);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Casos de Erro Comuns e Soluções
|
||||
|
||||
### Erro 401: Unauthorized
|
||||
|
||||
**Causa**: Token JWT ausente ou inválido.
|
||||
|
||||
**Solução**:
|
||||
```typescript
|
||||
try {
|
||||
await client.listModels();
|
||||
} catch (error: any) {
|
||||
if (error.message.includes('401')) {
|
||||
// Redirecionar para login ou renovar token
|
||||
console.log('Token inválido, faça login novamente');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Erro 400: Bad Request - Validação
|
||||
|
||||
**Causa**: Dados de entrada inválidos.
|
||||
|
||||
**Solução**:
|
||||
```typescript
|
||||
try {
|
||||
await client.createUser({ name: 'A', email: 'invalid' });
|
||||
} catch (error: any) {
|
||||
if (error.message.includes('validação')) {
|
||||
console.error('Erro de validação:', error.message);
|
||||
// Mostrar erros específicos ao usuário
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Erro 409: Conflict - Chave Já Definida
|
||||
|
||||
**Causa**: Tentativa de definir chave de criptografia quando já existe.
|
||||
|
||||
**Solução**:
|
||||
```typescript
|
||||
try {
|
||||
await client.setCryptoKey(key);
|
||||
} catch (error: any) {
|
||||
if (error.message.includes('já definida')) {
|
||||
console.log('Chave já configurada, usando existente');
|
||||
// Continuar com operações de criptografia
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### WebSocket Desconectado
|
||||
|
||||
**Causa**: Conexão perdida durante operação.
|
||||
|
||||
**Solução**:
|
||||
```typescript
|
||||
function createResilientWebSocket(url: string, onReconnect: () => void) {
|
||||
let ws: WebSocket;
|
||||
let reconnectAttempts = 0;
|
||||
const MAX_RECONNECTS = 5;
|
||||
|
||||
function connect() {
|
||||
ws = new WebSocket(url);
|
||||
|
||||
ws.onopen = () => {
|
||||
reconnectAttempts = 0;
|
||||
console.log('WebSocket conectado');
|
||||
};
|
||||
|
||||
ws.onclose = () => {
|
||||
if (reconnectAttempts < MAX_RECONNECTS) {
|
||||
reconnectAttempts++;
|
||||
const delay = Math.min(1000 * Math.pow(2, reconnectAttempts), 30000);
|
||||
console.log(`Reconectando em ${delay}ms...`);
|
||||
setTimeout(() => {
|
||||
connect();
|
||||
onReconnect();
|
||||
}, delay);
|
||||
} else {
|
||||
console.error('Máximo de tentativas de reconexão atingido');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
connect();
|
||||
return ws;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Boas Práticas
|
||||
|
||||
1. **Sempre trate erros**: Use try/catch em todas as chamadas de API
|
||||
2. **Valide dados no frontend**: Reduza requisições inválidas
|
||||
3. **Use cache quando apropriado**: Reduza carga no servidor
|
||||
4. **Implemente retry logic**: Para operações críticas
|
||||
5. **Monitore saúde do sistema**: Detecte problemas cedo
|
||||
6. **Gerencie tokens JWT**: Renove antes de expirar
|
||||
7. **Use WebSocket para operações longas**: Melhor UX
|
||||
8. **Log erros adequadamente**: Facilita debugging
|
||||
|
||||
---
|
||||
|
||||
**Última Atualização**: 2024
|
||||
|
||||
Reference in new issue
Block a user