192 lines · 7.7 KB
import { recordArtifactsCall } from "./artifacts-health";
import { env } from "cloudflare:workers";
import { basicAuthHeader, repoTokenSecret } from "./artifacts";
import { concatBytes, FLUSH_PKT, packetText, parseAllPackets, pktLine } from "./pktline";
import { isSha, ZERO_SHA } from "./store";
import type { RefInfo, RepoRefs, RepoRow } from "~/lib/types";

const REFS_CACHE_SECONDS = 300;
const HEADS_PREFIX = "refs/heads/";
const TAGS_PREFIX = "refs/tags/";
const PEELED_SUFFIX = "^{}";
const MAX_REFS = 5000;

type RefsRepo = Pick<RepoRow, "id" | "artifacts_name" | "artifacts_remote">;

function refsCacheKey(repoId: string): string {
  return `refs:${repoId}`;
}

export function parseAdvertisement(body: Uint8Array): RepoRefs {
  const branches: RefInfo[] = [];
  const tags = new Map<string, RefInfo>();
  let head: string | null = null;

  for (const packet of parseAllPackets(body)) {
    const line = packetText(packet);
    if (line === null || line.startsWith("#")) continue;
    const [refPart, capabilities] = line.split("\0");
    const [sha, name] = refPart.split(" ");
    if (capabilities) {
      const symref = capabilities.split(" ").find((cap) => cap.startsWith("symref=HEAD:"));
      if (symref) head = symref.slice("symref=HEAD:".length).replace(HEADS_PREFIX, "");
    }
    if (!sha || !name || sha === ZERO_SHA) continue;
    if (branches.length + tags.size >= MAX_REFS) break;
    if (name.startsWith(HEADS_PREFIX)) {
      branches.push({ name: name.slice(HEADS_PREFIX.length), sha });
    } else if (name.startsWith(TAGS_PREFIX)) {
      const isPeeled = name.endsWith(PEELED_SUFFIX);
      const tagName = name.slice(TAGS_PREFIX.length, isPeeled ? -PEELED_SUFFIX.length : undefined);