Filter out duplicates

This commit is contained in:
Owen
2025-09-15 21:50:21 -07:00
parent 426d8684bf
commit e97642a790

View File

@@ -105,117 +105,115 @@ export async function getTraefikConfig(
}; };
}; };
// Get resources with their targets and sites in a single optimized query // Get resources with their targets and sites in a single optimized query
// Start from sites on this exit node, then join to targets and resources // Start from sites on this exit node, then join to targets and resources
const resourcesWithTargetsAndSites = await db const resourcesWithTargetsAndSites = await db
.select({ .select({
// Resource fields // Resource fields
resourceId: resources.resourceId, resourceId: resources.resourceId,
fullDomain: resources.fullDomain, fullDomain: resources.fullDomain,
ssl: resources.ssl, ssl: resources.ssl,
http: resources.http, http: resources.http,
proxyPort: resources.proxyPort, proxyPort: resources.proxyPort,
protocol: resources.protocol, protocol: resources.protocol,
subdomain: resources.subdomain, subdomain: resources.subdomain,
domainId: resources.domainId, domainId: resources.domainId,
enabled: resources.enabled, enabled: resources.enabled,
stickySession: resources.stickySession, stickySession: resources.stickySession,
tlsServerName: resources.tlsServerName, tlsServerName: resources.tlsServerName,
setHostHeader: resources.setHostHeader, setHostHeader: resources.setHostHeader,
enableProxy: resources.enableProxy, enableProxy: resources.enableProxy,
headers: resources.headers, headers: resources.headers,
// Target fields // Target fields
targetId: targets.targetId, targetId: targets.targetId,
targetEnabled: targets.enabled, targetEnabled: targets.enabled,
ip: targets.ip, ip: targets.ip,
method: targets.method, method: targets.method,
port: targets.port, port: targets.port,
internalPort: targets.internalPort, internalPort: targets.internalPort,
path: targets.path, path: targets.path,
pathMatchType: targets.pathMatchType, pathMatchType: targets.pathMatchType,
// Site fields // Site fields
siteId: sites.siteId, siteId: sites.siteId,
siteType: sites.type, siteType: sites.type,
siteOnline: sites.online, siteOnline: sites.online,
subnet: sites.subnet, subnet: sites.subnet,
exitNodeId: sites.exitNodeId exitNodeId: sites.exitNodeId
}) })
.from(sites) .from(sites)
.innerJoin(targets, eq(targets.siteId, sites.siteId)) .innerJoin(targets, eq(targets.siteId, sites.siteId))
.innerJoin(resources, eq(resources.resourceId, targets.resourceId)) .innerJoin(resources, eq(resources.resourceId, targets.resourceId))
.where( .where(
and( and(
eq(targets.enabled, true), eq(targets.enabled, true),
eq(resources.enabled, true), eq(resources.enabled, true),
or( or(eq(sites.exitNodeId, exitNodeId), isNull(sites.exitNodeId)),
eq(sites.exitNodeId, exitNodeId), inArray(sites.type, siteTypes),
isNull(sites.exitNodeId) config.getRawConfig().traefik.allow_raw_resources
), ? isNotNull(resources.http) // ignore the http check if allow_raw_resources is true
inArray(sites.type, siteTypes), : eq(resources.http, true)
config.getRawConfig().traefik.allow_raw_resources )
? isNotNull(resources.http) // ignore the http check if allow_raw_resources is true );
: eq(resources.http, true)
)
);
// Group by resource and include targets with their unique site data // Group by resource and include targets with their unique site data
const resourcesMap = new Map(); const resourcesMap = new Map();
resourcesWithTargetsAndSites.forEach((row) => { resourcesWithTargetsAndSites.forEach((row) => {
const resourceId = row.resourceId; const resourceId = row.resourceId;
const targetPath = sanitizePath(row.path) || ""; // Handle null/undefined paths const targetPath = sanitizePath(row.path) || ""; // Handle null/undefined paths
const pathMatchType = row.pathMatchType || ""; const pathMatchType = row.pathMatchType || "";
// Create a unique key combining resourceId and path+pathMatchType // Create a unique key combining resourceId and path+pathMatchType
const pathKey = [targetPath, pathMatchType].filter(Boolean).join("-"); const pathKey = [targetPath, pathMatchType].filter(Boolean).join("-");
const mapKey = [resourceId, pathKey].filter(Boolean).join("-"); const mapKey = [resourceId, pathKey].filter(Boolean).join("-");
if (!resourcesMap.has(mapKey)) { if (!resourcesMap.has(mapKey)) {
resourcesMap.set(mapKey, { resourcesMap.set(mapKey, {
resourceId: row.resourceId,
fullDomain: row.fullDomain,
ssl: row.ssl,
http: row.http,
proxyPort: row.proxyPort,
protocol: row.protocol,
subdomain: row.subdomain,
domainId: row.domainId,
enabled: row.enabled,
stickySession: row.stickySession,
tlsServerName: row.tlsServerName,
setHostHeader: row.setHostHeader,
enableProxy: row.enableProxy,
targets: [],
headers: row.headers,
path: row.path, // the targets will all have the same path
pathMatchType: row.pathMatchType // the targets will all have the same pathMatchType
});
}
// Add target with its associated site data
resourcesMap.get(mapKey).targets.push({
resourceId: row.resourceId, resourceId: row.resourceId,
targetId: row.targetId, fullDomain: row.fullDomain,
ip: row.ip, ssl: row.ssl,
method: row.method, http: row.http,
port: row.port, proxyPort: row.proxyPort,
internalPort: row.internalPort, protocol: row.protocol,
enabled: row.targetEnabled, subdomain: row.subdomain,
site: { domainId: row.domainId,
siteId: row.siteId, enabled: row.enabled,
type: row.siteType, stickySession: row.stickySession,
subnet: row.subnet, tlsServerName: row.tlsServerName,
exitNodeId: row.exitNodeId, setHostHeader: row.setHostHeader,
online: row.siteOnline enableProxy: row.enableProxy,
} targets: [],
headers: row.headers,
path: row.path, // the targets will all have the same path
pathMatchType: row.pathMatchType // the targets will all have the same pathMatchType
}); });
}); }
// Add target with its associated site data
resourcesMap.get(mapKey).targets.push({
resourceId: row.resourceId,
targetId: row.targetId,
ip: row.ip,
method: row.method,
port: row.port,
internalPort: row.internalPort,
enabled: row.targetEnabled,
site: {
siteId: row.siteId,
type: row.siteType,
subnet: row.subnet,
exitNodeId: row.exitNodeId,
online: row.siteOnline
}
});
});
// convert the map to an object for printing // convert the map to an object for printing
logger.debug(`Resources: ${JSON.stringify(Object.fromEntries(resourcesMap), null, 2)}`); logger.debug(
`Resources: ${JSON.stringify(Object.fromEntries(resourcesMap), null, 2)}`
);
// make sure we have at least one resource // make sure we have at least one resource
if (resourcesMap.size === 0) { if (resourcesMap.size === 0) {
@@ -399,55 +397,64 @@ export async function getTraefikConfig(
targets as TargetWithSite[] targets as TargetWithSite[]
).some((target: TargetWithSite) => target.site.online); ).some((target: TargetWithSite) => target.site.online);
return (targets as TargetWithSite[]) return (
.filter((target: TargetWithSite) => { (targets as TargetWithSite[])
if (!target.enabled) { .filter((target: TargetWithSite) => {
return false; if (!target.enabled) {
}
// If any sites are online, exclude offline sites
if (anySitesOnline && !target.site.online) {
return false;
}
if (
target.site.type === "local" ||
target.site.type === "wireguard"
) {
if (
!target.ip ||
!target.port ||
!target.method
) {
return false; return false;
} }
} else if (target.site.type === "newt") {
if ( // If any sites are online, exclude offline sites
!target.internalPort || if (anySitesOnline && !target.site.online) {
!target.method ||
!target.site.subnet
) {
return false; return false;
} }
}
return true; if (
}) target.site.type === "local" ||
.map((target: TargetWithSite) => { target.site.type === "wireguard"
if ( ) {
target.site.type === "local" || if (
target.site.type === "wireguard" !target.ip ||
) { !target.port ||
return { !target.method
url: `${target.method}://${target.ip}:${target.port}` ) {
}; return false;
} else if (target.site.type === "newt") { }
const ip = } else if (target.site.type === "newt") {
target.site.subnet!.split("/")[0]; if (
return { !target.internalPort ||
url: `${target.method}://${ip}:${target.internalPort}` !target.method ||
}; !target.site.subnet
} ) {
}); return false;
}
}
return true;
})
.map((target: TargetWithSite) => {
if (
target.site.type === "local" ||
target.site.type === "wireguard"
) {
return {
url: `${target.method}://${target.ip}:${target.port}`
};
} else if (target.site.type === "newt") {
const ip =
target.site.subnet!.split("/")[0];
return {
url: `${target.method}://${ip}:${target.internalPort}`
};
}
})
// filter out duplicates
.filter(
(v, i, a) =>
a.findIndex(
(t) => t && v && t.url === v.url
) === i
)
);
})(), })(),
...(resource.stickySession ...(resource.stickySession
? { ? {