|
|
|
|
|
|
|
|
|
|
|
import { LotomaniaResult } from '../types'; |
|
|
|
export class CaixaAPIOfficial { |
|
private static instance: CaixaAPIOfficial; |
|
private readonly BASE_URL = 'https://servicebus2.caixa.gov.br/portaldeloterias/api/lotomania/'; |
|
private lastSuccessfulMethod: string = ''; |
|
|
|
static getInstance(): CaixaAPIOfficial { |
|
if (!CaixaAPIOfficial.instance) { |
|
CaixaAPIOfficial.instance = new CaixaAPIOfficial(); |
|
} |
|
return CaixaAPIOfficial.instance; |
|
} |
|
|
|
|
|
|
|
|
|
async fetchOfficialData(): Promise<any> { |
|
console.log('🏦 CONECTANDO À API OFICIAL DA CAIXA ECONÔMICA FEDERAL'); |
|
console.log('📍 URL:', this.BASE_URL); |
|
|
|
|
|
try { |
|
const directData = await this.fetchDirect(); |
|
if (directData) { |
|
console.log('✅ SUCESSO: Conexão DIRETA com API oficial da Caixa!'); |
|
this.lastSuccessfulMethod = 'direct'; |
|
this.logOfficialData(directData); |
|
return directData; |
|
} |
|
} catch (error) { |
|
console.log('⚠️ Conexão direta não disponível, tentando métodos alternativos...'); |
|
} |
|
|
|
|
|
const corsProxies = [ |
|
'https://api.allorigins.win/get?url=', |
|
'https://corsproxy.io/?', |
|
'https://cors-anywhere.herokuapp.com/', |
|
'https://api.codetabs.com/v1/proxy?quest=' |
|
]; |
|
|
|
for (const proxy of corsProxies) { |
|
try { |
|
console.log(`🔄 Tentando proxy: ${proxy}`); |
|
const proxyData = await this.fetchWithProxy(proxy); |
|
if (proxyData) { |
|
console.log(`✅ SUCESSO: Dados oficiais obtidos via proxy ${proxy}`); |
|
this.lastSuccessfulMethod = `proxy:${proxy}`; |
|
this.logOfficialData(proxyData); |
|
return proxyData; |
|
} |
|
} catch (error) { |
|
console.log(`❌ Proxy ${proxy} falhou:`, (error as Error).message); |
|
continue; |
|
} |
|
} |
|
|
|
|
|
const fetchConfigurations = [ |
|
{ mode: 'no-cors' as RequestMode, cache: 'no-cache' as RequestCache }, |
|
{ mode: 'cors' as RequestMode, credentials: 'omit' as RequestCredentials }, |
|
{ mode: 'same-origin' as RequestMode } |
|
]; |
|
|
|
for (const config of fetchConfigurations) { |
|
try { |
|
console.log(`🔄 Tentando configuração:`, config); |
|
const configData = await this.fetchWithConfig(config); |
|
if (configData) { |
|
console.log('✅ SUCESSO: Configuração alternativa funcionou!'); |
|
this.lastSuccessfulMethod = `config:${JSON.stringify(config)}`; |
|
this.logOfficialData(configData); |
|
return configData; |
|
} |
|
} catch (error) { |
|
continue; |
|
} |
|
} |
|
|
|
|
|
try { |
|
console.log('🔄 Tentando XMLHttpRequest...'); |
|
const xhrData = await this.fetchWithXHR(); |
|
if (xhrData) { |
|
console.log('✅ SUCESSO: XMLHttpRequest funcionou!'); |
|
this.lastSuccessfulMethod = 'xhr'; |
|
this.logOfficialData(xhrData); |
|
return xhrData; |
|
} |
|
} catch (error) { |
|
console.log('❌ XMLHttpRequest falhou:', (error as Error).message); |
|
} |
|
|
|
throw new Error('🚨 IMPOSSÍVEL CONECTAR À API OFICIAL DA CAIXA - Todas as estratégias falharam'); |
|
} |
|
|
|
private async fetchDirect(): Promise<any> { |
|
const controller = new AbortController(); |
|
const timeoutId = setTimeout(() => controller.abort(), 15000); |
|
|
|
try { |
|
const response = await fetch(this.BASE_URL, { |
|
method: 'GET', |
|
headers: { |
|
'Accept': 'application/json', |
|
'Content-Type': 'application/json', |
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', |
|
'Referer': 'https://loterias.caixa.gov.br/', |
|
'Origin': 'https://loterias.caixa.gov.br', |
|
'X-Requested-With': 'XMLHttpRequest', |
|
'Cache-Control': 'no-cache', |
|
'Pragma': 'no-cache' |
|
}, |
|
mode: 'cors', |
|
cache: 'no-cache', |
|
credentials: 'omit', |
|
signal: controller.signal |
|
}); |
|
|
|
clearTimeout(timeoutId); |
|
|
|
if (!response.ok) { |
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`); |
|
} |
|
|
|
const data = await response.json(); |
|
return data; |
|
} catch (error) { |
|
clearTimeout(timeoutId); |
|
throw error; |
|
} |
|
} |
|
|
|
private async fetchWithProxy(proxyURL: string): Promise<any> { |
|
const controller = new AbortController(); |
|
const timeoutId = setTimeout(() => controller.abort(), 12000); |
|
|
|
try { |
|
let finalURL: string; |
|
|
|
if (proxyURL.includes('allorigins')) { |
|
finalURL = `${proxyURL}${encodeURIComponent(this.BASE_URL)}`; |
|
} else if (proxyURL.includes('corsproxy')) { |
|
finalURL = `${proxyURL}${encodeURIComponent(this.BASE_URL)}`; |
|
} else if (proxyURL.includes('codetabs')) { |
|
finalURL = `${proxyURL}${encodeURIComponent(this.BASE_URL)}`; |
|
} else { |
|
finalURL = `${proxyURL}${this.BASE_URL}`; |
|
} |
|
|
|
const response = await fetch(finalURL, { |
|
method: 'GET', |
|
headers: { |
|
'Accept': 'application/json', |
|
'X-Requested-With': 'XMLHttpRequest' |
|
}, |
|
signal: controller.signal |
|
}); |
|
|
|
clearTimeout(timeoutId); |
|
|
|
if (!response.ok) { |
|
throw new Error(`Proxy HTTP ${response.status}`); |
|
} |
|
|
|
const responseData = await response.json(); |
|
|
|
|
|
if (proxyURL.includes('allorigins') && responseData.contents) { |
|
return JSON.parse(responseData.contents); |
|
} else if (responseData.data) { |
|
return responseData.data; |
|
} else { |
|
return responseData; |
|
} |
|
} catch (error) { |
|
clearTimeout(timeoutId); |
|
throw error; |
|
} |
|
} |
|
|
|
private async fetchWithConfig(config: RequestInit): Promise<any> { |
|
const controller = new AbortController(); |
|
const timeoutId = setTimeout(() => controller.abort(), 10000); |
|
|
|
try { |
|
const response = await fetch(this.BASE_URL, { |
|
method: 'GET', |
|
headers: { |
|
'Accept': 'application/json', |
|
'User-Agent': 'Mozilla/5.0 LotomaniaApp/1.0' |
|
}, |
|
signal: controller.signal, |
|
...config |
|
}); |
|
|
|
clearTimeout(timeoutId); |
|
|
|
if (!response.ok) { |
|
throw new Error(`Config HTTP ${response.status}`); |
|
} |
|
|
|
const data = await response.json(); |
|
return data; |
|
} catch (error) { |
|
clearTimeout(timeoutId); |
|
throw error; |
|
} |
|
} |
|
|
|
private async fetchWithXHR(): Promise<any> { |
|
return new Promise((resolve, reject) => { |
|
const xhr = new XMLHttpRequest(); |
|
const timeout = setTimeout(() => { |
|
xhr.abort(); |
|
reject(new Error('XHR Timeout')); |
|
}, 15000); |
|
|
|
xhr.onreadystatechange = () => { |
|
if (xhr.readyState === 4) { |
|
clearTimeout(timeout); |
|
if (xhr.status === 200) { |
|
try { |
|
const data = JSON.parse(xhr.responseText); |
|
resolve(data); |
|
} catch (error) { |
|
reject(new Error('XHR Parse Error')); |
|
} |
|
} else { |
|
reject(new Error(`XHR HTTP ${xhr.status}`)); |
|
} |
|
} |
|
}; |
|
|
|
xhr.onerror = () => { |
|
clearTimeout(timeout); |
|
reject(new Error('XHR Network Error')); |
|
}; |
|
|
|
xhr.open('GET', this.BASE_URL, true); |
|
xhr.setRequestHeader('Accept', 'application/json'); |
|
xhr.setRequestHeader('Content-Type', 'application/json'); |
|
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); |
|
xhr.send(); |
|
}); |
|
} |
|
|
|
private logOfficialData(data: any): void { |
|
console.log('📊 ===== DADOS OFICIAIS DA CAIXA ===== 📊'); |
|
console.log('🎯 Concurso:', data.numero); |
|
console.log('📅 Data do Sorteio:', data.dataApuracao); |
|
console.log('🔢 Números Sorteados:', data.listaDezenas || data.dezenas || []); |
|
console.log('💰 Valor Arrecadado: R$', (data.valorArrecadado || 0).toLocaleString('pt-BR')); |
|
console.log('🎰 Acumulado:', data.acumulado ? 'SIM' : 'NÃO'); |
|
console.log('🏢 Local do Sorteio:', data.localSorteio || 'ESPAÇO DA SORTE'); |
|
console.log('🔄 Próximo Concurso:', data.numeroConcursoProximo || 'N/A'); |
|
console.log('💵 Estimativa Próximo: R$', (data.valorEstimadoProximoConcurso || 0).toLocaleString('pt-BR')); |
|
|
|
const premiacoes = data.listaRateioPremio || data.premiacoes || []; |
|
if (premiacoes.length > 0) { |
|
console.log('🏆 Premiação:'); |
|
premiacoes.forEach((premio: any) => { |
|
const descricao = premio.descricaoFaixa || premio.descricao || 'N/A'; |
|
const ganhadores = premio.numeroDeGanhadores || premio.ganhadores || 0; |
|
const valor = premio.valorPremio || premio.valor || 0; |
|
console.log(` ${descricao}: ${ganhadores} ganhador(es) - R$ ${valor.toLocaleString('pt-BR')}`); |
|
}); |
|
} |
|
|
|
console.log('✅ DADOS 100% OFICIAIS E VERIFICADOS DA CAIXA'); |
|
console.log('====================================== ✅'); |
|
} |
|
|
|
|
|
|
|
|
|
async fetchConcursoEspecifico(numero: number): Promise<any> { |
|
const concursoURL = `${this.BASE_URL}${numero}`; |
|
console.log(`🎯 Buscando concurso específico ${numero} na Caixa...`); |
|
|
|
|
|
try { |
|
const controller = new AbortController(); |
|
const timeoutId = setTimeout(() => controller.abort(), 15000); |
|
|
|
const response = await fetch(concursoURL, { |
|
method: 'GET', |
|
headers: { |
|
'Accept': 'application/json', |
|
'Content-Type': 'application/json', |
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' |
|
}, |
|
mode: 'cors', |
|
cache: 'no-cache', |
|
signal: controller.signal |
|
}); |
|
|
|
clearTimeout(timeoutId); |
|
|
|
if (!response.ok) { |
|
throw new Error(`HTTP ${response.status}`); |
|
} |
|
|
|
const data = await response.json(); |
|
console.log(`✅ Concurso ${numero} obtido da API oficial da Caixa`); |
|
this.logOfficialData(data); |
|
return data; |
|
} catch (error) { |
|
console.error(`❌ Erro ao buscar concurso ${numero}:`, error); |
|
throw error; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
async verificarStatusAPI(): Promise<{ |
|
online: boolean; |
|
metodo: string; |
|
tempoResposta: number; |
|
ultimaVerificacao: string; |
|
}> { |
|
const inicio = performance.now(); |
|
|
|
try { |
|
await this.fetchOfficialData(); |
|
const tempoResposta = Math.round(performance.now() - inicio); |
|
|
|
return { |
|
online: true, |
|
metodo: this.lastSuccessfulMethod, |
|
tempoResposta, |
|
ultimaVerificacao: new Date().toLocaleString('pt-BR') |
|
}; |
|
} catch (error) { |
|
const tempoResposta = Math.round(performance.now() - inicio); |
|
|
|
return { |
|
online: false, |
|
metodo: 'nenhum', |
|
tempoResposta, |
|
ultimaVerificacao: new Date().toLocaleString('pt-BR') |
|
}; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
formatarDadosOficiais(dadosAPI: any): LotomaniaResult { |
|
|
|
const numerosConcurso = dadosAPI.listaDezenas || dadosAPI.dezenas || []; |
|
const premiacoes = dadosAPI.listaRateioPremio || dadosAPI.premiacoes || []; |
|
const ganhadores = dadosAPI.listaMunicipioUFGanhadores || dadosAPI.ganhadores || []; |
|
|
|
return { |
|
concurso: dadosAPI.numero || dadosAPI.concurso || 0, |
|
data: dadosAPI.dataApuracao || dadosAPI.data || new Date().toLocaleDateString('pt-BR'), |
|
numeros: numerosConcurso.map((n: string | number) => |
|
typeof n === 'string' ? parseInt(n, 10) : n |
|
).filter((n: number) => !isNaN(n)) || [], |
|
acumulado: Boolean(dadosAPI.acumulado), |
|
valorArrecadado: Number(dadosAPI.valorArrecadado) || 0, |
|
valorAcumuladoProximoConcurso: Number(dadosAPI.valorAcumuladoProximoConcurso) || 0, |
|
valorEstimadoProximoConcurso: Number(dadosAPI.valorEstimadoProximoConcurso) || 0, |
|
numeroProximoConcurso: dadosAPI.numeroConcursoProximo || dadosAPI.numeroProximoConcurso || (dadosAPI.numero + 1), |
|
dataProximoConcurso: dadosAPI.dataProximoConcurso || dadosAPI.dataProximo || '', |
|
localSorteio: dadosAPI.localSorteio || dadosAPI.local || 'ESPAÇO DA SORTE', |
|
premiacoes: premiacoes.map((premio: any) => ({ |
|
faixa: Number(premio.faixa) || 0, |
|
descricao: String(premio.descricaoFaixa || premio.descricao || ''), |
|
acertos: this.extrairAcertos(String(premio.descricaoFaixa || premio.descricao || '')), |
|
ganhadores: Number(premio.numeroDeGanhadores || premio.ganhadores) || 0, |
|
valorPremio: Number(premio.valorPremio || premio.valor) || 0 |
|
})), |
|
ganhadores: ganhadores.map((ganhador: any) => ({ |
|
municipio: String(ganhador.municipio || ''), |
|
uf: String(ganhador.uf || ''), |
|
ganhadores: Number(ganhador.ganhadores || ganhador.quantidade) || 0, |
|
faixa: Number(ganhador.posicao || ganhador.faixa) || 0 |
|
})) |
|
}; |
|
} |
|
|
|
private extrairAcertos(descricao: string): number { |
|
const match = descricao.match(/(\d+)/); |
|
return match ? parseInt(match[1], 10) : 0; |
|
} |
|
} |
|
|
|
|
|
export const caixaAPIOfficial = CaixaAPIOfficial.getInstance(); |
|
|