mirror of
https://github.com/everoddandeven/monerod-gui.git
synced 2025-01-03 09:29:36 +00:00
Port auto launch
This commit is contained in:
parent
9bb45d09e4
commit
d6dee8e56d
12 changed files with 611 additions and 64 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -8,6 +8,7 @@
|
|||
/release
|
||||
main.js
|
||||
src/**/*.js
|
||||
app/auto-launch/**/*.js
|
||||
*.js.map
|
||||
|
||||
# dependencies
|
||||
|
|
67
app/auto-launch/index.ts
Normal file
67
app/auto-launch/index.ts
Normal file
|
@ -0,0 +1,67 @@
|
|||
import * as pathTools from 'path';
|
||||
import autoLaunchHandler from './library/autoLaunchHandler';
|
||||
import { AutoLaunchOptions } from './library/autoLaunchAPI/autoLaunchInit';
|
||||
import AutoLaunchAPI from './library/autoLaunchAPI/autoLaunchAPI';
|
||||
|
||||
// Public: The main auto-launch class
|
||||
export default class AutoLaunch {
|
||||
private api: AutoLaunchAPI;
|
||||
/* Public */
|
||||
|
||||
// {Object}
|
||||
// :name - {String}
|
||||
// :path - (Optional) {String}
|
||||
// :options - (Optional) {Object}
|
||||
// :launchInBackground, - (Optional) {String}. If set, either use default --hidden arg or specified one.
|
||||
// :mac - (Optional) {Object}
|
||||
// :useLaunchAgent - (Optional) {Boolean}. If `true`, use filed-based Launch Agent. Otherwise use AppleScript
|
||||
// to add Login Item
|
||||
// :extraArgs - (Optional) {Array}
|
||||
constructor({ name , path, options }: { name: string, path: string, options: AutoLaunchOptions }) {
|
||||
// Name is the only mandatory parameter and must neither be null nor empty
|
||||
if (!name) { throw new Error('You must specify a name'); }
|
||||
|
||||
const opts = {
|
||||
appName: name,
|
||||
options: {
|
||||
launchInBackground: (options && (options.launchInBackground != null)) ? options.launchInBackground : false,
|
||||
mac: (options && (options.mac != null)) ? options.mac : {},
|
||||
extraArguments: (options && (options.extraArguments != null)) ? options.extraArguments : []
|
||||
},
|
||||
appPath: ''
|
||||
};
|
||||
|
||||
const versions = typeof process !== 'undefined' && process !== null ? process.versions : undefined;
|
||||
if (path != null) {
|
||||
// Verify that the path is absolute or is an AppX path
|
||||
if ((!pathTools.isAbsolute(path)) && !process.windowsStore) {
|
||||
throw new Error('path must be absolute');
|
||||
}
|
||||
opts.appPath = path;
|
||||
} else if (
|
||||
(versions != null)
|
||||
&& ((versions.nw != null) || (versions['node-webkit'] != null) || (versions.electron != null))) {
|
||||
// Autodetecting the appPath from the execPath.
|
||||
// This appPath will need to be fixed later depending of the OS used
|
||||
// TODO: is this the reason behind issue 92: https://github.com/Teamwork/node-auto-launch/issues/92
|
||||
opts.appPath = process.execPath;
|
||||
} else {
|
||||
throw new Error('You must give a path (this is only auto-detected for NW.js and Electron apps)');
|
||||
}
|
||||
|
||||
this.api = autoLaunchHandler(opts);
|
||||
}
|
||||
|
||||
public enable(): Promise<void> {
|
||||
return this.api.enable();
|
||||
}
|
||||
|
||||
public disable(): Promise<void> {
|
||||
return this.api.disable();
|
||||
}
|
||||
|
||||
// Returns a Promise which resolves to a {Boolean}
|
||||
public isEnabled(): Promise<boolean> {
|
||||
return this.api.isEnabled();
|
||||
}
|
||||
}
|
33
app/auto-launch/library/autoLaunchAPI/autoLaunchAPI.ts
Normal file
33
app/auto-launch/library/autoLaunchAPI/autoLaunchAPI.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import { AutoLaunchInit, AutoLaunchOptions } from "./autoLaunchInit";
|
||||
|
||||
export default abstract class AutoLaunchAPI {
|
||||
/* Public */
|
||||
|
||||
public appName: string;
|
||||
public appPath: string;
|
||||
public options: AutoLaunchOptions;
|
||||
|
||||
// init - {Object}
|
||||
// :appName - {String}
|
||||
// :appPath - {String}
|
||||
// :options - {Object}
|
||||
// :launchInBackground - (Optional) {String} If set, either use default --hidden arg or specified one.
|
||||
// :mac - (Optional) {Object}
|
||||
// :useLaunchAgent - (Optional) {Boolean} If `true`, use filed-based Launch Agent. Otherwise use AppleScript
|
||||
// to add Login Item
|
||||
// :extraArguments - (Optional) {Array}
|
||||
protected constructor(init: AutoLaunchInit) {
|
||||
this.appName = init.appName;
|
||||
this.appPath = init.appPath;
|
||||
this.options = init.options;
|
||||
}
|
||||
|
||||
// Returns a Promise
|
||||
public abstract enable(): Promise<void>;
|
||||
|
||||
// Returns a Promise
|
||||
public abstract disable(): Promise<void>;
|
||||
|
||||
// Returns a Promise which resolves to a {Boolean}
|
||||
public abstract isEnabled(): Promise<boolean>;
|
||||
}
|
92
app/auto-launch/library/autoLaunchAPI/autoLaunchAPILinux.ts
Normal file
92
app/auto-launch/library/autoLaunchAPI/autoLaunchAPILinux.ts
Normal file
|
@ -0,0 +1,92 @@
|
|||
import * as path from 'path';
|
||||
//import * as untildify from 'untildify';
|
||||
import * as fileBasedUtilities from '../fileBasedUtilities';
|
||||
import AutoLaunchAPI from './autoLaunchAPI';
|
||||
import { AutoLaunchInit } from './autoLaunchInit';
|
||||
|
||||
const LINUX_AUTOSTART_DIR = '~/.config/autostart';
|
||||
const LINUX_DESKTOP = `
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Version=1.0
|
||||
Name={{APP_NAME}}
|
||||
Comment={{APP_NAME}} startup script
|
||||
Exec={{APP_PATH}} {{ARGS}}
|
||||
StartupNotify=false
|
||||
Terminal=false
|
||||
`;
|
||||
|
||||
export default class AutoLaunchAPILinux extends AutoLaunchAPI {
|
||||
/* Public */
|
||||
|
||||
constructor(init: AutoLaunchInit) {
|
||||
super(init);
|
||||
this.appPath = this.fixAppPath();
|
||||
}
|
||||
|
||||
// Returns a Promise
|
||||
public override enable(): Promise<void> {
|
||||
const hiddenArg = this.options.launchInBackground;
|
||||
const extraArgs = this.options.extraArguments;
|
||||
const programArguments = [];
|
||||
|
||||
// Manage arguments
|
||||
if (hiddenArg) {
|
||||
programArguments.push((hiddenArg !== true) ? hiddenArg : '--hidden');
|
||||
}
|
||||
if (extraArgs) {
|
||||
programArguments.push(extraArgs);
|
||||
}
|
||||
const args = programArguments.join(' ');
|
||||
|
||||
const desktop = LINUX_DESKTOP.trim()
|
||||
.replace(/{{APP_NAME}}/g, this.appName)
|
||||
.replace(/{{APP_PATH}}/g, this.appPath)
|
||||
.replace(/{{ARGS}}/g, args);
|
||||
|
||||
return fileBasedUtilities.createFile({
|
||||
directory: this.getAutostartDirectory(),
|
||||
filePath: this.getDesktopFilePath(),
|
||||
data: desktop
|
||||
});
|
||||
}
|
||||
|
||||
// Returns a Promise
|
||||
public override disable(): Promise<void> {
|
||||
return fileBasedUtilities.removeFile(this.getDesktopFilePath());
|
||||
}
|
||||
|
||||
// Returns a Promise which resolves to a {Boolean}
|
||||
public override isEnabled(): Promise<boolean> {
|
||||
return fileBasedUtilities.fileExists(this.getDesktopFilePath());
|
||||
}
|
||||
|
||||
/* Private */
|
||||
|
||||
// Returns a {String}
|
||||
private getAutostartDirectory(): string {
|
||||
return fileBasedUtilities.untildify(LINUX_AUTOSTART_DIR);
|
||||
}
|
||||
|
||||
// Returns a {String}
|
||||
private getDesktopFilePath(): string {
|
||||
return path.join(this.getAutostartDirectory(), `${this.appName}.desktop`);
|
||||
}
|
||||
|
||||
// Returns a {String}
|
||||
private fixAppPath(): string {
|
||||
let execPath = this.appPath;
|
||||
|
||||
// If this is an AppImage, the actual AppImage's file path must be used, otherwise the mount path will be used.
|
||||
// This will fail on the next launch, since AppImages are mount temporarily when executed
|
||||
// in an everchanging mount folder.
|
||||
if (process.env?.APPIMAGE != null) {
|
||||
execPath = process.env.APPIMAGE;
|
||||
}
|
||||
|
||||
// As stated in the .desktop entry spec, Exec key's value must be properly escaped with reserved characters.
|
||||
execPath = fileBasedUtilities.escapeFilePath(execPath);
|
||||
|
||||
return execPath;
|
||||
}
|
||||
}
|
157
app/auto-launch/library/autoLaunchAPI/autoLaunchAPIMac.ts
Normal file
157
app/auto-launch/library/autoLaunchAPI/autoLaunchAPIMac.ts
Normal file
|
@ -0,0 +1,157 @@
|
|||
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;
|
||||
}
|
||||
}
|
105
app/auto-launch/library/autoLaunchAPI/autoLaunchAPIWindows.ts
Normal file
105
app/auto-launch/library/autoLaunchAPI/autoLaunchAPIWindows.ts
Normal file
|
@ -0,0 +1,105 @@
|
|||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as Winreg from 'winreg';
|
||||
import AutoLaunchAPI from './autoLaunchAPI';
|
||||
import { AutoLaunchInit } from './autoLaunchInit';
|
||||
|
||||
const regKey = new Winreg({
|
||||
hive: Winreg.HKCU,
|
||||
key: '\\Software\\Microsoft\\Windows\\CurrentVersion\\Run'
|
||||
});
|
||||
|
||||
export default class AutoLaunchAPIWindows extends AutoLaunchAPI {
|
||||
/* Public */
|
||||
|
||||
constructor(init: AutoLaunchInit) {
|
||||
super(init);
|
||||
}
|
||||
|
||||
// Returns a Promise
|
||||
public override enable(): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
let args = '';
|
||||
let pathToAutoLaunchedApp;
|
||||
const hiddenArg = this.options.launchInBackground;
|
||||
const extraArgs = this.options.extraArguments;
|
||||
const updateDotExe = path.join(path.dirname(process.execPath), '..', 'update.exe');
|
||||
|
||||
// If they're using Electron and Squirrel.Windows, point to its Update.exe instead of the actual appPath
|
||||
// Otherwise, we'll auto-launch an old version after the app has updated
|
||||
if (((process.versions != null ? process.versions.electron : undefined) != null) && fs.existsSync(updateDotExe)) {
|
||||
pathToAutoLaunchedApp = `"${updateDotExe}"`;
|
||||
args = ` --processStart "${path.basename(process.execPath)}"`;
|
||||
|
||||
// Manage arguments
|
||||
if (hiddenArg || extraArgs) {
|
||||
args += ' --process-start-args';
|
||||
if (hiddenArg) {
|
||||
args += ` "${(hiddenArg !== true) ? hiddenArg : '--hidden'}"`;
|
||||
}
|
||||
// Add any extra arguments
|
||||
if (extraArgs) {
|
||||
args += ' "';
|
||||
args += extraArgs.join('" "');
|
||||
args += '"';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If this is an AppX (from Microsoft Store), the path doesn't point to a directory per se,
|
||||
// but it's made of "DEV_ID.APP_ID!PACKAGE_NAME". It's used to identify the app in the AppsFolder.
|
||||
// To launch the app, explorer.exe must be call in combination with its path relative to AppsFolder
|
||||
if (process.windowsStore) {
|
||||
pathToAutoLaunchedApp = `"explorer.exe" shell:AppsFolder\\${this.appPath}`;
|
||||
} else {
|
||||
pathToAutoLaunchedApp = `"${this.appPath}"`;
|
||||
}
|
||||
|
||||
// Manage arguments
|
||||
if (hiddenArg) {
|
||||
args = (hiddenArg !== true) ? hiddenArg : ' --hidden';
|
||||
}
|
||||
// Add any extra arguments
|
||||
if (extraArgs) {
|
||||
args += ' ';
|
||||
args += extraArgs.join(' ');
|
||||
}
|
||||
}
|
||||
|
||||
regKey.set(this.appName, Winreg.REG_SZ, `"${pathToAutoLaunchedApp}"${args}`, (err) => {
|
||||
if (err != null) {
|
||||
return reject(err);
|
||||
}
|
||||
return resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Returns a Promise
|
||||
public override disable(): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
regKey.remove(this.appName, (err) => {
|
||||
if (err != null) {
|
||||
// The registry key should exist but, in case it fails because it doesn't exist,
|
||||
// resolve false instead of rejecting with an error
|
||||
if (err.message.indexOf('The system was unable to find the specified registry key or value') !== -1) {
|
||||
return resolve();
|
||||
}
|
||||
return reject(err);
|
||||
}
|
||||
return resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Returns a Promise which resolves to a {Boolean}
|
||||
public override isEnabled(): Promise<boolean> {
|
||||
return new Promise((resolve) => {
|
||||
regKey.valueExists(this.appName, (err, exists) => {
|
||||
if (err != null) {
|
||||
return resolve(false);
|
||||
}
|
||||
return resolve(exists);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
24
app/auto-launch/library/autoLaunchAPI/autoLaunchInit.ts
Normal file
24
app/auto-launch/library/autoLaunchAPI/autoLaunchInit.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
|
||||
// init - {Object}
|
||||
// :appName - {String}
|
||||
// :appPath - {String}
|
||||
// :options - {Object}
|
||||
// :launchInBackground - (Optional) {String} If set, either use default --hidden arg or specified one.
|
||||
// :mac - (Optional) {Object}
|
||||
// :useLaunchAgent - (Optional) {Boolean} If `true`, use filed-based Launch Agent. Otherwise use AppleScript
|
||||
// to add Login Item
|
||||
// :extraArguments - (Optional) {Array}
|
||||
|
||||
export interface AutoLaunchInit {
|
||||
appName: string;
|
||||
appPath: string;
|
||||
options: AutoLaunchOptions;
|
||||
}
|
||||
|
||||
export interface AutoLaunchOptions {
|
||||
launchInBackground?: string | boolean;
|
||||
mac?: {
|
||||
useLaunchAgent?: boolean;
|
||||
},
|
||||
extraArguments?: string[];
|
||||
}
|
23
app/auto-launch/library/autoLaunchHandler.ts
Normal file
23
app/auto-launch/library/autoLaunchHandler.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
import AutoLaunchAPI from './autoLaunchAPI/autoLaunchAPI';
|
||||
import AutoLaunchAPILinux from './autoLaunchAPI/autoLaunchAPILinux';
|
||||
import AutoLaunchAPIMac from './autoLaunchAPI/autoLaunchAPIMac';
|
||||
import AutoLaunchAPIWindows from './autoLaunchAPI/autoLaunchAPIWindows';
|
||||
import { AutoLaunchInit } from './autoLaunchAPI/autoLaunchInit';
|
||||
|
||||
/* This allows to select the AutoLaunch implementation specific to a */
|
||||
//
|
||||
// Returns a AutoLaunchAPI object
|
||||
|
||||
export default function autoLaunchHandler(options: AutoLaunchInit): AutoLaunchAPI {
|
||||
if (/^win/.test(process.platform)) {
|
||||
return new AutoLaunchAPIWindows(options);
|
||||
}
|
||||
if (/darwin/.test(process.platform)) {
|
||||
return new AutoLaunchAPIMac(options);
|
||||
}
|
||||
if ((/linux/.test(process.platform)) || (/freebsd/.test(process.platform))) {
|
||||
return new AutoLaunchAPILinux(options);
|
||||
}
|
||||
|
||||
throw new Error('Unsupported platform');
|
||||
}
|
79
app/auto-launch/library/fileBasedUtilities.ts
Normal file
79
app/auto-launch/library/fileBasedUtilities.ts
Normal file
|
@ -0,0 +1,79 @@
|
|||
import * as os from 'os';
|
||||
import * as fs from 'fs';
|
||||
|
||||
// Public: a few utils for file-based auto-launching
|
||||
|
||||
// This is essentially enabling auto-launching
|
||||
// options - {Object}
|
||||
// :directory - {String}
|
||||
// :filePath - {String}
|
||||
// :data - {String}
|
||||
// Returns a Promise
|
||||
export function createFile({ directory, filePath, data }: { directory: string, filePath: string, data: string }): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
fs.mkdir(directory, { recursive: true }, (mkdirErr) => {
|
||||
if (mkdirErr != null) {
|
||||
return reject(mkdirErr);
|
||||
}
|
||||
return fs.writeFile(filePath, data, (writeErr) => {
|
||||
if (writeErr != null) {
|
||||
return reject(writeErr);
|
||||
}
|
||||
return resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Verify auto-launch file exists or not
|
||||
// filePath - {String}
|
||||
// Returns a Promise
|
||||
export function fileExists(filePath: string): Promise<boolean> {
|
||||
return new Promise<boolean>((resolve) => {
|
||||
fs.stat(filePath, (err, stat) => {
|
||||
if (err != null) {
|
||||
return resolve(false);
|
||||
}
|
||||
return resolve(stat != null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// This is essentially disabling auto-launching
|
||||
// filePath - {String}
|
||||
// Returns a Promise
|
||||
export function removeFile(filePath: string): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
fs.stat(filePath, (statErr) => {
|
||||
// If it doesn't exist, this is good so resolve
|
||||
if (statErr != null) {
|
||||
return resolve();
|
||||
}
|
||||
|
||||
return fs.unlink(filePath, (unlinkErr) => {
|
||||
if (unlinkErr != null) {
|
||||
return reject(unlinkErr);
|
||||
}
|
||||
return resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Escape reserved characters in path
|
||||
// filePath - {String}
|
||||
// Returns {String}
|
||||
export function escapeFilePath(filePath: string): string {
|
||||
return filePath.replace(/(\s+)/g, '\\$1');
|
||||
// return filePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // https://github.com/tc39/proposal-regex-escaping
|
||||
}
|
||||
|
||||
export function untildify(pathWithTilde: string): string {
|
||||
const homeDirectory = os.homedir();
|
||||
|
||||
if (typeof pathWithTilde !== 'string') {
|
||||
throw new TypeError(`Expected a string, got ${typeof pathWithTilde}`);
|
||||
}
|
||||
|
||||
return homeDirectory ? pathWithTilde.replace(/^~(?=$|\/|\\)/, homeDirectory) : pathWithTilde;
|
||||
}
|
16
app/main.ts
16
app/main.ts
|
@ -1,4 +1,6 @@
|
|||
import { app, BrowserWindow, ipcMain, screen, dialog, Tray, Menu, MenuItemConstructorOptions, FileFilter, IpcMainInvokeEvent, Notification, NotificationConstructorOptions } from 'electron';
|
||||
import { app, BrowserWindow, ipcMain, screen, dialog, Tray, Menu, MenuItemConstructorOptions,
|
||||
IpcMainInvokeEvent, Notification, NotificationConstructorOptions
|
||||
} from 'electron';
|
||||
import { ChildProcessWithoutNullStreams, exec, ExecException, spawn } from 'child_process';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
|
@ -7,8 +9,7 @@ import { createHash } from 'crypto';
|
|||
import * as tar from 'tar';
|
||||
import * as os from 'os';
|
||||
import * as pidusage from 'pidusage';
|
||||
//import AutoLaunch from 'auto-launch';
|
||||
const AutoLaunch = require('auto-launch');
|
||||
import AutoLaunch from './auto-launch';
|
||||
|
||||
interface Stats {
|
||||
/**
|
||||
|
@ -60,8 +61,13 @@ if (!gotInstanceLock) {
|
|||
}
|
||||
|
||||
const autoLauncher = new AutoLaunch({
|
||||
name: 'Monero Daemon',
|
||||
path: `${process.execPath} --auto-launch`
|
||||
name: 'monerod-gui',
|
||||
path: process.execPath,
|
||||
options: {
|
||||
extraArguments: [
|
||||
'--auto-launch'
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
const isAutoLaunched: boolean = process.argv.includes('--auto-launch');
|
||||
|
|
70
app/package-lock.json
generated
70
app/package-lock.json
generated
|
@ -8,15 +8,17 @@
|
|||
"name": "monerod-gui",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"auto-launch": "^5.0.6",
|
||||
"applescript": "^1.0.0",
|
||||
"os": "^0.1.2",
|
||||
"pidusage": "^3.0.2",
|
||||
"tar": "^7.4.3",
|
||||
"unbzip2-stream": "^1.4.3"
|
||||
"unbzip2-stream": "^1.4.3",
|
||||
"winreg": "^1.2.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/auto-launch": "^5.0.5",
|
||||
"@types/pidusage": "^2.0.5"
|
||||
"@types/pidusage": "^2.0.5",
|
||||
"@types/winreg": "^1.2.36"
|
||||
}
|
||||
},
|
||||
"node_modules/@isaacs/cliui": {
|
||||
|
@ -67,6 +69,12 @@
|
|||
"integrity": "sha512-MIiyZI4/MK9UGUXWt0jJcCZhVw7YdhBuTOuqP/BjuLDLZ2PmmViMIQgZiWxtaMicQfAz/kMrZ5T7PKxFSkTeUA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/winreg": {
|
||||
"version": "1.2.36",
|
||||
"resolved": "https://registry.npmjs.org/@types/winreg/-/winreg-1.2.36.tgz",
|
||||
"integrity": "sha512-DtafHy5A8hbaosXrbr7YdjQZaqVewXmiasRS5J4tYMzt3s1gkh40ixpxgVFfKiQ0JIYetTJABat47v9cpr/sQg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
|
||||
|
@ -94,21 +102,6 @@
|
|||
"resolved": "https://registry.npmjs.org/applescript/-/applescript-1.0.0.tgz",
|
||||
"integrity": "sha512-yvtNHdWvtbYEiIazXAdp/NY+BBb65/DAseqlNiJQjOx9DynuzOYDbVLBJvuc0ve0VL9x6B3OHF6eH52y9hCBtQ=="
|
||||
},
|
||||
"node_modules/auto-launch": {
|
||||
"version": "5.0.6",
|
||||
"resolved": "https://registry.npmjs.org/auto-launch/-/auto-launch-5.0.6.tgz",
|
||||
"integrity": "sha512-OgxiAm4q9EBf9EeXdPBiVNENaWE3jUZofwrhAkWjHDYGezu1k3FRZHU8V2FBxGuSJOHzKmTJEd0G7L7/0xDGFA==",
|
||||
"dependencies": {
|
||||
"applescript": "^1.0.0",
|
||||
"mkdirp": "^0.5.1",
|
||||
"path-is-absolute": "^1.0.0",
|
||||
"untildify": "^3.0.2",
|
||||
"winreg": "1.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
|
@ -310,14 +303,6 @@
|
|||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/minipass": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
|
||||
|
@ -338,17 +323,6 @@
|
|||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/mkdirp": {
|
||||
"version": "0.5.6",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
|
||||
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.6"
|
||||
},
|
||||
"bin": {
|
||||
"mkdirp": "bin/cmd.js"
|
||||
}
|
||||
},
|
||||
"node_modules/os": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/os/-/os-0.1.2.tgz",
|
||||
|
@ -359,14 +333,6 @@
|
|||
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
|
||||
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="
|
||||
},
|
||||
"node_modules/path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/path-key": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||
|
@ -596,14 +562,6 @@
|
|||
"through": "^2.3.8"
|
||||
}
|
||||
},
|
||||
"node_modules/untildify": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/untildify/-/untildify-3.0.3.tgz",
|
||||
"integrity": "sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
|
@ -619,9 +577,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/winreg": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/winreg/-/winreg-1.2.4.tgz",
|
||||
"integrity": "sha512-IHpzORub7kYlb8A43Iig3reOvlcBJGX9gZ0WycHhghHtA65X0LYnMRuJs+aH1abVnMJztQkvQNlltnbPi5aGIA=="
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/winreg/-/winreg-1.2.5.tgz",
|
||||
"integrity": "sha512-uf7tHf+tw0B1y+x+mKTLHkykBgK2KMs3g+KlzmyMbLvICSHQyB/xOFjTT8qZ3oeTFyU7Bbj4FzXitGG6jvKhYw=="
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "8.1.0",
|
||||
|
|
|
@ -10,14 +10,16 @@
|
|||
"main": "main.js",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"auto-launch": "^5.0.6",
|
||||
"applescript": "^1.0.0",
|
||||
"os": "^0.1.2",
|
||||
"pidusage": "^3.0.2",
|
||||
"tar": "^7.4.3",
|
||||
"unbzip2-stream": "^1.4.3"
|
||||
"unbzip2-stream": "^1.4.3",
|
||||
"winreg": "^1.2.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/auto-launch": "^5.0.5",
|
||||
"@types/pidusage": "^2.0.5"
|
||||
"@types/pidusage": "^2.0.5",
|
||||
"@types/winreg": "^1.2.36"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue