From e0cde2d6ff1187b2ee2346ec6aea67a3190573cd Mon Sep 17 00:00:00 2001 From: Prospector Date: Mon, 7 Jul 2025 17:37:43 -0700 Subject: [PATCH] Revert "fix: error handling improvements (#3797)" This reverts commit 706976439db46125f9a9a9ea177ac9074d4147a8. --- .../composables/servers/modrinth-servers.ts | 111 +++--- .../composables/servers/modules/general.ts | 30 +- .../src/pages/servers/manage/[id].vue | 330 ++++++++---------- .../components/base/ErrorInformationCard.vue | 120 ------- packages/ui/src/components/index.ts | 1 - .../servers/errors/modrinth-server-error.ts | 2 +- .../errors/modrinth-servers-fetch-error.ts | 2 +- 7 files changed, 198 insertions(+), 398 deletions(-) delete mode 100644 packages/ui/src/components/base/ErrorInformationCard.vue diff --git a/apps/frontend/src/composables/servers/modrinth-servers.ts b/apps/frontend/src/composables/servers/modrinth-servers.ts index e91bb8530..8c79cc62d 100644 --- a/apps/frontend/src/composables/servers/modrinth-servers.ts +++ b/apps/frontend/src/composables/servers/modrinth-servers.ts @@ -124,63 +124,58 @@ export class ModrinthServer { return dataURL; } } catch (error) { - if (error instanceof ModrinthServerError && error.statusCode === 404) { - if (iconUrl) { - try { - const response = await fetch(iconUrl); - if (!response.ok) throw new Error("Failed to fetch icon"); - const file = await response.blob(); - const originalFile = new File([file], "server-icon-original.png", { - type: "image/png", - }); + if (error instanceof ModrinthServerError && error.statusCode === 404 && iconUrl) { + // Handle external icon processing + try { + const response = await fetch(iconUrl); + if (!response.ok) throw new Error("Failed to fetch icon"); + const file = await response.blob(); + const originalFile = new File([file], "server-icon-original.png", { + type: "image/png", + }); - if (import.meta.client) { - const dataURL = await new Promise((resolve) => { - const canvas = document.createElement("canvas"); - const ctx = canvas.getContext("2d"); - const img = new Image(); - img.onload = () => { - canvas.width = 64; - canvas.height = 64; - ctx?.drawImage(img, 0, 0, 64, 64); - canvas.toBlob(async (blob) => { - if (blob) { - const scaledFile = new File([blob], "server-icon.png", { - type: "image/png", - }); - await useServersFetch(`/create?path=/server-icon.png&type=file`, { - method: "POST", - contentType: "application/octet-stream", - body: scaledFile, - override: auth, - }); - await useServersFetch(`/create?path=/server-icon-original.png&type=file`, { - method: "POST", - contentType: "application/octet-stream", - body: originalFile, - override: auth, - }); - } - }, "image/png"); - const dataURL = canvas.toDataURL("image/png"); - sharedImage.value = dataURL; - resolve(dataURL); - URL.revokeObjectURL(img.src); - }; - img.src = URL.createObjectURL(file); - }); - return dataURL; - } - } catch (externalError: any) { - console.debug("Could not process external icon:", externalError.message); + if (import.meta.client) { + const dataURL = await new Promise((resolve) => { + const canvas = document.createElement("canvas"); + const ctx = canvas.getContext("2d"); + const img = new Image(); + img.onload = () => { + canvas.width = 64; + canvas.height = 64; + ctx?.drawImage(img, 0, 0, 64, 64); + canvas.toBlob(async (blob) => { + if (blob) { + const scaledFile = new File([blob], "server-icon.png", { type: "image/png" }); + await useServersFetch(`/create?path=/server-icon.png&type=file`, { + method: "POST", + contentType: "application/octet-stream", + body: scaledFile, + override: auth, + }); + await useServersFetch(`/create?path=/server-icon-original.png&type=file`, { + method: "POST", + contentType: "application/octet-stream", + body: originalFile, + override: auth, + }); + } + }, "image/png"); + const dataURL = canvas.toDataURL("image/png"); + sharedImage.value = dataURL; + resolve(dataURL); + URL.revokeObjectURL(img.src); + }; + img.src = URL.createObjectURL(file); + }); + return dataURL; } + } catch (error) { + console.error("Failed to process external icon:", error); } - } else { - throw error; } } - } catch (error: any) { - console.debug("Icon processing failed:", error.message); + } catch (error) { + console.error("Failed to process server icon:", error); } sharedImage.value = undefined; @@ -244,18 +239,6 @@ export class ModrinthServer { break; } } catch (error) { - if (error instanceof ModrinthServerError) { - if (error.statusCode === 404 && ["fs", "content"].includes(module)) { - console.debug(`Optional ${module} resource not found:`, error.message); - continue; - } - - if (error.statusCode === 503) { - console.debug(`Temporary ${module} unavailable:`, error.message); - continue; - } - } - this.errors[module] = { error: error instanceof ModrinthServerError diff --git a/apps/frontend/src/composables/servers/modules/general.ts b/apps/frontend/src/composables/servers/modules/general.ts index b2f100658..9e8a4c4cd 100644 --- a/apps/frontend/src/composables/servers/modules/general.ts +++ b/apps/frontend/src/composables/servers/modules/general.ts @@ -194,25 +194,19 @@ export class GeneralModule extends ServerModule implements ServerGeneral { } async setMotd(motd: string): Promise { - try { - const props = (await this.server.fetchConfigFile("ServerProperties")) as any; - if (props) { - props.motd = motd; - const newProps = this.server.constructServerProperties(props); - const octetStream = new Blob([newProps], { type: "application/octet-stream" }); - const auth = await useServersFetch(`servers/${this.serverId}/fs`); + const props = (await this.server.fetchConfigFile("ServerProperties")) as any; + if (props) { + props.motd = motd; + const newProps = this.server.constructServerProperties(props); + const octetStream = new Blob([newProps], { type: "application/octet-stream" }); + const auth = await useServersFetch(`servers/${this.serverId}/fs`); - await useServersFetch(`/update?path=/server.properties`, { - method: "PUT", - contentType: "application/octet-stream", - body: octetStream, - override: auth, - }); - } - } catch { - console.error( - "[Modrinth Servers] [General] Failed to set MOTD due to lack of server properties file.", - ); + await useServersFetch(`/update?path=/server.properties`, { + method: "PUT", + contentType: "application/octet-stream", + body: octetStream, + override: auth, + }); } } } diff --git a/apps/frontend/src/pages/servers/manage/[id].vue b/apps/frontend/src/pages/servers/manage/[id].vue index 566cc1ed2..35fd28343 100644 --- a/apps/frontend/src/pages/servers/manage/[id].vue +++ b/apps/frontend/src/pages/servers/manage/[id].vue @@ -18,25 +18,48 @@ v-if="serverData?.status === 'suspended' && serverData.suspension_reason === 'upgrading'" class="flex min-h-[calc(100vh-4rem)] items-center justify-center text-contrast" > - +
+
+
+
+ +
+

Server upgrading

+
+

+ Your server's hardware is currently being upgraded and will be back online shortly! +

+
+
- +
+
+
+
+ +
+

Server suspended

+
+

+ {{ + serverData.suspension_reason === "cancelled" + ? "Your subscription has been cancelled." + : serverData.suspension_reason + ? `Your server has been suspended: ${serverData.suspension_reason}` + : "Your server has been suspended." + }} +
+ Contact Modrinth Support if you believe this is an error. +

+
+ + + +
- +
+
+
+
+ +
+

Server not found

+
+

+ You don't have permission to view this server or it no longer exists. If you believe this + is an error, please contact Modrinth Support. +

+
+ + + + + +
- - - +

+ Your server's node, where your Modrinth Server is physically hosted, is experiencing + issues. We are working with our datacenter to resolve the issue as quickly as possible. +

+

+ Your data is safe and will not be lost, and your server will be back online as soon as the + issue is resolved. +

+

+ For updates, please join the Modrinth Discord or contact Modrinth Support via the chat + bubble in the bottom right corner and we'll be happy to help. +

+ +
+ + +
+
+ + + + + + +
- - - +

+ Something went wrong, and we couldn't connect to your server. This is likely due to a + temporary network issue. You'll be reconnected automatically. +

+
+ + + + +
{ const stopUptimeUpdates = () => { if (uptimeIntervalId) { clearInterval(uptimeIntervalId); - pollingIntervalId = null; + intervalId = null; } }; @@ -992,7 +1055,7 @@ const notifyError = (title: string, text: string) => { }); }; -let pollingIntervalId: ReturnType | null = null; +let intervalId: ReturnType | null = null; const countdown = ref(15); const formattedTime = computed(() => { @@ -1036,142 +1099,23 @@ const backupInProgress = computed(() => { }); const stopPolling = () => { - if (pollingIntervalId) { - clearTimeout(pollingIntervalId); - pollingIntervalId = null; + if (intervalId) { + clearInterval(intervalId); + intervalId = null; } }; const startPolling = () => { - stopPolling(); - - let retryCount = 0; - const maxRetries = 10; - - const poll = async () => { - try { - await server.refresh(["general", "ws"]); - - if (!server.moduleErrors?.general?.error) { - stopPolling(); - connectWebSocket(); - return; - } - - retryCount++; - if (retryCount >= maxRetries) { - console.error("Max retries reached, stopping polling"); - stopPolling(); - return; - } - - // Exponential backoff: 3s, 6s, 12s, 24s, etc. - const delay = Math.min(3000 * Math.pow(2, retryCount - 1), 60000); - - pollingIntervalId = setTimeout(poll, delay); - } catch (error) { - console.error("Polling failed:", error); - retryCount++; - - if (retryCount < maxRetries) { - const delay = Math.min(3000 * Math.pow(2, retryCount - 1), 60000); - pollingIntervalId = setTimeout(poll, delay); - } + countdown.value = 15; + intervalId = setInterval(() => { + if (countdown.value <= 0) { + reloadNuxtApp(); + } else { + countdown.value--; } - }; - - poll(); + }, 1000); }; -const nodeUnavailableDetails = computed(() => [ - { - label: "Server ID", - value: server.serverId, - type: "inline" as const, - }, - { - label: "Node", - value: server.general?.datacenter ?? "Unknown! Please contact support!", - type: "inline" as const, - }, -]); - -const suspendedDescription = computed(() => { - if (serverData.value?.suspension_reason === "cancelled") { - return "Your subscription has been cancelled.\nContact Modrinth Support if you believe this is an error."; - } - if (serverData.value?.suspension_reason) { - return `Your server has been suspended: ${serverData.value.suspension_reason}\nContact Modrinth Support if you believe this is an error.`; - } - return "Your server has been suspended.\nContact Modrinth Support if you believe this is an error."; -}); - -const generalErrorDetails = computed(() => [ - { - label: "Server ID", - value: server.serverId, - type: "inline" as const, - }, - { - label: "Timestamp", - value: String(server.moduleErrors?.general?.timestamp), - type: "inline" as const, - }, - { - label: "Error Name", - value: server.moduleErrors?.general?.error.name, - type: "inline" as const, - }, - { - label: "Error Message", - value: server.moduleErrors?.general?.error.message, - type: "block" as const, - }, - ...(server.moduleErrors?.general?.error.originalError - ? [ - { - label: "Original Error", - value: String(server.moduleErrors.general.error.originalError), - type: "hidden" as const, - }, - ] - : []), - ...(server.moduleErrors?.general?.error.stack - ? [ - { - label: "Stack Trace", - value: server.moduleErrors.general.error.stack, - type: "hidden" as const, - }, - ] - : []), -]); - -const suspendedAction = computed(() => ({ - label: "Go to billing settings", - onClick: () => router.push("/settings/billing"), - color: "brand" as const, -})); - -const generalErrorAction = computed(() => ({ - label: "Go back to all servers", - onClick: () => router.push("/servers/manage"), - color: "brand" as const, -})); - -const nodeUnavailableAction = computed(() => ({ - label: "Join Modrinth Discord", - onClick: () => navigateTo("https://discord.modrinth.com", { external: true }), - color: "standard" as const, -})); - -const connectionLostAction = computed(() => ({ - label: "Reload", - onClick: () => reloadNuxtApp(), - color: "brand" as const, - disabled: formattedTime.value !== "00", -})); - const copyServerDebugInfo = () => { const debugInfo = `Server ID: ${serverData.value?.server_id}\nError: ${errorMessage.value}\nKind: ${serverData.value?.upstream?.kind}\nProject ID: ${serverData.value?.upstream?.project_id}\nVersion ID: ${serverData.value?.upstream?.version_id}\nLog: ${errorLog.value}`; navigator.clipboard.writeText(debugInfo); diff --git a/packages/ui/src/components/base/ErrorInformationCard.vue b/packages/ui/src/components/base/ErrorInformationCard.vue deleted file mode 100644 index 9edfc0263..000000000 --- a/packages/ui/src/components/base/ErrorInformationCard.vue +++ /dev/null @@ -1,120 +0,0 @@ - - - diff --git a/packages/ui/src/components/index.ts b/packages/ui/src/components/index.ts index 3057f43de..9b41b4f5c 100644 --- a/packages/ui/src/components/index.ts +++ b/packages/ui/src/components/index.ts @@ -16,7 +16,6 @@ export { default as DoubleIcon } from './base/DoubleIcon.vue' export { default as DropArea } from './base/DropArea.vue' export { default as DropdownSelect } from './base/DropdownSelect.vue' export { default as EnvironmentIndicator } from './base/EnvironmentIndicator.vue' -export { default as ErrorInformationCard } from './base/ErrorInformationCard.vue' export { default as FileInput } from './base/FileInput.vue' export { default as FilterBar } from './base/FilterBar.vue' export type { FilterBarOption } from './base/FilterBar.vue' diff --git a/packages/utils/servers/errors/modrinth-server-error.ts b/packages/utils/servers/errors/modrinth-server-error.ts index c0a548a77..ece8825c8 100644 --- a/packages/utils/servers/errors/modrinth-server-error.ts +++ b/packages/utils/servers/errors/modrinth-server-error.ts @@ -54,6 +54,6 @@ export class ModrinthServerError extends Error { } super(errorMessage) - this.name = 'ModrinthServersFetchError' + this.name = 'PyroServersFetchError' } } diff --git a/packages/utils/servers/errors/modrinth-servers-fetch-error.ts b/packages/utils/servers/errors/modrinth-servers-fetch-error.ts index a2df7baa3..ce01e737f 100644 --- a/packages/utils/servers/errors/modrinth-servers-fetch-error.ts +++ b/packages/utils/servers/errors/modrinth-servers-fetch-error.ts @@ -5,6 +5,6 @@ export class ModrinthServersFetchError extends Error { public originalError?: Error, ) { super(message) - this.name = 'ModrinthFetchError' + this.name = 'PyroFetchError' } }