continue refactor, this is looking good!

This commit is contained in:
fccview
2025-11-05 20:11:06 +00:00
parent 2ba9cdc622
commit e129bac619
8 changed files with 51 additions and 54 deletions

17
app/_consts/commands.ts Normal file
View File

@@ -0,0 +1,17 @@
export const WRITE_CRONTAB = (content: string, user: string) => `echo '${content}' | crontab -u ${user} -`;
export const READ_CRONTAB = (user: string) => `crontab -l -u ${user} 2>/dev/null || echo ""`;
export const READ_CRON_FILE = () => 'crontab -l 2>/dev/null || echo ""'
export const WRITE_CRON_FILE = (content: string) => `echo "${content}" | crontab -`;
export const WRITE_HOST_CRONTAB = (base64Content: string, user: string) => `echo '${base64Content}' | base64 -d | crontab -u ${user} -`;
export const ID_U = (username: string) => `id -u ${username}`;
export const ID_G = (username: string) => `id -g ${username}`;
export const MAKE_SCRIPT_EXECUTABLE = (scriptPath: string) => `chmod +x "${scriptPath}"`;
export const RUN_SCRIPT = (scriptPath: string) => `bash "${scriptPath}"`;

View File

@@ -273,13 +273,6 @@ export const runCronJob = async (
command = NSENTER_RUN_JOB(executionUser, escapedCommand);
} else {
command = job.command;
const appUser = process.env.USER || "unknown";
if (job.user !== appUser) {
console.warn(
`[Native Mode] Running job ${job.id} as current user (${appUser}) instead of target user (${job.user}).`
);
}
}
const { stdout, stderr } = await execAsync(command, {

View File

@@ -6,10 +6,11 @@ import { join } from "path";
import { existsSync } from "fs";
import { exec } from "child_process";
import { promisify } from "util";
import { normalizeLineEndings } from "@/app/_utils/scripts";
import { getHostScriptPath, getScriptPath, normalizeLineEndings } from "@/app/_utils/scripts";
import { SCRIPTS_DIR } from "@/app/_consts/file";
import { loadAllScripts, Script } from "@/app/_utils/scriptScanner";
import { isDocker } from "@/app/_server/actions/global";
import { MAKE_SCRIPT_EXECUTABLE, RUN_SCRIPT } from "@/app/_consts/commands";
const execAsync = promisify(exec);
@@ -51,24 +52,20 @@ const ensureHostScriptsDirectory = async () => {
};
const saveScriptFile = async (filename: string, content: string) => {
const docker = await isDocker();
const scriptsDir = docker ? "/app/scripts" : join(process.cwd(), SCRIPTS_DIR);
await ensureScriptsDirectory();
const scriptPath = join(scriptsDir, filename);
const scriptPath = getScriptPath(filename);
await writeFile(scriptPath, content, "utf8");
try {
await execAsync(`chmod +x "${scriptPath}"`);
await execAsync(MAKE_SCRIPT_EXECUTABLE(scriptPath));
} catch (error) {
console.error(`Failed to set execute permissions on ${scriptPath}:`, error);
}
};
const deleteScriptFile = async (filename: string) => {
const docker = await isDocker();
const scriptsDir = docker ? "/app/scripts" : join(process.cwd(), SCRIPTS_DIR);
const scriptPath = join(scriptsDir, filename);
const scriptPath = getScriptPath(filename);
if (existsSync(scriptPath)) {
await unlink(scriptPath);
}
@@ -238,10 +235,7 @@ export const cloneScript = async (
export const getScriptContent = async (filename: string): Promise<string> => {
try {
const docker = await isDocker();
const scriptPath = docker
? join("/app/scripts", filename)
: join(process.cwd(), "scripts", filename);
const scriptPath = getScriptPath(filename);
if (existsSync(scriptPath)) {
const content = await readFile(scriptPath, "utf8");
@@ -278,10 +272,7 @@ export const executeScript = async (
}> => {
try {
await ensureHostScriptsDirectory();
const docker = await isDocker();
const hostScriptPath = docker
? join("/app/scripts", filename)
: join(process.cwd(), "scripts", filename);
const hostScriptPath = getHostScriptPath(filename);
if (!existsSync(hostScriptPath)) {
return {
@@ -291,7 +282,7 @@ export const executeScript = async (
};
}
const { stdout, stderr } = await execAsync(`bash "${hostScriptPath}"`, {
const { stdout, stderr } = await execAsync(RUN_SCRIPT(hostScriptPath), {
timeout: 30000,
});

View File

@@ -4,6 +4,7 @@ import { exec } from "child_process";
import { promisify } from "util";
import { readHostCrontab, writeHostCrontab } from "@/app/_utils/system/hostCrontab";
import { isDocker } from "@/app/_server/actions/global";
import { READ_CRON_FILE, WRITE_CRON_FILE } from "@/app/_consts/commands";
const execAsync = promisify(exec);
@@ -32,7 +33,7 @@ export const readCronFiles = async (): Promise<string> => {
if (!docker) {
try {
const { stdout } = await execAsync('crontab -l 2>/dev/null || echo ""');
const { stdout } = await execAsync(READ_CRON_FILE());
return stdout;
} catch (error) {
console.error("Error reading crontab:", error);
@@ -48,7 +49,7 @@ export const writeCronFiles = async (content: string): Promise<boolean> => {
if (!docker) {
try {
await execAsync('echo "' + content + '" | crontab -');
await execAsync(WRITE_CRON_FILE(content));
return true;
} catch (error) {
console.error("Error writing crontab:", error);

View File

@@ -1,6 +1,6 @@
import { promises as fs } from "fs";
import path from "path";
import { isDocker } from "../_server/actions/global";
import { SCRIPTS_DIR } from "../_consts/file";
export interface Script {
id: string;
@@ -68,10 +68,7 @@ const scanScriptsDirectory = async (dirPath: string): Promise<Script[]> => {
}
export const loadAllScripts = async (): Promise<Script[]> => {
const docker = await isDocker();
const scriptsDir = docker
? "/app/scripts"
: path.join(process.cwd(), "scripts");
const scriptsDir = path.join(process.cwd(), SCRIPTS_DIR);
return await scanScriptsDirectory(scriptsDir);
}

View File

@@ -7,6 +7,7 @@ import {
import { parseJobsFromLines, deleteJobInLines, updateJobInLines, pauseJobInLines, resumeJobInLines } from "@/app/_utils/cron/line-manipulation";
import { cleanCrontabContent, readCronFiles, writeCronFiles } from "@/app/_utils/cron/files-manipulation";
import { isDocker } from "@/app/_server/actions/global";
import { READ_CRONTAB, WRITE_CRONTAB } from "@/app/_consts/commands";
const execAsync = promisify(exec);
@@ -20,24 +21,28 @@ export interface CronJob {
}
const readUserCrontab = async (user: string): Promise<string> => {
if (await isDocker()) {
const docker = await isDocker();
if (docker) {
const userCrontabs = await readAllHostCrontabs();
const targetUserCrontab = userCrontabs.find((uc) => uc.user === user);
return targetUserCrontab?.content || "";
} else {
const { stdout } = await execAsync(
`crontab -l -u ${user} 2>/dev/null || echo ""`
READ_CRONTAB(user)
);
return stdout;
}
};
const writeUserCrontab = async (user: string, content: string): Promise<boolean> => {
if (await isDocker()) {
const docker = await isDocker();
if (docker) {
return await writeHostCrontabForUser(user, content);
} else {
try {
await execAsync(`echo '${content}' | crontab -u ${user} -`);
await execAsync(WRITE_CRONTAB(content, user));
return true;
} catch (error) {
console.error(`Error writing crontab for user ${user}:`, error);
@@ -47,7 +52,9 @@ const writeUserCrontab = async (user: string, content: string): Promise<boolean>
};
const getAllUsers = async (): Promise<{ user: string; content: string }[]> => {
if (await isDocker()) {
const docker = await isDocker();
if (docker) {
return await readAllHostCrontabs();
} else {
const { getAllTargetUsers } = await import("@/app/_utils/system/hostCrontab");
@@ -56,9 +63,7 @@ const getAllUsers = async (): Promise<{ user: string; content: string }[]> => {
for (const user of users) {
try {
const { stdout } = await execAsync(
`crontab -l -u ${user} 2>/dev/null || echo ""`
);
const { stdout } = await execAsync(READ_CRONTAB(user));
results.push({ user, content: stdout });
} catch (error) {
console.error(`Error reading crontab for user ${user}:`, error);

View File

@@ -1,3 +1,4 @@
import { ID_G, ID_U, READ_CRONTAB, WRITE_HOST_CRONTAB } from "@/app/_consts/commands";
import { NSENTER_HOST_CRONTAB } from "@/app/_consts/nsenter";
import { exec } from "child_process";
import { promisify } from "util";
@@ -82,9 +83,7 @@ export const getAllTargetUsers = async (): Promise<string[]> => {
export const readHostCrontab = async (): Promise<string> => {
try {
const user = await getTargetUser();
return await execHostCrontab(
`crontab -l -u ${user} 2>/dev/null || echo ""`
);
return await execHostCrontab(READ_CRONTAB(user));
} catch (error) {
console.error("Error reading host crontab:", error);
return "";
@@ -100,9 +99,7 @@ export const readAllHostCrontabs = async (): Promise<
for (const user of users) {
try {
const content = await execHostCrontab(
`crontab -l -u ${user} 2>/dev/null || echo ""`
);
const content = await execHostCrontab(READ_CRONTAB(user));
results.push({ user, content });
} catch (error) {
console.warn(`Error reading crontab for user ${user}:`, error);
@@ -126,9 +123,7 @@ export const writeHostCrontab = async (content: string): Promise<boolean> => {
}
const base64Content = Buffer.from(finalContent).toString("base64");
await execHostCrontab(
`echo '${base64Content}' | base64 -d | crontab -u ${user} -`
);
await execHostCrontab(WRITE_HOST_CRONTAB(base64Content, user));
return true;
} catch (error) {
console.error("Error writing host crontab:", error);
@@ -147,9 +142,7 @@ export const writeHostCrontabForUser = async (
}
const base64Content = Buffer.from(finalContent).toString("base64");
await execHostCrontab(
`echo '${base64Content}' | base64 -d | crontab -u ${user} -`
);
await execHostCrontab(WRITE_HOST_CRONTAB(base64Content, user));
return true;
} catch (error) {
console.error(`Error writing host crontab for user ${user}:`, error);
@@ -159,8 +152,8 @@ export const writeHostCrontabForUser = async (
export async function getUserInfo(username: string): Promise<UserInfo | null> {
try {
const uidResult = await execHostCrontab(`id -u ${username}`);
const gidResult = await execHostCrontab(`id -g ${username}`);
const uidResult = await execHostCrontab(ID_U(username));
const gidResult = await execHostCrontab(ID_G(username));
const uid = parseInt(uidResult.trim());
const gid = parseInt(gidResult.trim());

View File

@@ -1,5 +1,5 @@
# @id: demo-script
# @title: Hi, this is a demo scripttttt
# @title: Hi, this is a demo script
# @description: This script logs a "hello world" to teach you how scripts work.
#!/bin/bash