Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions i18n/locales/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,7 @@
"cleanupSessionsDescription": "Cleans up expired sessions to save space and ensure security.",
"cleanupSessionsName": "Clean up sessions."
},
"utilityTitle": "Utility tasks",
"viewTask": "View {arrow}",
"weeklyScheduledTitle": "Weekly scheduled tasks"
}
Expand Down
46 changes: 42 additions & 4 deletions pages/admin/task/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,44 @@
</div>
</li>
</ul>
<h2 class="text-sm font-medium text-zinc-400 mt-8">
{{ $t("tasks.admin.utilityTitle") }}
</h2>
<ul role="list" class="mt-4 grid grid-cols-1 lg:grid-cols-2 gap-6">
<li
v-for="task in other"
:key="task"
class="col-span-1 divide-y divide-gray-200 rounded-lg bg-zinc-800 border border-zinc-700 shadow-sm"
>
<div class="flex w-full items-center justify-between space-x-6 p-6">
<div class="flex-1">
<div class="flex items-center space-x-2">
<h3 class="text-sm font-medium text-zinc-100">
{{ scheduledTasks[task].name }}
</h3>
</div>
<p class="mt-1 text-sm text-zinc-400">
{{ scheduledTasks[task].description }}
</p>
<button
class="mt-3 rounded-md text-xs font-medium text-zinc-100 hover:text-zinc-300 focus:outline-none focus:ring-2 focus:ring-zinc-100 focus:ring-offset-2"
@click="() => startTask(task)"
>
<i18n-t
keypath="tasks.admin.execute"
tag="span"
scope="global"
class="inline-flex items-center gap-x-1"
>
<template #arrow>
<PlayIcon class="size-4" aria-hidden="true" />
</template>
</i18n-t>
</button>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
Expand All @@ -185,7 +223,7 @@ definePageMeta({

const { t } = useI18n();

const { runningTasks, historicalTasks, dailyTasks, weeklyTasks } =
const { runningTasks, historicalTasks, dailyTasks, weeklyTasks, other } =
await $dropFetch("/api/v1/admin/task");

const liveRunningTasks = ref(
Expand Down Expand Up @@ -219,9 +257,9 @@ const scheduledTasks: {
name: "",
description: "",
},
debug: {
name: "",
description: "",
"import:check-integrity": {
name: "Check Integrity",
description: "Re-imports all versions and updates their manifests.",
},
};

Expand Down
4 changes: 3 additions & 1 deletion server/api/v1/admin/task/index.get.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import taskHandler from "~/server/internal/tasks";
import type { TaskGroup } from "~/server/internal/tasks/group";

export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["task:read"]);
Expand Down Expand Up @@ -38,6 +39,7 @@ export default defineEventHandler(async (h3) => {
});
const dailyTasks = await taskHandler.dailyTasks();
const weeklyTasks = await taskHandler.weeklyTasks();
const other: TaskGroup[] = ["import:check-integrity"];

return { runningTasks, historicalTasks, dailyTasks, weeklyTasks };
return { runningTasks, historicalTasks, dailyTasks, weeklyTasks, other };
});
2 changes: 1 addition & 1 deletion server/internal/services/torrential/droplet-interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ class DropletInterfaceManager {
run: async (message) => {
const callbacks = this.callbacks.get(message.messageId);
if (!callbacks) {
logger.warn(
logger.debug(
`got a droplet message with old message id: ${message.type}, ${message.messageId}`,
);
return undefined;
Expand Down
4 changes: 2 additions & 2 deletions server/internal/tasks/group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ export const taskGroups = {
"import:version": {
concurrency: true,
},
debug: {
concurrency: true,
"import:check-integrity": {
concurrency: false,
},
} as const;

Expand Down
13 changes: 7 additions & 6 deletions server/internal/tasks/index.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import type { MinimumRequestObject } from "~/server/h3";
import type { GlobalACL } from "../acls";
import aclManager from "../acls";

import cleanupInvites from "./registry/invitations";
import cleanupSessions from "./registry/sessions";
import checkUpdate from "./registry/update";
import cleanupObjects from "./registry/objects";
import { taskGroups, type TaskGroup } from "./group";
import prisma from "../db/database";
import { ArkErrors, type } from "arktype";
import pino from "pino";
import { logger } from "~/server/internal/logging";
import { Writable } from "node:stream";

import cleanupInvites from "./registry/invitations";
import cleanupSessions from "./registry/sessions";
import checkUpdate from "./registry/update";
import cleanupObjects from "./registry/objects";
import checkIntegrity from "./registry/check-integrity";

type TaskActionLink = `${string}:${string}`;

// a task that has been run
Expand Down Expand Up @@ -65,7 +66,7 @@ class TaskHandler {
this.saveScheduledTask(cleanupSessions);
this.saveScheduledTask(checkUpdate);
this.saveScheduledTask(cleanupObjects);
//this.saveScheduledTask(debug);
this.saveScheduledTask(checkIntegrity);
}

/**
Expand Down
80 changes: 80 additions & 0 deletions server/internal/tasks/registry/check-integrity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import prisma from "~/server/internal/db/database";
import { defineDropTask, wrapTaskContext } from "..";
import { libraryManager } from "../../library";

export default defineDropTask({
buildId: () => `import:check-integrity:${new Date().toISOString()}`,
name: "Check version integrity",
acls: ["system:import:version:read"],
taskGroup: "import:check-integrity",
async run({ progress, logger, addAction }) {
const versions = await prisma.gameVersion.findMany({
where: {
versionPath: {
not: null,
},
},
select: {
versionId: true,
versionPath: true,
displayName: true,
game: {
select: {
libraryId: true,
libraryPath: true,
mName: true,
},
},
},
});

logger.info(`Checking version integrity for ${versions.length} versions`);

let i = 0;
const progressStep = 100 / versions.length;
for (const version of versions) {
const displayName = `${version.game.mName} ${version.displayName ?? version.versionPath}`;
logger.info(`Starting integrity check for ${displayName}`);

const library = await libraryManager.getLibrary(version.game.libraryId);
if (!library) {
logger.warn(`No library for ${displayName}`);
continue;
}

const min = i * progressStep;
const max = (i + 1) * progressStep;
const taskContext = wrapTaskContext(
{ progress, logger, addAction },
{ min, max, prefix: `re-check ${displayName}` },
);

const manifest = await library.generateDropletManifest(
version.game.libraryPath,
version.versionPath!,
taskContext.progress,
(value) => {
taskContext.logger.info(value);
},
);

// SAFETY: this is requested from the database
// eslint-disable-next-line drop/no-prisma-delete
await prisma.gameVersion.update({
where: {
versionId: version.versionId,
},
data: {
versionId: crypto.randomUUID(),
dropletManifest: manifest,
},
});

logger.info(`Finished integrity check for ${displayName}`);
i++;
}

logger.info("Done");
progress(100);
},
});
18 changes: 0 additions & 18 deletions server/internal/tasks/registry/debug.ts

This file was deleted.

Loading