viabilidade/app.js

141 lines
5.1 KiB
JavaScript
Raw Normal View History

const dotenv = require("dotenv");
dotenv.config();
const express = require("express");
const path = require("path");
const cors = require("cors");
const { fetchJson } = require("./services/jsonService");
const { getMinDistance } = require("./services/distanceService");
const { geocodeWithGoogle } = require("./services/geocodeService");
const { insertConsultaData } = require("./models/databaseModel");
function createApp() {
const app = express();
app.use(cors());
app.use(express.static(path.join(__dirname, "public")));
app.use(express.json());
// manual CEP+Numero query: resolves ViaCEP -> Nominatim -> Geogrid
app.get("/consulta-cep", async (req, res) => {
const { cep: rawCep, numero: rawNumero } = req.query;
if (!rawCep) return res.status(400).json({ error: "cep é obrigatório" });
const cep = String(rawCep).trim().replace(/\D/g, "");
if (cep.length !== 8) return res.status(400).json({ error: "cep inválido, verifique se foram digitados apenas números" });
const numero = rawNumero ? String(rawNumero).trim() : "";
try {
const viaCepUrl = 'https://api.cep.rest/';
let cepRestData = await fetch(viaCepUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ cep }) })
.then(response => response.json());
// ViaCEP com retry e backoff (corrige shadowing e trata exceções)
const maxAttempts = 5;
let attempt = 0;
let retryDelayMs = 1000; // delay inicial
if (!cepRestData || cepRestData.erro) {
while (attempt < maxAttempts) {
try {
cepRestData = await fetch(viaCepUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ cep })
}).then(response => response.json());
if (cepRestData && !cepRestData.erro) break;
console.info(`[INFO] ViaCEP retornou erro ou vazio na tentativa ${attempt + 1} para CEP ${cep}`);
} catch (e) {
console.warn(`[WARN] Erro na chamada ViaCEP (tentativa ${attempt + 1}) para ${cep}: ${e && e.message ? e.message : e}`);
}
attempt++;
console.info(`[INFO] Aguardando ${retryDelayMs}ms antes da próxima tentativa ViaCEP (${attempt}/${maxAttempts})`);
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
retryDelayMs *= 2;
}
}
if (!cepRestData || cepRestData.erro) {
console.error(`[ERROR] ViaCEP falhou após ${maxAttempts} tentativas para CEP ${cep}`);
return res.status(404).json({ error: "CEP não encontrado" });
}
const logradouro = cepRestData.data.logradouro || "";
const bairro = cepRestData.data.bairro || "";
const cidade = cepRestData.data.localidade || "";
const uf = cepRestData.data.uf || "";
const endereco = `${logradouro}, ${numero}, ${bairro}, ${cidade} - ${uf}`
.replace(/, ,/g, ",")
.replace(/^,\s*/, "");
if (!process.env.GOOGLE_API_KEY)
return res
.status(500)
.json({ error: "GOOGLE_API_KEY não definida no servidor" });
const geo = await geocodeWithGoogle(endereco || `${cidade} ${uf} ${cep}`);
if (!geo)
return res
.status(404)
.json({ error: "geocode não encontrado (Google)" });
const lat = Number(geo.lat);
const lon = Number(geo.lon);
const result = await getMinDistance(lat, lon);
// determinar valores de retorno padrão
let distancia = null;
let dedicado = "Não viável";
let naoDedicado = "Não viável";
if (result && result.dist !== undefined && result.dist !== null) {
distancia = result.dist;
// preciso criar 2 campos: Link Dedicado e Link Não Dedicado em que o dedicado é viável até 1000m e o não dedicado até 500m
if (distancia <= 500) {
dedicado = "Viável";
naoDedicado = "Viável";
} else if (distancia <= 1000) {
dedicado = "Viável";
naoDedicado = "Não viável";
} else {
dedicado = "Não viável";
naoDedicado = "Não viável";
}
} else {
dedicado = "Não viável";
naoDedicado = "Não viável";
}
const response = {
endereco,
latitude: lat,
longitude: lon,
distancia,
dedicado,
naoDedicado,
};
// Inserção no banco: usar fire-and-forget para não atrasar a resposta ao usuário.
// Se preferir garantir que a gravação ocorreu antes de responder, troque a chamada abaixo por:
// await insertConsultaData(cep, uf, cidade, bairro, logradouro);
insertConsultaData(cep, uf, cidade, bairro, logradouro, dedicado, naoDedicado)
.then(() => console.info(`[INFO] Consulta salva para CEP ${cep}`))
.catch((err) => console.error(`[ERROR] Falha ao salvar consulta para CEP ${cep}:`, err));
return res.json(response);
} catch (err) {
console.error(err);
return res.status(500).json({ error: "erro na consulta" });
}
});
return app;
}
module.exports = createApp;