From a84a13c76d99f1e6f4505d43108a4111749e5035 Mon Sep 17 00:00:00 2001 From: AAGaming Date: Sat, 25 May 2024 19:14:54 -0400 Subject: Custom error handler and some misc fixes --- frontend/src/components/DeckyErrorBoundary.tsx | 201 +++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 frontend/src/components/DeckyErrorBoundary.tsx (limited to 'frontend/src/components/DeckyErrorBoundary.tsx') diff --git a/frontend/src/components/DeckyErrorBoundary.tsx b/frontend/src/components/DeckyErrorBoundary.tsx new file mode 100644 index 00000000..a851b2e1 --- /dev/null +++ b/frontend/src/components/DeckyErrorBoundary.tsx @@ -0,0 +1,201 @@ +import { sleep } from '@decky/ui'; +import { ErrorInfo, FunctionComponent, useReducer, useState } from 'react'; + +import { uninstallPlugin } from '../plugin'; +import { doRestart, doShutdown } from '../updater'; + +interface ReactErrorInfo { + error: Error; + info: ErrorInfo; +} + +interface DeckyErrorBoundaryProps { + error: ReactErrorInfo; + errorKey: string; + reset: () => void; +} + +declare global { + interface Window { + SystemNetworkStore?: any; + } +} + +const pluginErrorRegex = /\(http:\/\/localhost:1337\/plugins\/(.*)\//; +const pluginSourceMapErrorRegex = /\(decky:\/\/decky\/plugin\/(.*)\//; +const legacyPluginErrorRegex = /\(decky:\/\/decky\/legacy_plugin\/(.*)\/index.js/; + +function getLikelyErrorSource(error: ReactErrorInfo): [source: string, wasPlugin: boolean] { + const pluginMatch = error.error.stack?.match(pluginErrorRegex); + if (pluginMatch) { + return [decodeURIComponent(pluginMatch[1]), true]; + } + + const pluginMatchViaMap = error.error.stack?.match(pluginSourceMapErrorRegex); + if (pluginMatchViaMap) { + return [decodeURIComponent(pluginMatchViaMap[1]), true]; + } + + const legacyPluginMatch = error.error.stack?.match(legacyPluginErrorRegex); + if (legacyPluginMatch) { + return [decodeURIComponent(legacyPluginMatch[1]), true]; + } + + if (error.error.stack?.includes('http://localhost:1337/')) { + return ['the Decky frontend', false]; + } + return ['Steam', false]; +} + +export const startSSH = DeckyBackend.callable('utilities/start_ssh'); +export const starrCEFForwarding = DeckyBackend.callable('utilities/allow_remote_debugging'); + +function ipToString(ip: number) { + return [(ip >>> 24) & 255, (ip >>> 16) & 255, (ip >>> 8) & 255, (ip >>> 0) & 255].join('.'); +} + +// Intentionally not localized since we can't really trust React here +const DeckyErrorBoundary: FunctionComponent = ({ error, reset }) => { + const [actionLog, addLogLine] = useReducer((log: string, line: string) => (log += '\n' + line), ''); + const [actionsEnabled, setActionsEnabled] = useState(true); + const [debugAllowed, setDebugAllowed] = useState(true); + const [errorSource, wasCausedByPlugin] = getLikelyErrorSource(error); + + return ( +
+

+ ⚠️ An error occured rendering this content. +

+

This error likely occured in {getLikelyErrorSource(error)}.

+ {actionLog?.length > 0 && ( +
+          
+            Running actions...
+            {actionLog}
+          
+        
+ )} + {actionsEnabled && ( + <> +

Actions:

+

Use the touch screen.

+
+ + +
+
+ + +
+ {debugAllowed && ( +
+ +
+ )} + {wasCausedByPlugin && ( +
+ {'\n'} + +
+ )} + + )} + +
+        
+          {error.error.stack}
+          {'\n\n'}
+          Component Stack:
+          {error.info.componentStack}
+        
+      
+
+ ); +}; + +export default DeckyErrorBoundary; -- cgit v1.2.3