149 lines
4.4 KiB
JavaScript
149 lines
4.4 KiB
JavaScript
import { existsSync } from "node:fs";
|
|
import { createClient } from "@supabase/supabase-js";
|
|
import { prepareAssets } from "./assets.mjs";
|
|
|
|
if (existsSync(".env.local")) process.loadEnvFile(".env.local");
|
|
const id = process.argv[2];
|
|
if (
|
|
!id ||
|
|
!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id)
|
|
)
|
|
throw new Error(
|
|
"Usage: npm run reprocess -- <dataset UUID>. Stop the MineGeo worker first.",
|
|
);
|
|
if (!process.env.NEXT_PUBLIC_SUPABASE_URL || !process.env.SUPABASE_SECRET_KEY)
|
|
throw new Error("Configure Supabase in .env.local before reprocessing.");
|
|
const client = createClient(
|
|
process.env.NEXT_PUBLIC_SUPABASE_URL,
|
|
process.env.SUPABASE_SECRET_KEY,
|
|
{
|
|
auth: { persistSession: false, autoRefreshToken: false },
|
|
},
|
|
);
|
|
function check(result) {
|
|
if (result.error) throw new Error(result.error.message);
|
|
return result.data;
|
|
}
|
|
const dataset = check(
|
|
await client.from("datasets").select("*").eq("id", id).single(),
|
|
);
|
|
if (
|
|
dataset.revision_id ||
|
|
dataset.parent_dataset_id ||
|
|
!["draft", "review", "rejected", "failed"].includes(dataset.state)
|
|
)
|
|
throw new Error(
|
|
"Only an unpublished, inactive original capture can be reprocessed. Published revisions cannot be changed. Contributions cannot be overwritten; upload a new capture instead.",
|
|
);
|
|
const job = check(
|
|
await client.from("upload_jobs").select("*").eq("dataset_id", id).single(),
|
|
);
|
|
if (!["complete", "failed", "cancelled"].includes(job.state))
|
|
throw new Error(
|
|
"This job is already queued or running. Stop the worker and wait for it to finish before retrying.",
|
|
);
|
|
const input = check(
|
|
await client
|
|
.from("dataset_inputs")
|
|
.select("validated,manifest")
|
|
.eq("dataset_id", id)
|
|
.single(),
|
|
);
|
|
if (
|
|
(input.manifest.availableViewpoints ?? input.manifest.viewpoints).some(
|
|
(p) => p.assetRoot,
|
|
)
|
|
)
|
|
throw new Error(
|
|
"This draft contains accepted contributions. Upload a new capture instead of reprocessing mixed media.",
|
|
);
|
|
if (dataset.source === "plugin")
|
|
await prepareAssets(input.manifest.minecraftVersion);
|
|
|
|
// This maintenance command runs with the worker stopped. Compare-and-set
|
|
// guards reject intervening publication, ownership of a job, or another repair.
|
|
const changed = check(
|
|
await client
|
|
.from("datasets")
|
|
.update({
|
|
state: "processing",
|
|
rejection_reason: null,
|
|
map_path: null,
|
|
cover_path: null,
|
|
panorama_count: 0,
|
|
updated_at: new Date().toISOString(),
|
|
})
|
|
.eq("id", id)
|
|
.eq("state", dataset.state)
|
|
.is("revision_id", null)
|
|
.select("id"),
|
|
);
|
|
if (changed.length !== 1)
|
|
throw new Error(
|
|
"Dataset state changed; nothing was queued. Run the command again.",
|
|
);
|
|
try {
|
|
check(
|
|
await client
|
|
.from("dataset_inputs")
|
|
.update({ validated: false })
|
|
.eq("dataset_id", id),
|
|
);
|
|
const queued = check(
|
|
await client
|
|
.from("upload_jobs")
|
|
.update({
|
|
state: "queued",
|
|
attempts: 0,
|
|
progress: 0,
|
|
error: null,
|
|
lease_owner: null,
|
|
lease_until: null,
|
|
updated_at: new Date().toISOString(),
|
|
})
|
|
.eq("id", job.id)
|
|
.eq("state", job.state)
|
|
.eq("updated_at", job.updated_at)
|
|
.select("id"),
|
|
);
|
|
if (queued.length !== 1)
|
|
throw new Error(
|
|
"Job state changed while queuing; stop the worker before retrying.",
|
|
);
|
|
} catch (error) {
|
|
// A transport error can occur after an update committed. If the job is
|
|
// queued/running, leave its dataset processing; otherwise restore its draft.
|
|
const current = await client
|
|
.from("upload_jobs")
|
|
.select("state")
|
|
.eq("id", job.id)
|
|
.single();
|
|
if (!current.error && !["queued", "running"].includes(current.data.state)) {
|
|
check(
|
|
await client
|
|
.from("datasets")
|
|
.update({
|
|
state: dataset.state,
|
|
rejection_reason: dataset.rejection_reason,
|
|
map_path: dataset.map_path,
|
|
cover_path: dataset.cover_path,
|
|
panorama_count: dataset.panorama_count,
|
|
updated_at: new Date().toISOString(),
|
|
})
|
|
.eq("id", id)
|
|
.eq("state", "processing")
|
|
.is("revision_id", null),
|
|
);
|
|
check(
|
|
await client
|
|
.from("dataset_inputs")
|
|
.update({ validated: input.validated })
|
|
.eq("dataset_id", id),
|
|
);
|
|
}
|
|
throw error;
|
|
}
|
|
console.log(
|
|
`Queued dataset ${id} for a fresh render. Start MineGeo; no new export or upload is needed.`,
|
|
);
|