chore(pyroservers): introduce deferred modules
This commit is contained in:
@@ -287,11 +287,17 @@ const constructServerProperties = (properties: any): string => {
|
||||
};
|
||||
|
||||
const processImage = async (iconUrl: string | undefined) => {
|
||||
const image = ref<string | null>(null);
|
||||
const sharedImage = useState<string | undefined>(
|
||||
`server-icon-${internalServerRefrence.value.serverId}`,
|
||||
() => undefined,
|
||||
);
|
||||
|
||||
if (sharedImage.value) {
|
||||
return sharedImage.value;
|
||||
}
|
||||
|
||||
const image = ref<string | null>(null);
|
||||
|
||||
const auth = await PyroFetch<JWTAuth>(`servers/${internalServerRefrence.value.serverId}/fs`);
|
||||
try {
|
||||
const fileData = await PyroFetch(`/download?path=/server-icon-original.png`, {
|
||||
@@ -313,7 +319,7 @@ const processImage = async (iconUrl: string | undefined) => {
|
||||
const dataURL = canvas.toDataURL("image/png");
|
||||
internalServerRefrence.value.general.image = dataURL;
|
||||
image.value = dataURL;
|
||||
sharedImage.value = dataURL; // Store in useState
|
||||
sharedImage.value = dataURL;
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
@@ -380,6 +386,7 @@ const processImage = async (iconUrl: string | undefined) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return image.value;
|
||||
};
|
||||
|
||||
@@ -580,10 +587,14 @@ const reinstallContent = async (replace: string, projectId: string, versionId: s
|
||||
|
||||
const createBackup = async (backupName: string) => {
|
||||
try {
|
||||
const response = (await PyroFetch(`servers/${internalServerRefrence.value.serverId}/backups`, {
|
||||
method: "POST",
|
||||
body: { name: backupName },
|
||||
})) as { id: string };
|
||||
const response = await PyroFetch<{ id: string }>(
|
||||
`servers/${internalServerRefrence.value.serverId}/backups`,
|
||||
{
|
||||
method: "POST",
|
||||
body: { name: backupName },
|
||||
},
|
||||
);
|
||||
await internalServerRefrence.value.refresh(["backups"]);
|
||||
return response.id;
|
||||
} catch (error) {
|
||||
console.error("Error creating backup:", error);
|
||||
@@ -597,6 +608,7 @@ const renameBackup = async (backupId: string, newName: string) => {
|
||||
method: "POST",
|
||||
body: { name: newName },
|
||||
});
|
||||
await internalServerRefrence.value.refresh(["backups"]);
|
||||
} catch (error) {
|
||||
console.error("Error renaming backup:", error);
|
||||
throw error;
|
||||
@@ -608,6 +620,7 @@ const deleteBackup = async (backupId: string) => {
|
||||
await PyroFetch(`servers/${internalServerRefrence.value.serverId}/backups/${backupId}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
await internalServerRefrence.value.refresh(["backups"]);
|
||||
} catch (error) {
|
||||
console.error("Error deleting backup:", error);
|
||||
throw error;
|
||||
@@ -622,6 +635,7 @@ const restoreBackup = async (backupId: string) => {
|
||||
method: "POST",
|
||||
},
|
||||
);
|
||||
await internalServerRefrence.value.refresh(["backups"]);
|
||||
} catch (error) {
|
||||
console.error("Error restoring backup:", error);
|
||||
throw error;
|
||||
@@ -660,12 +674,10 @@ const getAutoBackup = async () => {
|
||||
|
||||
const lockBackup = async (backupId: string) => {
|
||||
try {
|
||||
return await PyroFetch(
|
||||
`servers/${internalServerRefrence.value.serverId}/backups/${backupId}/lock`,
|
||||
{
|
||||
method: "POST",
|
||||
},
|
||||
);
|
||||
await PyroFetch(`servers/${internalServerRefrence.value.serverId}/backups/${backupId}/lock`, {
|
||||
method: "POST",
|
||||
});
|
||||
await internalServerRefrence.value.refresh(["backups"]);
|
||||
} catch (error) {
|
||||
console.error("Error locking backup:", error);
|
||||
throw error;
|
||||
@@ -674,14 +686,12 @@ const lockBackup = async (backupId: string) => {
|
||||
|
||||
const unlockBackup = async (backupId: string) => {
|
||||
try {
|
||||
return await PyroFetch(
|
||||
`servers/${internalServerRefrence.value.serverId}/backups/${backupId}/unlock`,
|
||||
{
|
||||
method: "POST",
|
||||
},
|
||||
);
|
||||
await PyroFetch(`servers/${internalServerRefrence.value.serverId}/backups/${backupId}/unlock`, {
|
||||
method: "POST",
|
||||
});
|
||||
await internalServerRefrence.value.refresh(["backups"]);
|
||||
} catch (error) {
|
||||
console.error("Error locking backup:", error);
|
||||
console.error("Error unlocking backup:", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
@@ -970,10 +980,31 @@ const modules: any = {
|
||||
`https://api.modrinth.com/v2/project/${data.upstream.project_id}`,
|
||||
);
|
||||
data.project = res as Project;
|
||||
|
||||
if (data.project?.icon_url) {
|
||||
const sharedImage = useState<string | undefined>(
|
||||
`server-icon-${serverId}`,
|
||||
() => undefined,
|
||||
);
|
||||
if (!sharedImage.value) {
|
||||
data.image = (await processImage(data.project.icon_url)) ?? undefined;
|
||||
sharedImage.value = data.image;
|
||||
} else {
|
||||
data.image = sharedImage.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const sharedImage = useState<string | undefined>(
|
||||
`server-icon-${serverId}`,
|
||||
() => undefined,
|
||||
);
|
||||
|
||||
if (import.meta.client) {
|
||||
data.image = (await processImage(data.project?.icon_url)) ?? undefined;
|
||||
data.image =
|
||||
sharedImage.value ?? (await processImage(data.project?.icon_url)) ?? undefined;
|
||||
}
|
||||
|
||||
const motd = await getMotd();
|
||||
if (motd === "A Minecraft Server") {
|
||||
await setMotd(
|
||||
@@ -1417,6 +1448,7 @@ export type Server<T extends avaliableModules> = {
|
||||
preserveInstallState?: boolean;
|
||||
},
|
||||
) => Promise<void>;
|
||||
loadModules: (modulesToLoad: avaliableModules) => Promise<void>;
|
||||
setError: (error: Error) => void;
|
||||
error?: Error;
|
||||
serverId: string;
|
||||
@@ -1469,18 +1501,37 @@ export const usePyroServer = async (serverId: string, includedModules: avaliable
|
||||
|
||||
await Promise.allSettled(modulePromises);
|
||||
},
|
||||
loadModules: async (modulesToLoad: avaliableModules) => {
|
||||
const newModules = modulesToLoad.filter((module) => !server[module]);
|
||||
if (newModules.length === 0) return;
|
||||
|
||||
newModules.forEach((module) => {
|
||||
server[module] = modules[module];
|
||||
});
|
||||
|
||||
await server.refresh(newModules);
|
||||
},
|
||||
setError: (error: Error) => {
|
||||
server.error = error;
|
||||
},
|
||||
serverId,
|
||||
});
|
||||
|
||||
includedModules.forEach((module) => {
|
||||
const initialModules = includedModules.filter((module) => ["general", "ws"].includes(module));
|
||||
const deferredModules = includedModules.filter((module) => !["general", "ws"].includes(module));
|
||||
|
||||
initialModules.forEach((module) => {
|
||||
server[module] = modules[module];
|
||||
});
|
||||
|
||||
internalServerRefrence.value = server;
|
||||
await server.refresh();
|
||||
await server.refresh(initialModules);
|
||||
|
||||
if (deferredModules.length > 0) {
|
||||
nextTick(async () => {
|
||||
await server.loadModules(deferredModules);
|
||||
});
|
||||
}
|
||||
|
||||
return server as Server<typeof includedModules>;
|
||||
};
|
||||
|
||||
@@ -258,7 +258,8 @@
|
||||
<button
|
||||
v-if="
|
||||
result.installed ||
|
||||
server.content.data.find((x) => x.project_id === result.project_id) ||
|
||||
(server?.content?.data &&
|
||||
server.content.data.find((x) => x.project_id === result.project_id)) ||
|
||||
server.general?.project?.id === result.project_id
|
||||
"
|
||||
disabled
|
||||
@@ -376,7 +377,9 @@ async function updateServerContext() {
|
||||
if (!auth.value.user) {
|
||||
router.push("/auth/sign-in?redirect=" + encodeURIComponent(route.fullPath));
|
||||
} else if (route.query.sid !== null) {
|
||||
server.value = await usePyroServer(route.query.sid, ["general", "content"]);
|
||||
server.value = await usePyroServer(route.query.sid, ["general", "content"], {
|
||||
waitForModules: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,8 +498,8 @@ async function serverInstall(project) {
|
||||
) ?? versions[0];
|
||||
|
||||
if (projectType.value.id === "modpack") {
|
||||
await server.value.general?.reinstall(
|
||||
route.query.sid,
|
||||
await server.value.general.reinstall(
|
||||
server.value.serverId,
|
||||
false,
|
||||
project.project_id,
|
||||
version.id,
|
||||
@@ -504,7 +507,7 @@ async function serverInstall(project) {
|
||||
eraseDataOnInstall.value,
|
||||
);
|
||||
project.installed = true;
|
||||
navigateTo(`/servers/manage/${route.query.sid}/options/loader`);
|
||||
navigateTo(`/servers/manage/${server.value.serverId}/options/loader`);
|
||||
} else if (projectType.value.id === "mod") {
|
||||
await server.value.content.install("mod", version.project_id, version.id);
|
||||
await server.value.refresh(["content"]);
|
||||
|
||||
@@ -363,7 +363,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<NuxtPage
|
||||
:route="route"
|
||||
:is-connected="isConnected"
|
||||
@@ -425,15 +424,14 @@ const createdAt = ref(
|
||||
const route = useNativeRoute();
|
||||
const router = useRouter();
|
||||
const serverId = route.params.id as string;
|
||||
const server = await usePyroServer(serverId, [
|
||||
"general",
|
||||
"content",
|
||||
"backups",
|
||||
"network",
|
||||
"startup",
|
||||
"ws",
|
||||
"fs",
|
||||
]);
|
||||
|
||||
const server = await usePyroServer(serverId, ["general", "ws"]);
|
||||
|
||||
const loadModulesPromise = Promise.resolve().then(() =>
|
||||
server.loadModules(["content", "backups", "network", "startup", "fs"]),
|
||||
);
|
||||
|
||||
provide("modulesLoaded", loadModulesPromise);
|
||||
|
||||
watch(
|
||||
() => server.error,
|
||||
@@ -664,6 +662,26 @@ const newLoader = ref<string | null>(null);
|
||||
const newLoaderVersion = ref<string | null>(null);
|
||||
const newMCVersion = ref<string | null>(null);
|
||||
|
||||
const onReinstall = (potentialArgs: any) => {
|
||||
if (!serverData.value) return;
|
||||
|
||||
serverData.value.status = "installing";
|
||||
|
||||
if (potentialArgs?.loader) {
|
||||
newLoader.value = potentialArgs.loader;
|
||||
}
|
||||
if (potentialArgs?.lVersion) {
|
||||
newLoaderVersion.value = potentialArgs.lVersion;
|
||||
}
|
||||
if (potentialArgs?.mVersion) {
|
||||
newMCVersion.value = potentialArgs.mVersion;
|
||||
}
|
||||
|
||||
error.value = null;
|
||||
errorTitle.value = "Error";
|
||||
errorMessage.value = "An unexpected error occurred.";
|
||||
};
|
||||
|
||||
const handleInstallationResult = async (data: WSInstallationResultEvent) => {
|
||||
switch (data.result) {
|
||||
case "ok": {
|
||||
@@ -737,26 +755,6 @@ const handleInstallationResult = async (data: WSInstallationResultEvent) => {
|
||||
}
|
||||
};
|
||||
|
||||
const onReinstall = (potentialArgs: any) => {
|
||||
if (!serverData.value) return;
|
||||
|
||||
serverData.value.status = "installing";
|
||||
|
||||
if (potentialArgs?.loader) {
|
||||
newLoader.value = potentialArgs.loader;
|
||||
}
|
||||
if (potentialArgs?.lVersion) {
|
||||
newLoaderVersion.value = potentialArgs.lVersion;
|
||||
}
|
||||
if (potentialArgs?.mVersion) {
|
||||
newMCVersion.value = potentialArgs.mVersion;
|
||||
}
|
||||
|
||||
error.value = null;
|
||||
errorTitle.value = "Error";
|
||||
errorMessage.value = "An unexpected error occurred.";
|
||||
};
|
||||
|
||||
const updateStats = (currentStats: Stats["current"]) => {
|
||||
isConnected.value = true;
|
||||
stats.value = {
|
||||
|
||||
@@ -297,33 +297,37 @@ const showbackupSettingsModal = () => {
|
||||
backupSettingsModal.value?.show();
|
||||
};
|
||||
|
||||
const handleBackupCreated = (payload: { success: boolean; message: string }) => {
|
||||
const handleBackupCreated = async (payload: { success: boolean; message: string }) => {
|
||||
if (payload.success) {
|
||||
addNotification({ type: "success", text: payload.message });
|
||||
await props.server.refresh(["backups"]);
|
||||
} else {
|
||||
addNotification({ type: "error", text: payload.message });
|
||||
}
|
||||
};
|
||||
|
||||
const handleBackupRenamed = (payload: { success: boolean; message: string }) => {
|
||||
const handleBackupRenamed = async (payload: { success: boolean; message: string }) => {
|
||||
if (payload.success) {
|
||||
addNotification({ type: "success", text: payload.message });
|
||||
await props.server.refresh(["backups"]);
|
||||
} else {
|
||||
addNotification({ type: "error", text: payload.message });
|
||||
}
|
||||
};
|
||||
|
||||
const handleBackupRestored = (payload: { success: boolean; message: string }) => {
|
||||
const handleBackupRestored = async (payload: { success: boolean; message: string }) => {
|
||||
if (payload.success) {
|
||||
addNotification({ type: "success", text: payload.message });
|
||||
await props.server.refresh(["backups"]);
|
||||
} else {
|
||||
addNotification({ type: "error", text: payload.message });
|
||||
}
|
||||
};
|
||||
|
||||
const handleBackupDeleted = (payload: { success: boolean; message: string }) => {
|
||||
const handleBackupDeleted = async (payload: { success: boolean; message: string }) => {
|
||||
if (payload.success) {
|
||||
addNotification({ type: "success", text: payload.message });
|
||||
await props.server.refresh(["backups"]);
|
||||
} else {
|
||||
addNotification({ type: "error", text: payload.message });
|
||||
}
|
||||
@@ -387,8 +391,8 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
if (hasOngoingBackups) {
|
||||
refreshInterval.value = setInterval(() => {
|
||||
props.server.refresh(["backups"]);
|
||||
refreshInterval.value = setInterval(async () => {
|
||||
await props.server.refresh(["backups"]);
|
||||
}, 10000);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user