diff --git a/src/sources/gitea.ts b/src/sources/gitea.ts index e69de29..d08824e 100644 --- a/src/sources/gitea.ts +++ b/src/sources/gitea.ts @@ -0,0 +1,119 @@ +import { Readable } from 'node:stream'; +import { log } from '../logger'; + +const GITEA_TOKEN = process.env.GITEA_TOKEN as string || ""; +const GITEA_SERVER = process.env.GITEA_SERVER as string || ""; +const GITEA_OWNER = process.env.GITEA_OWNER as string || ""; +const GITEA_REPO = process.env.GITEA_REPO as string || ""; +const GITEA_PKG_URL = `https://${GITEA_SERVER}/${GITEA_OWNER}/${GITEA_REPO}` + +const REQUIRED_ENV_VARS = [ + "GITEA_SERVER", + "GITEA_OWNER", + "GITEA_REPO", +] as const; + +let missing: boolean = false; +for (const key of REQUIRED_ENV_VARS) { + if (!process.env[key]) { + log('ERROR', '`Missing required environment variable: ${key}'); + missing = true; + } else { + log('DEBUG', `Environment Variable: ${key} = ${process.env[key]}`); + } +} + +if (!GITEA_TOKEN) { + log('INFO', 'Connecting to Gitea server without authentication'); +} else { + log('INFO', "Connecting to Gitea with token authentication"); +} + +if (missing) { + log('ERROR', "Exit code 42"); + process.exit(42); +} + +interface GiteaPackageAsset { + name: string; + id: string; +} +export interface GiteaPackageResponse { + id: number; + name: string; + draft: boolean; + prerelease: boolean; + assets: GiteaPackageAsset[]; +} + +export async function getLatestPackageName() :Promise { + const get = await sendRequest(`${GITEA_PKG_URL}/releases/latest`); + + if (get.name) { + return get + } else { + log("ERROR", "Invalid Resposne from Gitea Server"); + log("ERROR", "Exit code 18"); + process.exit(18); + } +} + +export async function getPackageAttachment(release_id: number, attachment_id: number) :Promise { + return getRequestStream(`${GITEA_PKG_URL}/releases/${release_id}/assets/${attachment_id}`); +} + +async function getRequestStream(url: string) :Promise { + const options: RequestInit = { + method: "GET", + headers: { + 'Authorization': GITEA_TOKEN ? `token ${GITEA_TOKEN}` : "", + 'Accept': 'application/x-ndjson' + } + }; + + try { + const res = await fetch(url, options); + if (!res.ok) { + log('ERROR', `Stream request failed: ${res.status}`, { url }); + throw new Error(`HTTP Error: ${res.status}`); + } + + if (!res.body) { + throw new Error("Response body is empty"); + } + + return Readable.fromWeb(res.body as any); + } catch (err) { + log('ERROR', `Failed to initialise stream from ${url}`, err); + throw err; + } +} + +async function sendRequest(url: string) :Promise { + let options = { + method: "GET", + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': "", + } + } + if (GITEA_TOKEN) { + options.headers.Authorization = `token ${GITEA_TOKEN}`; + } + try { + const res = await fetch(url, options); + if (!res.ok) { + log('ERROR', `Gitea request failed: ${res.status}, ${res.statusText}`); + throw new Error(`HTTP Error: ${res.status}`); + } + + const data = await res.json(); + log('DEBUG', `Successful request to ${url}`); + return data as T; + } catch (err) { + log('ERROR', `Network or Parsing error for ${url}`, err); + log('ERROR', "Exit code 12"); + process.exit(12) + } +} \ No newline at end of file