Skip to content

Commit

Permalink
Migrate from os.execCommand() to shell()
Browse files Browse the repository at this point in the history
Migrate all code to the shell() wrapper which provides error handling
  • Loading branch information
OrigamingWasTaken committed Oct 5, 2024
1 parent a480976 commit 44892c2
Show file tree
Hide file tree
Showing 15 changed files with 196 additions and 82 deletions.
6 changes: 4 additions & 2 deletions frontend/src/windows/main/components/Updater.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,21 @@
import { loadSettings, saveSettings } from './settings';
import { compareVersions, curlGet } from '../ts/utils';
import Link from './Link.svelte';
import { shell } from '../ts/tools/shell';
let showUpdatePopup = false;
let updateVersion = version;
let body = '';
async function checkForUpdate() {
const checkWifi = await os.execCommand('ping -c 1 google.com');
if (checkWifi.stdOut.includes('Unknown host')) {
const checkWifi = await shell(`if [[ "$(networksetup -getairportnetwork en0 | grep -o 'Current Wi-Fi Network:')" != "" ]]; then echo "true"; else echo "false"; fi`,[],{completeCommand: true});
if (!checkWifi.stdOut.includes('true')) {
toast.error('Could not connect to internet');
return;
}
const releases = await curlGet('https://api.github.com/repos/AppleBlox/appleblox/releases').catch((err) => {
console.error('[Updater] ', err);
return;
});
if (releases.message) return;
for (const re of releases) {
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/windows/main/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { version } from '../../../../package.json';
import App from './App.svelte';
import { RPCController } from './ts/tools/rpc';
import { AbloxWatchdog } from './ts/watchdog';
import { shell } from './ts/tools/shell';

// Initialize NeutralinoJS
init();
Expand All @@ -26,7 +27,7 @@ events.on('ready', async () => {
console.info(`[Main] AppleBlox v${version}`);
console.info(`[Main] Current Time: ${new Date().toLocaleString()}`);
console.info(`[Main] NeutralinoJS Version: ${window.NL_VERSION}`);
console.info(`[Main] ${(await os.execCommand('uname -a')).stdOut.trim()}`);
console.info(`[Main] ${(await shell('uname',["-a"])).stdOut.trim()}`);

/** Launch the process manager */
const watchdog = new AbloxWatchdog();
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/windows/main/pages/Custom/ModsUI.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import path from 'path-browserify';
import { toast } from 'svelte-sonner';
import Roblox from '../../ts/roblox';
import shellFS from '../../ts/tools/shellfs';
let mods: { filename: string; path: string; state: boolean }[] = [];
Roblox.Mods.loadMods().then((m) => (mods = m));
Expand All @@ -20,7 +21,7 @@
try {
const modIndex = mods.findIndex((m) => m.path === filePath);
if (path.basename(filePath).endsWith('.disabled')) {
await os.execCommand(`mv "${filePath}" "${filePath.replace(/\.disabled$/, '')}"`);
await shellFS.move(filePath,filePath.replace(/\.disabled$/, ''))
if (modIndex >= 0) {
mods[modIndex] = {
...mods[modIndex],
Expand All @@ -29,7 +30,7 @@
};
}
} else {
await os.execCommand(`mv "${filePath}" "${filePath}.disabled"`);
await shellFS.move(filePath,`${filePath}.disabled`)
if (modIndex >= 0) {
mods[modIndex] = {
...mods[modIndex],
Expand Down
6 changes: 2 additions & 4 deletions frontend/src/windows/main/pages/Misc.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,14 @@
toast.error("The logs file doesn't seem to exist.");
return;
}
os.execCommand(`open -R "${logPath}"`).catch((err) => {
console.error('[MiscPanel] ', err);
});
shellFS.open(logPath,{reveal: true})
break;
}
case 'clear_logs':
clearLogsPopup = true;
break;
case 'open_folder':
os.execCommand('open -R ~/"Library/Application Support/AppleBlox"/');
shellFS.open(path.join(await os.getEnv("HOME"),"Library","Application Support","AppleBlox"),{reveal: true})
break;
}
}
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/windows/main/ts/roblox/delegate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ async function setUrlscheme(
bundleId: string
): Promise<{ toggled: true } | { toggled: false; stdErr: string; stdOut: string }> {
const command = await shell(`${urlscheme}`, ['set', uri, bundleId], { skipStderrCheck: true });
if (!command.stdout.includes('Successfully') && !command.stderr.includes('Successfully')) {
return { toggled: false, stdErr: command.stderr, stdOut: command.stdout };
if (!command.stdOut.includes('Successfully') && !command.stdErr.includes('Successfully')) {
return { toggled: false, stdErr: command.stdErr, stdOut: command.stdOut };
}
return { toggled: true };
}
Expand All @@ -21,7 +21,7 @@ export class RobloxDelegate {
static async check(retoggle = false) {
// If it's not active but toggled in settings, retoggle.
const cmd = await shell(`${urlscheme}`, ['check', 'roblox-player', 'ch.origaming.appleblox'], { skipStderrCheck: true });
const toggled = cmd.stdout.includes('true') || cmd.stderr.includes('true');
const toggled = cmd.stdOut.includes('true') || cmd.stdErr.includes('true');
if (!toggled && retoggle && (await getValue<boolean>('roblox.launching.delegate')) === true) {
await this.toggle(true);
return true;
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/windows/main/ts/roblox/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,10 @@ export default async function onGameEvent(data: GameEventInfo) {
// Resolution fix for mods
if ((await getValue('mods.general.fix_res')) === true) {
const maxRes = (
await shell("system_profiler SPDisplaysDataType | grep Resolution | awk -F': ' '{print $2}'")
).stdout
await shell("system_profiler SPDisplaysDataType | grep Resolution | awk -F': ' '{print $2}'", [], {
completeCommand: true,
})
).stdOut
.trim()
.split(' ');
await Roblox.Window.setDesktopRes(maxRes[0], maxRes[2], 6);
Expand Down
32 changes: 21 additions & 11 deletions frontend/src/windows/main/ts/roblox/instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,9 @@ export class RobloxInstance {
}

// We find every roblox processes and get the RobloxPlayer one
const robloxProcess = (await os.execCommand('pgrep -f "Roblox"')).stdOut.split('\n');
const robloxProcess = (await shell('pgrep', ['-f', 'Roblox'])).stdOut.trim().split('\n');
for (const pid of robloxProcess) {
const info = (await os.execCommand(`ps -p ${pid} -o command=`)).stdOut.trim();
const info = (await shell(`ps -p ${pid} -o command=`, [], { completeCommand: true, skipStderrCheck: true })).stdOut.trim();
if (info.length < 2) continue;
const processFileName = path.basename(info);
if (processFileName === 'RobloxPlayer') {
Expand All @@ -175,7 +175,9 @@ export class RobloxInstance {
if (tries < 1) {
throw new Error(`Couldn't find a .log file created less than 15 seconds ago in "${logsDirectory}". Stopping.`);
}
const latestFile = (await os.execCommand(`cd "${logsDirectory}" && ls -t | head -1`)).stdOut.trim();
const latestFile = (
await shell(`cd "${logsDirectory}" && ls -t | head -1`, [], { completeCommand: true })
).stdOut.trim();
const latestFilePath = path.join(logsDirectory, latestFile);
const createdAt = (await filesystem.getStats(latestFilePath)).createdAt;
const timeDifference = (Date.now() - createdAt) / 1000;
Expand All @@ -192,10 +194,13 @@ export class RobloxInstance {
}

// Read the first content, to not miss anything
await os.execCommand(`iconv -f utf-8 -t utf-8 -c "${this.latestLogPath}" > /tmp/roblox_ablox.log`);
const content = (await os.execCommand('cat /tmp/roblox_ablox.log')).stdOut;
await shell(`iconv -f utf-8 -t utf-8 -c "${this.latestLogPath}" > /tmp/roblox_ablox.log`, [], { completeCommand: true });
const content = (await shell('cat', ['/tmp/roblox_ablox.log'])).stdOut;
// Spawns the logs watcher, and be sure that it kills any previous one
await os.execCommand(`pkill -f "tail -f /Users/$(whoami)/Library/Logs/Roblox/"`);
await shell(`pkill -f "tail -f /Users/$(whoami)/Library/Logs/Roblox/"`, [], {
completeCommand: true,
skipStderrCheck: true,
});
this.logsInstance = await os.spawnProcess(`tail -f "${this.latestLogPath}" | while read line; do echo "Change"; done
`);
console.info(`[Roblox.Instance] Logs watcher started with PID: ${this.logsInstance.pid}`);
Expand All @@ -214,18 +219,23 @@ export class RobloxInstance {
console.warn('[Roblox.Instance] Logs watcher exited with output:', evt.detail.data);
console.info('[Roblox.Instance] Restarting logs watcher');

await os.execCommand(`pkill -f "tail -f /Users/$(whoami)/Library/Logs/Roblox/"`);
await shell(`pkill -f "tail -f /Users/$(whoami)/Library/Logs/Roblox/"`, [], {
completeCommand: true,
skipStderrCheck: true,
});
this.logsInstance = await os.spawnProcess(
`tail -f "${this.latestLogPath}" | while read line; do echo "Change"; done`
);
return;
}

// Convert the file to ensure proper encoding
await os.execCommand(`iconv -f utf-8 -t utf-8 -c "${this.latestLogPath}" > /tmp/roblox_ablox.log`);
await shell(`iconv -f utf-8 -t utf-8 -c "${this.latestLogPath}" > /tmp/roblox_ablox.log`, [], {
completeCommand: true,
});

// Read the content of the converted file
const content = (await os.execCommand('cat /tmp/roblox_ablox.log')).stdOut;
const content = (await shell('cat', ['/tmp/roblox_ablox.log'])).stdOut;

// Process only new lines
const contentLines = content.split('\n');
Expand Down Expand Up @@ -284,14 +294,14 @@ export class RobloxInstance {
this.isWatching = false;
this.onEvent = null;
// Kill logs watcher
await os.execCommand(`pkill -f "tail -f /Users/$(whoami)/Library/Logs/Roblox/"`);
shell(`pkill -f "tail -f /Users/$(whoami)/Library/Logs/Roblox/"`, [], { completeCommand: true, skipStderrCheck: true });
}

/** Quits Roblox */
public async quit() {
if (this.gameInstance == null) throw new Error("The instance hasn't be started yet");
await this.cleanup();
console.info('[Roblox.Instance] Quitting Roblox');
await os.execCommand(`kill -9 ${this.gameInstance}`);
await shell('kill -9', ['-9', this.gameInstance.toString()]);
}
}
8 changes: 5 additions & 3 deletions frontend/src/windows/main/ts/roblox/launch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export async function launchRoblox(
showFlagErrorPopup: (title: string, description: string, code: string) => Promise<boolean>,
robloxUrl?: string
) {
if (rbxInstance || (await os.execCommand('pgrep -f "RobloxPlayer"')).stdOut.trim().length > 2) {
if (rbxInstance || (await shell('pgrep', ['-f', 'RobloxPlayer'], {skipStderrCheck: true})).stdOut.trim().length > 2) {
setLaunchText('Roblox is already open');
setLaunchingRoblox(false);
toast.error('Due to technical reasons, you must close all instances of Roblox before launching from AppleBlox.');
Expand Down Expand Up @@ -136,8 +136,10 @@ export async function launchRoblox(
try {
if ((await getValue('mods.general.fix_res')) === true) {
const maxRes = (
await shell("system_profiler SPDisplaysDataType | grep Resolution | awk -F': ' '{print $2}'")
).stdout
await shell("system_profiler SPDisplaysDataType | grep Resolution | awk -F': ' '{print $2}'", [], {
completeCommand: true,
})
).stdOut
.trim()
.split(' ');
await Roblox.Window.setDesktopRes(maxRes[0], maxRes[2], 5);
Expand Down
30 changes: 19 additions & 11 deletions frontend/src/windows/main/ts/roblox/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { toast } from 'svelte-sonner';
import Roblox from '.';
import { libraryPath } from '../libraries';
import shellFS from '../tools/shellfs';
import { shell } from '../tools/shell';

export class RobloxUtils {
/** Checks if roblox is installed, and if not show a popup */
Expand All @@ -14,21 +15,25 @@ export class RobloxUtils {
return true;
}
if (!popup) return false;
os.execCommand(`osascript <<'END'
shell(
`osascript <<'END'
set theAlertText to "Roblox is not installed"
set theAlertMessage to "To use AppleBlox, you first need to install Roblox. Would you like to open the download page?"
display alert theAlertText message theAlertMessage as critical buttons {"Cancel", "Open link"} default button "Open link" cancel button "Cancel" giving up after 60
set the button_pressed to the button returned of the result
if the button_pressed is "Open link" then
open location "https://roblox.com/download"
end if
END`);
END`,
[],
{ completeCommand: true }
);
return false;
}

/** Uses cli to check if any instance of roblox is open */
static async isRobloxOpen() {
const cmd = await os.execCommand('ps aux | grep "Roblox" | grep -v "grep"');
const cmd = await shell('ps aux | grep "Roblox" | grep -v "grep"', [], { completeCommand: true, skipStderrCheck: true });
return cmd.stdOut.includes('Roblox');
}

Expand All @@ -40,26 +45,29 @@ END`);
if (await RobloxUtils.isRobloxOpen()) {
toast.info('Closing Roblox...', { duration: 1000 });
console.info('[Roblox.Utils] Closing Roblox...');
await os.execCommand('pkill -9 Roblox');
await shell('pkill', ['-9', 'Roblox'],{skipStderrCheck: true});
await sleep(2000);
}

toast.info('Opening Roblox...', { duration: 1000 });
console.info('[Roblox.Utils] Opening Roblox...');
await os.execCommand(`open "${Roblox.path}"`, { background: true });
await shellFS.open(Roblox.path);

await sleep(1000);

toast.info('Terminating all processes...', { duration: 1000 });
console.info('[Roblox.Utils] Terminating all Roblox processes...');
const result = await os.execCommand("ps aux | grep -i roblox | grep -v grep | awk '{print $2}' | xargs");
const result = await shell("ps aux | grep -i roblox | grep -v grep | awk '{print $2}' | xargs", [], {
completeCommand: true,
skipStderrCheck: true
});
console.info('[Roblox.Utils] Termination result: ', result);
const processes = result.stdOut.trim().split(' ');
for (const proc of processes) {
console.info(`[Roblox.Utils] Terminating Roblox Process (PID: ${proc})`);

try {
await os.execCommand(`kill -9 ${proc}`);
await shell("kill",["-9",proc],{skipStderrCheck: true})
} catch (err) {
console.error(`[Roblox.Utils] Error terminating process ${proc}: ${err}`);
toast.error(`Error terminating process ${proc}: ${err}`);
Expand Down Expand Up @@ -120,17 +128,17 @@ END`);
path.join(savePath, 'Launch Roblox.app/Contents/MacOS/launch'),
`#!/bin/bash\n${path.join(path.dirname(window.NL_PATH), 'MacOS/bootstrap')} --launch`
);
await os.execCommand(`chmod +x ${path.join(savePath, 'Launch Roblox.app/Contents/MacOS/launch').replaceAll(' ', '\\ ')}`);
await shellFS.chmod(path.join(savePath, 'Launch Roblox.app/Contents/MacOS/launch').replaceAll(' ', '\\ '),"+x")
toast.success(`Created a shortcut at "${path.join(savePath, 'Launch Roblox.app')}"`);
}

static async killAll() {
await os.execCommand(`ps aux | grep -i roblox | grep -v grep | awk '{print $2}' | xargs kill -9`);
await shell(`ps aux | grep -i roblox | grep -v grep | awk '{print $2}' | xargs kill -9`,[],{completeCommand: true, skipStderrCheck: true});
}

static async quit() {
await os.execCommand(`osascript -e 'tell application "Roblox" to if it is running then quit'`);
while ((await os.execCommand('ps aux | grep RobloxPlayer | grep -v grep')).stdOut.trim().length > 2) {
await shell(`osascript -e 'tell application "Roblox" to if it is running then quit'`,[],{completeCommand: true, skipStderrCheck: true});
while ((await shell('ps aux | grep RobloxPlayer | grep -v grep',[],{completeCommand: true})).stdOut.trim().length > 2) {
await sleep(500);
}
return;
Expand Down
23 changes: 14 additions & 9 deletions frontend/src/windows/main/ts/roblox/window.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { computer, os } from '@neutralinojs/lib';
import { libraryPath } from '../libraries';
import { shell } from '../tools/shell';

const window_manager = libraryPath('window_manager');

Expand All @@ -12,7 +13,7 @@ export class RobloxWindow {
* @param y The target y-coordinate
*/
public static async move(x: number | string, y: number | string) {
os.execCommand(`${window_manager} move "Roblox" ${x} ${y}`);
await shell(`${window_manager}`, ['move', 'Roblox', x, y]);
console.info(`[Roblox.Window] Moved Roblox window to "${x},${y}"`);
}
/**
Expand All @@ -21,12 +22,13 @@ export class RobloxWindow {
* @param height The target height
*/
public static async resize(width: number | string, height: number | string) {
os.execCommand(`${window_manager} resize "Roblox" ${width} ${height}`);
shell(`${window_manager}`, ['resize', 'Roblox', width, height]);
console.info(`[Roblox.Window] Resized Roblox window to "${width},${height}"`);
}

public static async isFullscreen(): Promise<boolean> {
const getInfoCmd = await os.execCommand(`osascript -e 'tell application "System Events"
const getInfoCmd = await shell(
`osascript -e 'tell application "System Events"
tell application "Roblox" to activate
try
tell process "Roblox"
Expand All @@ -37,7 +39,10 @@ export class RobloxWindow {
return "true"
end try
end tell'
`);
`,
[],
{ completeCommand: true }
);
return getInfoCmd.stdOut.trim() === 'true';
}

Expand All @@ -47,8 +52,10 @@ export class RobloxWindow {
*/
public static async setFullscreen(fullscreen: boolean): Promise<void> {
if ((await RobloxWindow.isFullscreen()) === fullscreen) return;
await os.execCommand(
`osascript -e 'tell application "Roblox" to activate' -e 'delay 0.5' -e 'tell application "System Events" to tell process "Roblox" to keystroke "f" using {command down}'`
await shell(
`osascript -e 'tell application "Roblox" to activate' -e 'delay 0.5' -e 'tell application "System Events" to tell process "Roblox" to keystroke "f" using {command down}'`,
[],
{ skipStderrCheck: true, completeCommand: true }
);
}

Expand All @@ -61,8 +68,6 @@ export class RobloxWindow {

/** Sets the desktop resolution */
public static async setDesktopRes(width: number | string, height: number | string, duration = 1) {
os.execCommand(`${libraryPath('window_manager')} setres ${width} ${height} ${duration} 1`, {
background: true,
});
shell(`${window_manager}`, ['setres', width, height, duration, 1], { background: true });
}
}
2 changes: 1 addition & 1 deletion frontend/src/windows/main/ts/tools/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export class DiscordRPC {
private async isRunning(): Promise<boolean> {
try {
const result = await shell('pgrep', ['-f', 'discordrpc_ablox']);
return result.stdout.split('\n').length > 2;
return result.stdOut.split('\n').length > 2;
} catch (err) {
return false;
}
Expand Down
Loading

0 comments on commit 44892c2

Please sign in to comment.