diff --git a/app/actions/settings.js b/app/actions/settings.js index 271e15db1..1c0623a6d 100644 --- a/app/actions/settings.js +++ b/app/actions/settings.js @@ -13,7 +13,7 @@ export const SELECT_FILE = 'SELECT_FILE'; export const ISO_VALIDATION_START = 'ISO_VALIDATION_START'; export const ISO_VALIDATION_COMPLETE = 'ISO_VALIDATION_COMPLETE'; export const SET_RESET_CONFIRM = 'SET_RESET_CONFIRM'; -export const RESETTING_DOLPHIN = 'RESETTING_DOLPHIN' +export const RESETTING_DOLPHIN = 'RESETTING_DOLPHIN'; async function wait(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); @@ -67,7 +67,7 @@ export function browseFile(field) { // Maybe this should be done as some kind of callback or something... but this works if (field === "isoPath") { validateISO()(dispatch, getState); - getState().dolphinManager.setGamePath(filePath) + getState().dolphinManager.setGamePath(filePath); } }; } @@ -102,7 +102,7 @@ export function validateISO() { } catch (err) { // Do nothing } - + if (!fileStats) { dispatch({ type: ISO_VALIDATION_COMPLETE, @@ -120,7 +120,7 @@ export function validateISO() { }); return; } - + const hash = crypto.createHash('sha1'); const input = fs.createReadStream(isoPath); @@ -151,12 +151,12 @@ export function validateISO() { if (data) { hash.update(data); return; - } + } // Reading complete, check hash const resultHash = hash.digest('hex'); const isValidISO = _.get(ISOHashes, resultHash) || "unknown"; - + isoStateLocalCache[cacheKey] = isValidISO; dispatch({ @@ -190,17 +190,17 @@ export function resetDolphin() { await wait(10); try { const dolphinManager = getState().settings.dolphinManager; - dolphinManager.resetDolphin(); + await dolphinManager.resetDolphin(); const meleeFile = electronSettings.get('settings.isoPath'); dolphinManager.setGamePath(meleeFile); - } catch(err) { + } catch (err) { log.info("Dolphin could not be reset"); log.warn(err.message); const errorAction = displayError( 'settings-global', `Dolphin could not be reset. ${err.message}`, ); - + dispatch(errorAction); } dispatch({ diff --git a/app/domain/DolphinManager.js b/app/domain/DolphinManager.js index 4678a333a..93a9dc32f 100644 --- a/app/domain/DolphinManager.js +++ b/app/domain/DolphinManager.js @@ -10,6 +10,7 @@ import ini from 'ini'; import electronSettings from 'electron-settings'; import { getDolphinPath } from '../utils/settings'; +import { sudoRemovePath } from '../utils/sudoExec'; const { app } = require('electron').remote; @@ -53,16 +54,38 @@ export default class DolphinManager { await this.runDolphin(false); } - resetDolphin() { + async resetDolphin() { const appPath = app.getAppPath(); const originalDolphinPath = path.join(appPath, "../app.asar.unpacked/app/dolphin"); log.info("Resetting dolphin"); const userDataPath = app.getPath("userData"); const targetPath = path.join(userDataPath, 'dolphin'); log.info("Overwriting dolphin"); - fs.removeSync(targetPath); - fs.copySync(originalDolphinPath, targetPath); - log.info("Dolphin was reset"); + + let isCopySuccess = false; + try { + fs.removeSync(targetPath); + fs.copySync(originalDolphinPath, targetPath); + log.info("Dolphin was reset"); + isCopySuccess = true; + } catch (err) { + log.error("Failed to reset Dolphin, will try again with elevated permissions"); + } + + if (!isCopySuccess) { + try { + // TODO: This doesn't actually work, the UAC prompt never shows up. Might need to use + // TODO: ipc to trigger it in the main process? But I'm too lazy right now + await sudoRemovePath(targetPath); + fs.copySync(originalDolphinPath, targetPath); + log.info("Dolphin was reset"); + isCopySuccess = true; + } catch (err) { + log.error("Failed to reset Dolphin, will try again with elevated permissions"); + log.error(err); + throw new Error("Failed to reset Dolphin. You may need to reinstall the desktop app."); + } + } } setGamePath(filePath) { @@ -93,7 +116,7 @@ export default class DolphinManager { const newINI = ini.encode(dolphinINI); fs.writeFileSync(iniPath, newINI); } catch (err) { - log.warn(`Failed to update the dolphin paths\n${err}`) + log.warn(`Failed to update the dolphin paths\n${err}`); throw err; } } diff --git a/app/main.dev.js b/app/main.dev.js index fb848c41e..c9d51b492 100644 --- a/app/main.dev.js +++ b/app/main.dev.js @@ -22,7 +22,7 @@ import fs from 'fs-extra'; import ini from 'ini'; import semver from 'semver'; import MenuBuilder from './menu'; -import {sudoExecAsyncNonWindows, sudoExecAsyncWindows} from './utils/sudoExec'; +import { sudoRemovePath } from './utils/sudoExec'; // Set up AppUpdater log.transports.file.level = 'info'; @@ -36,10 +36,6 @@ const appDataPath = app.getPath("appData"); const isProd = process.env.NODE_ENV === 'production'; const isDev = process.env.NODE_ENV === "development"; -const sudoOptions = { - name: "Slippi Desktop App", -}; - let mainWindow = null; let didFinishLoad = false; @@ -128,14 +124,7 @@ const handlePreloadLogic = async () => { try { log.info("Copying dolphin instance..."); - switch (platform) { - case "win32": // windows - await sudoExecAsyncWindows(`rmdir /Q /S "${targetPath}"`); - break; - default: - await sudoExecAsyncNonWindows("rm -rf \"$DOLPHIN_PATH\"", { ...sudoOptions, env: { DOLPHIN_PATH: targetPath } }); - } - + await sudoRemovePath(targetPath); fs.copySync(originalDolphinPath, targetPath); isCopySuccess = true; } catch (ex) { diff --git a/app/utils/sudoExec.js b/app/utils/sudoExec.js index fe9b99fe2..fbfa91646 100644 --- a/app/utils/sudoExec.js +++ b/app/utils/sudoExec.js @@ -5,10 +5,25 @@ import sudo from 'sudo-prompt'; import path from 'path'; import { exec } from 'child_process'; +const sudoOptions = { + name: "Slippi Desktop App", +}; + +export async function sudoRemovePath(pathToRemove) { + const platform = process.platform; + switch (platform) { + case "win32": // windows + await sudoExecAsyncWindows(`rmdir /Q /S "${pathToRemove}"`); + break; + default: + await sudoExecAsyncNonWindows("rm -rf \"$DOLPHIN_PATH\"", { ...sudoOptions, env: { DOLPHIN_PATH: pathToRemove } }); + } +} + export function sudoExecAsyncNonWindows(command, options) { return new Promise((resolve, reject) => { sudo.exec( - command, + command, options, (error) => { if ( @@ -18,8 +33,8 @@ export function sudoExecAsyncNonWindows(command, options) { } else { reject(new Error(`Could not run elevated command: ${error}`)); } - }) - }) + }); + }); } export function sudoExecAsyncWindows(command) { @@ -38,6 +53,6 @@ export function sudoExecAsyncWindows(command) { } else { reject(new Error(`Could not run elevated command: ${error}`)); } - }) - }) + }); + }); }