import { all, placeholders } from "../db";
import { repoDb } from "../scoped-db";
import { pullBaseRepoIds } from "../pull-scope";
/** Most bytes one account's fork pull requests may hold bridged into other repos at once. */
export const MAX_OPEN_BRIDGED_BYTES = 1024 * 1024 * 1024;
export type BridgeCharge = { headOwnerId: string; baseRepoId: string; number: number };
/**
* The bytes still pinned by bridges of pull requests whose head repo `ownerId` owns. Those pull requests live
* in the parents of the owner's forks, so this asks each parent about the owner's forks of it.
*/
export async function openBridgedBytes(ownerId: string): Promise<number> {
const forks = await all<{ id: string; fork_of_id: string }>(
"SELECT id, fork_of_id FROM repos WHERE owner_id = ? AND fork_of_id IS NOT NULL",
ownerId,
);
const byParent = new Map<string, string[]>();
for (const fork of forks) byParent.set(fork.fork_of_id, [...(byParent.get(fork.fork_of_id) ?? []), fork.id]);
const totals = await Promise.all(
[...byParent].map(async ([parentId, forkIds]) => {
const row = await repoDb(parentId).first<{ total: number | null }>(
`SELECT SUM(bridged_bytes) AS total FROM pull_requests
WHERE head_repo_id IN (${placeholders(forkIds.length)}) AND bridged_bytes > 0`,
...forkIds,
);
return row?.total ?? 0;
}),
);
return totals.reduce((sum, total) => sum + total, 0);
}
/** Whether the head owner may start another relay; bridges reusing objects the target already has stay free. */
export async function bridgeQuotaAvailable(charge: BridgeCharge): Promise<boolean> {
return (await openBridgedBytes(charge.headOwnerId)) < MAX_OPEN_BRIDGED_BYTES;
}
export async function recordBridgedBytes(charge: BridgeCharge, bytes: number): Promise<void> {
if (bytes <= 0) return;