Depot API & v4 (#298)
* feat: nginx + torrential basics & services system * fix: lint + i18n * fix: update torrential to remove openssl * feat: add torrential to Docker build * feat: move to self hosted runner * fix: move off self-hosted runner * fix: update nginx.conf * feat: torrential cache invalidation * fix: update torrential for cache invalidation * feat: integrity check task * fix: lint * feat: move to version ids * fix: client fixes and client-side checks * feat: new depot apis and version id fixes * feat: update torrential * feat: droplet bump and remove unsafe update functions * fix: lint * feat: v4 featureset: emulators, multi-launch commands * fix: lint * fix: mobile ui for game editor * feat: launch options * fix: lint * fix: remove axios, use $fetch * feat: metadata and task api improvements * feat: task actions * fix: slight styling issue * feat: fix style and lints * feat: totp backend routes * feat: oidc groups * fix: update drop-base * feat: creation of passkeys & totp * feat: totp signin * feat: webauthn mfa/signin * feat: launch selecting ui * fix: manually running tasks * feat: update add company game modal to use new SelectorGame * feat: executor selector * fix(docker): update rust to rust nightly for torrential build (#305) * feat: new version ui * feat: move package lookup to build time to allow for deno dev * fix: lint * feat: localisation cleanup * feat: apply localisation cleanup * feat: potential i18n refactor logic * feat: remove args from commands * fix: lint * fix: lockfile --------- Co-authored-by: Aden Lindsay <140392385+AdenMGB@users.noreply.github.com>
This commit is contained in:
@@ -14,15 +14,19 @@ import pino from "pino";
|
||||
import { logger } from "~/server/internal/logging";
|
||||
import { Writable } from "node:stream";
|
||||
|
||||
type TaskActionLink = `${string}:${string}`;
|
||||
|
||||
// a task that has been run
|
||||
type FinishedTask = {
|
||||
success: boolean;
|
||||
progress: number;
|
||||
key: string | undefined;
|
||||
log: string[];
|
||||
error: { title: string; description: string } | undefined;
|
||||
name: string;
|
||||
taskGroup: TaskGroup;
|
||||
acls: string[];
|
||||
actions: TaskActionLink[];
|
||||
|
||||
// ISO timestamp of when the task started
|
||||
startTime: string;
|
||||
@@ -53,7 +57,6 @@ class TaskHandler {
|
||||
"cleanup:invitations",
|
||||
"cleanup:sessions",
|
||||
"check:update",
|
||||
"debug",
|
||||
];
|
||||
private weeklyScheduledTasks: TaskGroup[] = ["cleanup:objects"];
|
||||
|
||||
@@ -74,8 +77,12 @@ class TaskHandler {
|
||||
this.taskCreators.set(task.taskGroup, task.build);
|
||||
}
|
||||
|
||||
async create(task: Task) {
|
||||
if (this.hasTask(task.id)) throw new Error("Task with ID already exists.");
|
||||
async create(iTask: Omit<Task, "id">) {
|
||||
const task: Task = { ...iTask, id: crypto.randomUUID() };
|
||||
if (this.hasTaskID(task.id))
|
||||
throw new Error("Task with ID already exists.");
|
||||
if (task.key && this.hasTaskKey(task.key))
|
||||
throw new Error("Task with key already exists");
|
||||
|
||||
let updateCollectTimeout: NodeJS.Timeout | undefined;
|
||||
let updateCollectResolves: Array<(value: unknown) => void> = [];
|
||||
@@ -115,6 +122,7 @@ class TaskHandler {
|
||||
error: taskEntry.error,
|
||||
log: taskEntry.log.slice(logOffset),
|
||||
reset,
|
||||
actions: taskEntry.actions,
|
||||
};
|
||||
logOffset = taskEntry.log.length;
|
||||
|
||||
@@ -189,6 +197,7 @@ class TaskHandler {
|
||||
|
||||
this.taskPool.set(task.id, {
|
||||
name: task.name,
|
||||
key: task.key,
|
||||
taskGroup: task.taskGroup,
|
||||
success: false,
|
||||
progress: 0,
|
||||
@@ -198,6 +207,7 @@ class TaskHandler {
|
||||
acls: task.acls,
|
||||
startTime: new Date().toISOString(),
|
||||
endTime: undefined,
|
||||
actions: task.initialActions ?? [],
|
||||
});
|
||||
|
||||
await updateAllClients(true);
|
||||
@@ -205,9 +215,13 @@ class TaskHandler {
|
||||
droplet.callAltThreadFunc(async () => {
|
||||
const taskEntry = this.taskPool.get(task.id);
|
||||
if (!taskEntry) throw new Error("No task entry");
|
||||
const addAction = (action: TaskActionLink) => {
|
||||
taskEntry.actions.push(action);
|
||||
updateAllClients();
|
||||
};
|
||||
|
||||
try {
|
||||
await task.run({ progress, logger: taskLogger });
|
||||
await task.run({ progress, logger: taskLogger, addAction });
|
||||
taskEntry.success = true;
|
||||
} catch (error: unknown) {
|
||||
taskEntry.success = false;
|
||||
@@ -239,6 +253,7 @@ class TaskHandler {
|
||||
log: taskEntry.log,
|
||||
|
||||
acls: taskEntry.acls,
|
||||
actions: taskEntry.actions,
|
||||
|
||||
...(taskEntry.error ? { error: taskEntry.error } : undefined),
|
||||
},
|
||||
@@ -246,6 +261,8 @@ class TaskHandler {
|
||||
|
||||
this.taskPool.delete(task.id);
|
||||
});
|
||||
|
||||
return task.id;
|
||||
}
|
||||
|
||||
async connect(
|
||||
@@ -290,6 +307,7 @@ class TaskHandler {
|
||||
| undefined,
|
||||
log: task.log,
|
||||
progress: task.progress,
|
||||
actions: task.actions as TaskActionLink[],
|
||||
};
|
||||
peer.send(JSON.stringify(catchupMessage));
|
||||
}
|
||||
@@ -336,10 +354,16 @@ class TaskHandler {
|
||||
.toArray();
|
||||
}
|
||||
|
||||
hasTask(id: string) {
|
||||
hasTaskID(id: string) {
|
||||
return this.taskPool.has(id);
|
||||
}
|
||||
|
||||
hasTaskKey(key: string) {
|
||||
return (
|
||||
this.taskPool.values().find((v) => v.key && v.key == key) != undefined
|
||||
);
|
||||
}
|
||||
|
||||
dailyTasks() {
|
||||
return this.dailyScheduledTasks;
|
||||
}
|
||||
@@ -355,8 +379,8 @@ class TaskHandler {
|
||||
return;
|
||||
}
|
||||
const task = taskConstructor();
|
||||
await this.create(task);
|
||||
return task.id;
|
||||
const id = await this.create(task);
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -415,6 +439,7 @@ class TaskHandler {
|
||||
export type TaskRunContext = {
|
||||
progress: (progress: number) => void;
|
||||
logger: typeof logger;
|
||||
addAction: (link: TaskActionLink) => void;
|
||||
};
|
||||
|
||||
export function wrapTaskContext(
|
||||
@@ -426,6 +451,7 @@ export function wrapTaskContext(
|
||||
});
|
||||
|
||||
return {
|
||||
...context,
|
||||
progress(progress) {
|
||||
if (progress > 100 || progress < 0) {
|
||||
logger.warn("[wrapTaskContext] progress must be between 0 and 100");
|
||||
@@ -444,10 +470,12 @@ export function wrapTaskContext(
|
||||
|
||||
export interface Task {
|
||||
id: string;
|
||||
key?: string;
|
||||
taskGroup: TaskGroup;
|
||||
name: string;
|
||||
run: (context: TaskRunContext) => Promise<void>;
|
||||
acls: GlobalACL[];
|
||||
initialActions?: TaskActionLink[];
|
||||
}
|
||||
|
||||
export type TaskMessage = {
|
||||
@@ -458,6 +486,7 @@ export type TaskMessage = {
|
||||
error: null | undefined | { title: string; description: string };
|
||||
log: string[];
|
||||
reset?: boolean;
|
||||
actions: TaskActionLink[];
|
||||
};
|
||||
|
||||
export type PeerImpl = {
|
||||
@@ -471,6 +500,7 @@ export interface BuildTask {
|
||||
name: string;
|
||||
run: (context: TaskRunContext) => Promise<void>;
|
||||
acls: GlobalACL[];
|
||||
initialActions?: TaskActionLink[];
|
||||
}
|
||||
|
||||
interface DropTask {
|
||||
@@ -519,6 +549,7 @@ export function defineDropTask(buildTask: BuildTask): DropTask {
|
||||
name: buildTask.name,
|
||||
run: buildTask.run,
|
||||
acls: buildTask.acls,
|
||||
initialActions: buildTask.initialActions ?? [],
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ type FieldReferenceMap = {
|
||||
};
|
||||
|
||||
export default defineDropTask({
|
||||
buildId: () => `cleanup:objects:${new Date().toISOString()}`,
|
||||
buildId: () => `cleanup:objects:${Date.now()}`,
|
||||
name: "Cleanup Objects",
|
||||
acls: ["system:maintenance:read"],
|
||||
taskGroup: "cleanup:objects",
|
||||
|
||||
Reference in New Issue
Block a user