116 lines
4.3 KiB
TypeScript
116 lines
4.3 KiB
TypeScript
// ERPNext Proxy — Transparente, igual ao Plus proxy
|
|
// /erpnext-app/* → http://erpnext:8080/*
|
|
|
|
import { Express, Response } from "express";
|
|
import { createProxyMiddleware } from "http-proxy-middleware";
|
|
|
|
const ERPNEXT_HOST = process.env.ERPNEXT_CONTAINER_HOST || "erpnext";
|
|
const ERPNEXT_CONTAINER_PORT = parseInt(process.env.ERPNEXT_CONTAINER_PORT || "8080", 10);
|
|
const ERPNEXT_TIMEOUT = parseInt(process.env.ERPNEXT_TIMEOUT || "60000", 10);
|
|
|
|
export function setupErpNextProxy(app: Express): void {
|
|
// Só ativa se o container estiver configurado (DOCKER_MODE ou flag explícita)
|
|
const dockerMode = process.env.DOCKER_MODE === "true";
|
|
const forceProxy = process.env.ERPNEXT_PROXY_ENABLED === "true";
|
|
|
|
if (!dockerMode && !forceProxy) {
|
|
console.log("[ERPNext Proxy] Modo container desativado — proxy não configurado.");
|
|
console.log("[ERPNext Proxy] Use ERPNEXT_URL para apontar para instância externa.");
|
|
return;
|
|
}
|
|
|
|
const erpnextTarget = `http://${ERPNEXT_HOST}:${ERPNEXT_CONTAINER_PORT}`;
|
|
|
|
const erpnextProxy = createProxyMiddleware({
|
|
target: erpnextTarget,
|
|
changeOrigin: true,
|
|
timeout: ERPNEXT_TIMEOUT,
|
|
proxyTimeout: ERPNEXT_TIMEOUT,
|
|
pathRewrite: {
|
|
"^/erpnext-app": "",
|
|
},
|
|
on: {
|
|
error: (err, req, res) => {
|
|
console.error("[ERPNext Proxy] Error:", err.message);
|
|
if (res && typeof (res as Response).status === "function") {
|
|
(res as Response).status(502).json({
|
|
error: "ERPNext não disponível",
|
|
message: `Frappe não está rodando em ${erpnextTarget}`,
|
|
});
|
|
}
|
|
},
|
|
proxyReq: (proxyReq, req) => {
|
|
console.log(`[ERPNext Proxy] ${req.method} ${req.url} -> ${erpnextTarget}`);
|
|
const forwardedHost = req.headers["x-forwarded-host"];
|
|
const host = (typeof forwardedHost === "string" ? forwardedHost : req.headers.host) || "localhost";
|
|
const forwardedProto = req.headers["x-forwarded-proto"];
|
|
const proto = typeof forwardedProto === "string" ? forwardedProto : "https";
|
|
proxyReq.setHeader("X-Forwarded-Host", host);
|
|
proxyReq.setHeader("X-Forwarded-Proto", proto);
|
|
proxyReq.setHeader("X-Forwarded-Prefix", "/erpnext-app");
|
|
// Frappe usa este header para resolver URLs absolutas
|
|
proxyReq.setHeader("X-Site-Name", "erpnext.local");
|
|
},
|
|
proxyRes: (proxyRes) => {
|
|
const location = proxyRes.headers["location"];
|
|
if (location && typeof location === "string") {
|
|
let newLocation = location;
|
|
// Rewrite URLs absolutas do container → /erpnext-app
|
|
newLocation = newLocation.replace(
|
|
new RegExp(`http://${ERPNEXT_HOST}:${ERPNEXT_CONTAINER_PORT}`, "g"),
|
|
"/erpnext-app"
|
|
);
|
|
newLocation = newLocation.replace(/http:\/\/erpnext:8080/g, "/erpnext-app");
|
|
// Se é path relativo sem prefixo, adiciona /erpnext-app
|
|
if (newLocation.startsWith("/") && !newLocation.startsWith("/erpnext-app")) {
|
|
newLocation = "/erpnext-app" + newLocation;
|
|
}
|
|
proxyRes.headers["location"] = newLocation;
|
|
}
|
|
},
|
|
},
|
|
});
|
|
|
|
app.use("/erpnext-app", erpnextProxy);
|
|
|
|
// Status check do container ERPNext
|
|
app.get("/api/erpnext/container-status", async (_req, res) => {
|
|
try {
|
|
const controller = new AbortController();
|
|
const timeout = setTimeout(() => controller.abort(), 5000);
|
|
|
|
const response = await fetch(`${erpnextTarget}/api/method/frappe.ping`, {
|
|
signal: controller.signal,
|
|
});
|
|
clearTimeout(timeout);
|
|
|
|
if (response.ok) {
|
|
const data = await response.json() as any;
|
|
res.json({
|
|
status: "online",
|
|
host: ERPNEXT_HOST,
|
|
port: ERPNEXT_CONTAINER_PORT,
|
|
message: data.message,
|
|
mode: "container",
|
|
});
|
|
} else {
|
|
res.json({
|
|
status: "error",
|
|
host: ERPNEXT_HOST,
|
|
port: ERPNEXT_CONTAINER_PORT,
|
|
httpStatus: response.status,
|
|
});
|
|
}
|
|
} catch (err: any) {
|
|
res.json({
|
|
status: "offline",
|
|
host: ERPNEXT_HOST,
|
|
port: ERPNEXT_CONTAINER_PORT,
|
|
error: err.name === "AbortError" ? "timeout" : err.message,
|
|
});
|
|
}
|
|
});
|
|
|
|
console.log(`[ERPNext Proxy] Configurado: /erpnext-app -> ${erpnextTarget}`);
|
|
}
|