mirror of
https://github.com/everoddandeven/monerod-gui.git
synced 2024-12-23 03:59:27 +00:00
157 lines
5.5 KiB
TypeScript
157 lines
5.5 KiB
TypeScript
const applescript = require('applescript');
|
|
import * as path from 'path';
|
|
import * as fileBasedUtilities from '../fileBasedUtilities';
|
|
import AutoLaunchAPI from './autoLaunchAPI';
|
|
import { AutoLaunchInit } from './autoLaunchInit';
|
|
|
|
const MAC_LAUNCHAGENTS_DIR = '~/Library/LaunchAgents/';
|
|
const MAC_PLIST_DATA = `<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
<key>Label</key>
|
|
<string>{{APP_NAME}}</string>
|
|
<key>ProgramArguments</key>
|
|
<array>
|
|
{{PROGRAM_ARGUMENTS_SECTION}}
|
|
</array>
|
|
<key>RunAtLoad</key>
|
|
<true/>
|
|
</dict>
|
|
</plist>`;
|
|
|
|
export default class AutoLaunchAPIMac extends AutoLaunchAPI {
|
|
/* Public */
|
|
|
|
constructor(init: AutoLaunchInit) {
|
|
super(init);
|
|
this.appName = this.fixAppName();
|
|
this.appPath = this.fixAppPath();
|
|
}
|
|
|
|
// Returns a Promise
|
|
public override enable(): Promise<void> {
|
|
const hiddenArg = this.options.launchInBackground;
|
|
const extraArgs = this.options.extraArguments;
|
|
|
|
// Add the file if we're using a Launch Agent
|
|
if (this.options?.mac?.useLaunchAgent) {
|
|
const programArguments = [this.appPath];
|
|
|
|
// Manage arguments
|
|
if (hiddenArg) {
|
|
programArguments.push((hiddenArg !== true) ? hiddenArg : '--hidden');
|
|
}
|
|
if (extraArgs) {
|
|
programArguments.push(...extraArgs);
|
|
}
|
|
const programArgumentsSection = programArguments
|
|
.map((argument) => ` <string>${argument}</string>`)
|
|
.join('\n');
|
|
const plistData = MAC_PLIST_DATA.trim()
|
|
.replace(/{{APP_NAME}}/g, this.appName)
|
|
.replace(/{{PROGRAM_ARGUMENTS_SECTION}}/g, programArgumentsSection);
|
|
|
|
return fileBasedUtilities.createFile({
|
|
directory: this.getLaunchAgentsDirectory(),
|
|
filePath: this.getPlistFilePath(),
|
|
data: plistData
|
|
});
|
|
}
|
|
|
|
// Otherwise, use default method; use AppleScript to tell System Events to add a Login Item
|
|
|
|
const isHidden = hiddenArg ? 'true' : 'false';
|
|
// TODO: Manage extra arguments
|
|
const properties = `{path:"${this.appPath}", hidden:${isHidden}, name:"${this.appName}"}`;
|
|
|
|
return this.execApplescriptCommand(`make login item at end with properties ${properties}`);
|
|
}
|
|
|
|
// Returns a Promise
|
|
public override disable(): Promise<void> {
|
|
// Delete the file if we're using a Launch Agent
|
|
if (this.options.mac?.useLaunchAgent) {
|
|
return fileBasedUtilities.removeFile(this.getPlistFilePath());
|
|
}
|
|
|
|
// Otherwise remove the Login Item
|
|
return this.execApplescriptCommand(`delete login item "${this.appName}"`);
|
|
}
|
|
|
|
// Returns a Promise which resolves to a {Boolean}
|
|
public override isEnabled(): Promise<boolean> {
|
|
// Check if the Launch Agent file exists
|
|
if (this.options.mac?.useLaunchAgent) {
|
|
return fileBasedUtilities.fileExists(this.getPlistFilePath());
|
|
}
|
|
|
|
// Otherwise check if a Login Item exists for our app
|
|
return this.execApplescriptCommand('get the name of every login item')
|
|
.then((loginItems) => (loginItems != null) && Array.from<any>(loginItems).includes(this.appName));
|
|
}
|
|
|
|
/* Private */
|
|
|
|
// commandSuffix - {String}
|
|
// Returns a Promise
|
|
private execApplescriptCommand(commandSuffix: string): Promise<any>{
|
|
return new Promise((resolve, reject) => {
|
|
applescript.execString(`tell application "System Events" to ${commandSuffix}`, (err: { message: string, strPath: string, appleScript: string } | null, result: any) => {
|
|
if (err != null) {
|
|
return reject(err);
|
|
}
|
|
return resolve(result);
|
|
});
|
|
});
|
|
}
|
|
|
|
// Returns a {String}
|
|
private getLaunchAgentsDirectory(): string {
|
|
return fileBasedUtilities.untildify(MAC_LAUNCHAGENTS_DIR);
|
|
}
|
|
|
|
// Returns a {String}
|
|
private getPlistFilePath(): string {
|
|
return path.join(this.getLaunchAgentsDirectory(), `${this.appName}.plist`);
|
|
}
|
|
|
|
// Corrects the path to point to the outer .app
|
|
// Returns a {String}
|
|
private fixAppPath(): string {
|
|
let execPath = this.appPath;
|
|
|
|
// This will match apps whose inner app and executable's basename is the outer app's basename plus "Helper"
|
|
// (the default Electron app structure for example)
|
|
// It will also match apps whose outer app's basename is different to the rest but the inner app and executable's
|
|
// basenames are matching (a typical distributed NW app for example)
|
|
// Does not match when the three are different
|
|
// Also matches when the path is pointing not to the exectuable in the inner app at all but to the Electron
|
|
// executable in the outer app
|
|
// eslint-disable-next-line max-len
|
|
execPath = execPath.replace(/(^.+?[^/]+?\.app)\/Contents\/(Frameworks\/((\1|[^/]+?) Helper)\.app\/Contents\/MacOS\/\3|MacOS\/Electron)/, '$1');
|
|
|
|
// When using a launch agent, it needs the inner executable path
|
|
if (!this.options.mac?.useLaunchAgent) {
|
|
execPath = execPath.replace(/\.app\/Contents\/MacOS\/[^/]*$/, '.app');
|
|
}
|
|
|
|
return execPath;
|
|
}
|
|
|
|
// Kept from Coffeescript, but should we honor the name given to autoLaunch or should we change it specifically for macOS?
|
|
// No explanation, see issue 92: https://github.com/Teamwork/node-auto-launch/issues/92
|
|
private fixAppName(): string {
|
|
let fixedName: string;
|
|
|
|
const tempPath = this.appPath.split('/');
|
|
|
|
fixedName = tempPath[tempPath.length - 1];
|
|
// Remove ".app" from the appName if it exists
|
|
if (fixedName.indexOf('.app', fixedName.length - '.app'.length) !== -1) {
|
|
fixedName = fixedName.substr(0, fixedName.length - '.app'.length);
|
|
}
|
|
|
|
return fixedName;
|
|
}
|
|
}
|