pangolin/server/lib/blueprints/clientResources.ts
2025-09-14 15:57:41 -07:00

117 lines
3.6 KiB
TypeScript

import {
SiteResource,
siteResources,
Transaction,
} from "@server/db";
import { sites } from "@server/db";
import { eq, and } from "drizzle-orm";
import {
Config,
} from "./types";
import logger from "@server/logger";
export type ClientResourcesResults = {
resource: SiteResource;
}[];
export async function updateClientResources(
orgId: string,
config: Config,
trx: Transaction,
siteId?: number
): Promise<ClientResourcesResults> {
const results: ClientResourcesResults = [];
for (const [resourceNiceId, resourceData] of Object.entries(
config["client-resources"]
)) {
const [existingResource] = await trx
.select()
.from(siteResources)
.where(
and(
eq(siteResources.orgId, orgId),
eq(siteResources.niceId, resourceNiceId)
)
)
.limit(1);
const resourceSiteId = resourceData.site;
let site;
if (resourceSiteId) {
// Look up site by niceId
[site] = await trx
.select({ siteId: sites.siteId })
.from(sites)
.where(
and(
eq(sites.niceId, resourceSiteId),
eq(sites.orgId, orgId)
)
)
.limit(1);
} else if (siteId) {
// Use the provided siteId directly, but verify it belongs to the org
[site] = await trx
.select({ siteId: sites.siteId })
.from(sites)
.where(and(eq(sites.siteId, siteId), eq(sites.orgId, orgId)))
.limit(1);
} else {
throw new Error(`Target site is required`);
}
if (!site) {
throw new Error(
`Site not found: ${resourceSiteId} in org ${orgId}`
);
}
if (existingResource) {
// Update existing resource
const [updatedResource] = await trx
.update(siteResources)
.set({
name: resourceData.name || resourceNiceId,
siteId: site.siteId,
proxyPort: resourceData["proxy-port"]!,
destinationIp: resourceData.hostname,
destinationPort: resourceData["internal-port"],
protocol: resourceData.protocol
})
.where(
eq(
siteResources.siteResourceId,
existingResource.siteResourceId
)
)
.returning();
results.push({ resource: updatedResource });
} else {
// Create new resource
const [newResource] = await trx
.insert(siteResources)
.values({
orgId: orgId,
siteId: site.siteId,
niceId: resourceNiceId,
name: resourceData.name || resourceNiceId,
proxyPort: resourceData["proxy-port"]!,
destinationIp: resourceData.hostname,
destinationPort: resourceData["internal-port"],
protocol: resourceData.protocol
})
.returning();
logger.info(
`Created new client resource ${newResource.name} (${newResource.siteResourceId}) for org ${orgId}`
);
results.push({ resource: newResource });
}
}
return results;
}