Initial commit

This commit is contained in:
Scott E. Graves
2018-09-25 12:30:15 -05:00
commit a778b6dd25
52 changed files with 3450 additions and 0 deletions

416
electron.js Normal file
View File

@@ -0,0 +1,416 @@
// Modules to control application life and create native browser window
const {app, BrowserWindow, Tray, nativeImage, Menu} = require('electron');
const {ipcMain} = require('electron');
const path = require('path');
const url = require('url');
require('electron-debug')();
const os = require('os');
const helpers = require('./helpers');
const fs = require('fs');
const unzip = require('unzipper');
const AutoLaunch = require('auto-launch');
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;
let mainWindowTray;
let mountedPIDs = [];
function createWindow() {
// Create the browser window.
const height = process.env.ELECTRON_START_URL ? 340 : 320;
mainWindow = new BrowserWindow({
width: 425,
height: height,
resizable: false,
webPreferences: {
webSecurity: !process.env.ELECTRON_START_URL
}
});
// and load the index.html of the app.
const startUrl = process.env.ELECTRON_START_URL || url.format({
pathname: path.join(__dirname, '/build/index.html'),
protocol: 'file:',
slashes: true
});
mainWindow.loadURL(startUrl);
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
});
if (os.platform() === 'win32') {
const autoLauncher = new AutoLaunch({
name: 'Repertory UI',
path: path.resolve(path.join(app.getAppPath(), '..\\..\\repertory-ui.exe')),
});
const image = nativeImage.createFromPath(path.join(__dirname, '/build/icon.ico'));
const contextMenu = Menu.buildFromTemplate([
{
label: 'Visible', type: 'checkbox', click(item) {
if (item.checked) {
mainWindow.show();
if (mainWindow.isMinimized()) {
mainWindow.restore();
}
mainWindow.focus()
} else {
mainWindow.hide();
}
}
},
{
label: 'Auto-start', type: 'checkbox', click(item) {
if (item.checked) {
autoLauncher.enable();
} else {
autoLauncher.disable();
}
}
}
]);
contextMenu.items[0].checked = true;
autoLauncher.isEnabled()
.then((enabled) => {
contextMenu.items[1].checked = enabled;
mainWindowTray = new Tray(image);
mainWindowTray.setToolTip('Repertory UI');
mainWindowTray.setContextMenu(contextMenu)
})
.catch(() => {
app.quit();
});
}
}
const instanceLock = app.requestSingleInstanceLock();
if (!instanceLock) {
app.quit()
} else {
app.on('second-instance', () => {
if (mainWindow) {
if (mainWindow.isMinimized()) {
mainWindow.restore();
}
mainWindow.focus()
}
});
app.on('ready', createWindow);
app.on('window-all-closed', () => {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
});
app.on('activate', () => {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
});
}
ipcMain.on('check_installed', (event, data) => {
const dataDirectory = helpers.resolvePath(data.Directory);
const destination = path.join(dataDirectory, data.Version);
helpers
.getMissingDependencies(data.Dependencies)
.then((dependencies) => {
let exists = false;
try {
exists = fs.existsSync(destination) && fs.lstatSync(destination).isDirectory();
} catch (e) {
}
event.sender.send('check_installed_reply', {
data: {
Dependencies: dependencies,
Exists: exists,
Success: true,
Version: data.Version,
}
});
}).catch((e) => {
event.sender.send('check_installed_reply', {
data: {
Dependencies: [],
Error: e,
Success: false,
Version: data.Version,
}
});
});
});
ipcMain.on('delete_file', (event, data) => {
try {
if (fs.existsSync(data.FilePath)) {
fs.unlinkSync(data.FilePath);
}
} catch (e) {
}
});
ipcMain.on('detect_mounts', (event, data) => {
let driveLetters = {
Hyperspace: [],
Sia: [],
};
const grabDriveLetters = (hsLocation, siaLocation) => {
for (let i = 'c'.charCodeAt(0); i <= 'z'.charCodeAt(0); i++) {
const drive = (String.fromCharCode(i) + ':').toUpperCase();
if (!(hsLocation.startsWith(drive) || siaLocation.startsWith(drive))) {
try {
if (!fs.existsSync(drive)) {
driveLetters.Hyperspace.push(drive);
driveLetters.Sia.push(drive);
}
} catch (e) {
}
}
}
if (hsLocation.length > 0) {
if (!driveLetters.Hyperspace.find((driveLetter) => {
return driveLetter === hsLocation;
})) {
driveLetters.Hyperspace.push(hsLocation);
}
}
if (siaLocation.length > 0) {
if (!driveLetters.Sia.find((driveLetter) => {
return driveLetter === siaLocation;
})) {
driveLetters.Sia.push(siaLocation);
}
}
};
const dataDirectory = helpers.resolvePath(data.Directory);
helpers
.detectRepertoryMounts(dataDirectory, data.Version)
.then((results) => {
let hsLocation = results.Hyperspace.Location;
let siaLocation = results.Sia.Location;
if (os.platform() === 'win32') {
hsLocation = hsLocation.toUpperCase();
siaLocation = siaLocation.toUpperCase();
grabDriveLetters(hsLocation, siaLocation);
}
event.sender.send('detect_mounts_reply', {
data: {
DriveLetters: driveLetters,
Locations: {
Hyperspace: hsLocation,
Sia: siaLocation,
},
Success: true,
PIDS: {
Hyperspace: results.Hyperspace.PID,
Sia: results.Sia.PID,
}
}
});
})
.catch((err) => {
grabDriveLetters('', '');
event.sender.send('detect_mounts_reply', {
data: {
DriveLetters: driveLetters,
Error: err,
Success: false,
}
});
});
});
ipcMain.on('download_file', (event, data) => {
const dataDirectory = helpers.resolvePath(data.Directory);
const destination = path.join(dataDirectory, data.Filename);
helpers.downloadFile(data.URL, destination, (progress) => {
event.sender.send('download_file_progress', {
data: {
Destination: destination,
Progress: progress,
URL: data.URL,
}
});
}, (success, err) => {
event.sender.send('download_file_complete', {
data: {
Destination: destination,
Error: err,
Success: success,
URL: data.URL,
}
});
});
});
ipcMain.on('extract_release', (event, data) => {
const dataDirectory = helpers.resolvePath(data.Directory);
const destination = path.join(dataDirectory, data.Version);
helpers.mkDirByPathSync(destination);
const stream = fs.createReadStream(data.Source);
stream.pipe(unzip.Extract({ path: destination }))
.on('error', (e) => {
try {
helpers.removeDirectoryRecursively(destination);
} catch (e) {
}
stream.close();
event.sender.send('extract_release_complete', {
data: {
Error: e,
Source: data.Source,
Success: false,
}
});
})
.on('finish', () => {
stream.close();
event.sender.send('extract_release_complete', {
data: {
Source: data.Source,
Success: true,
}
});
});
});
ipcMain.on('get_platform', (event) => {
event.sender.send('get_platform_reply', {
data: os.platform()
});
});
ipcMain.on('get_state', (event, data) => {
const dataDirectory = helpers.resolvePath(data);
helpers.mkDirByPathSync(dataDirectory);
const configFile = path.join(dataDirectory, 'settings.json');
if (fs.existsSync(configFile)) {
event.sender.send('get_state_reply', {
data: JSON.parse(fs.readFileSync(configFile, 'utf8')),
});
} else {
event.sender.send('get_state_reply', {
data: null,
});
}
});
ipcMain.on('grab_releases', (event) => {
event.sender.send('grab_releases_reply');
});
ipcMain.on('grab_ui_releases', (event) => {
event.sender.send('grab_ui_releases_reply');
});
ipcMain.on('install_dependency', (event, data) => {
helpers
.executeAndWait(data.Source)
.then(()=> {
event.sender.send('install_dependency_reply', {
data: {
Source: data.Source,
Success: true,
}
});
})
.catch((e)=> {
event.sender.send('install_dependency_reply', {
data: {
Error: e,
Source: data.Source,
Success: false,
}
});
});
});
ipcMain.on('install_upgrade', (event, data) => {
helpers
.executeAsync(data.Source)
.then(()=> {
mainWindow.close();
})
.catch((e)=> {
event.sender.send('install_upgrade_reply', {
data: {
Error: e,
Source: data.Source,
Success: false,
}
});
});
});
ipcMain.on('mount_drive', (event, data) => {
const dataDirectory = helpers.resolvePath(data.Directory);
const errorHandler = (pid) => {
mountedPIDs.splice(mountedPIDs.indexOf(pid), 1);
event.sender.send('unmount_drive_reply', {
data: {
PID: -1,
StorageType: data.StorageType,
Success: false,
}
});
};
helpers.executeMount(dataDirectory, data.Version, data.StorageType, data.Location, (_, pid)=> {
errorHandler(pid);
})
.then(pid=> {
if (pid !== -1) {
mountedPIDs.push(pid);
}
event.sender.send('mount_drive_reply', {
data: {
PID: pid,
StorageType: data.StorageType,
Success: true,
}
});
})
.catch((_, pid) => {
errorHandler(pid);
});
});
ipcMain.on('save_state', (event, data) => {
const dataDirectory = helpers.resolvePath(data.Directory);
helpers.mkDirByPathSync(dataDirectory);
const configFile = path.join(dataDirectory, 'settings.json');
fs.writeFileSync(configFile, JSON.stringify(data.State), 'utf8');
});
ipcMain.on('unmount_drive', (event, data) => {
helpers.stopProcessByPID(data.PID)
.then((pid)=> {
if (mountedPIDs.indexOf(pid) === -1) {
event.sender.send('unmount_drive_reply');
}
})
.catch((e) => {
console.log(e);
});
});