Merged 1.0.8_branch into master
This commit is contained in:
@@ -1,5 +1,11 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 1.0.8
|
||||||
|
* \#8: Add tooltips to settings
|
||||||
|
* \#36: Add ability to select Linux distribution type if OS is unsupported
|
||||||
|
* \#37: Version check fails with incorrect message when VC runtime is missing
|
||||||
|
* Added additional WinFsp uninstall strings
|
||||||
|
|
||||||
## 1.0.7
|
## 1.0.7
|
||||||
* \#31: New installation displays 'Mount location is not set' on Windows
|
* \#31: New installation displays 'Mount location is not set' on Windows
|
||||||
* \#33: Add 'Microsoft Visual C++ Redistributable' as dependency installation on Windows
|
* \#33: Add 'Microsoft Visual C++ Redistributable' as dependency installation on Windows
|
||||||
|
|||||||
@@ -9,11 +9,10 @@ Repertory allows you to mount Sia and/or SiaPrime blockchain storage solutions v
|
|||||||
* SiaPrime >=1.4.0
|
* SiaPrime >=1.4.0
|
||||||
|
|
||||||
## Downloads
|
## Downloads
|
||||||
* **Repertory UI v1.0.7 Linux 64-bit** [<Primary\>](https://pixeldrain.com/u/thkU0RHP) [<Alternate\>](https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage)
|
* **Repertory UI v1.0.8 Linux 64-bit** [<Primary\>](https://pixeldrain.com/u/a1H78Dc_) [<Alternate\>](https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage)
|
||||||
* NOTE: Linux distributions require `fuse` and `libfuse` to be installed.
|
* NOTE: Linux distributions require `fuse` and `libfuse` to be installed.
|
||||||
* **Repertory UI v1.0.7 OS X 64-bit** [<Primary\>](https://pixeldrain.com/u/gBW5TSR0) [<Alternate\>](https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_mac.dmg)
|
* **Repertory UI v1.0.8 OS X 64-bit** [<Primary\>](https://pixeldrain.com/u/6NjT6uEl) [<Alternate\>](https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_mac.dmg)
|
||||||
* **Repertory UI v1.0.7 Windows 64-bit** [<Primary\>](https://pixeldrain.com/u/AcsttDQ_) [<Alternate\>](https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_win.exe)
|
* **Repertory UI v1.0.8 Windows 64-bit** [<Primary\>](https://pixeldrain.com/u/u_pP3IAk) [<Alternate\>](https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_win.exe)
|
||||||
* NOTE: Windows systems require [Microsoft Visual C++ Redistributable for Visual Studio 2015, 2017 and 2019](https://aka.ms/vs/16/release/vc_redist.x64.exe)
|
|
||||||
|
|
||||||
## Supported Platforms
|
## Supported Platforms
|
||||||
* OS X 64-bit
|
* OS X 64-bit
|
||||||
|
|||||||
17
package.json
17
package.json
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "repertory-ui",
|
"name": "repertory-ui",
|
||||||
"version": "1.0.7",
|
"version": "1.0.8",
|
||||||
"private": true,
|
"private": true,
|
||||||
"author": "scott.e.graves@protonmail.com",
|
"author": "scott.e.graves@protonmail.com",
|
||||||
"description": "GUI for Repertory - Repertory allows you to mount Sia and/or SiaPrime blockchain storage solutions via FUSE on Linux/OS X or via WinFSP on Windows.",
|
"description": "GUI for Repertory - Repertory allows you to mount Sia and/or SiaPrime blockchain storage solutions via FUSE on Linux/OS X or via WinFSP on Windows.",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-svg-core": "^1.2.19",
|
"@fortawesome/fontawesome-svg-core": "^1.2.22",
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.9.0",
|
"@fortawesome/free-solid-svg-icons": "^5.10.2",
|
||||||
"@fortawesome/react-fontawesome": "^0.1.4",
|
"@fortawesome/react-fontawesome": "^0.1.4",
|
||||||
"auto-launch": "^5.0.5",
|
"auto-launch": "^5.0.5",
|
||||||
"axios": "^0.18.1",
|
"axios": "^0.18.1",
|
||||||
@@ -14,10 +14,10 @@
|
|||||||
"font-awesome": "^4.7.0",
|
"font-awesome": "^4.7.0",
|
||||||
"node-schedule": "^1.3.2",
|
"node-schedule": "^1.3.2",
|
||||||
"randomstring": "^1.1.5",
|
"randomstring": "^1.1.5",
|
||||||
"react": "^16.8.6",
|
"react": "^16.9.0",
|
||||||
"react-dom": "^16.8.6",
|
"react-dom": "^16.9.0",
|
||||||
"react-loader-spinner": "^2.3.0",
|
"react-loader-spinner": "^2.3.0",
|
||||||
"react-redux": "^7.1.0",
|
"react-redux": "^7.1.1",
|
||||||
"react-scripts": "2.1.8",
|
"react-scripts": "2.1.8",
|
||||||
"react-tooltip": "^3.10.0",
|
"react-tooltip": "^3.10.0",
|
||||||
"redux": "^4.0.4",
|
"redux": "^4.0.4",
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"cross-env": "^5.2.0",
|
"cross-env": "^5.2.0",
|
||||||
"electron": "^4.2.8",
|
"electron": "^4.2.9",
|
||||||
"electron-builder": "^20.44.4",
|
"electron-builder": "^20.44.4",
|
||||||
"extract-text-webpack-plugin": "^3.0.2",
|
"extract-text-webpack-plugin": "^3.0.2",
|
||||||
"typescript": "^3.5.3",
|
"typescript": "^3.5.3",
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
"test": "react-scripts test",
|
"test": "react-scripts test",
|
||||||
"eject": "react-scripts eject",
|
"eject": "react-scripts eject",
|
||||||
"electron-dev": "cross-env ELECTRON_START_URL=http://localhost:3000 electron .",
|
"electron-dev": "cross-env ELECTRON_START_URL=http://localhost:3000 electron .",
|
||||||
"electron-dev-unix": "cross-env ELECTRON_START_URL=http://localhost:3000 electron $NODE_DEBUG_OPTION .",
|
"electron-dev-unix": "cross-env ELECTRON_START_URL=http://localhost:3000 electron .",
|
||||||
"pack": "npm run build && electron-builder --dir --x64",
|
"pack": "npm run build && electron-builder --dir --x64",
|
||||||
"dist": "npm run build && electron-builder --x64",
|
"dist": "npm run build && electron-builder --x64",
|
||||||
"dist-all": "npm run build && electron-builder --x64 --win --linux --mac",
|
"dist-all": "npm run build && electron-builder --x64 --win --linux --mac",
|
||||||
@@ -69,6 +69,7 @@
|
|||||||
"build/**/*",
|
"build/**/*",
|
||||||
"node_modules/**/*",
|
"node_modules/**/*",
|
||||||
"src/helpers.js",
|
"src/helpers.js",
|
||||||
|
"src/renderer/**/*",
|
||||||
"public/detect_linux.sh",
|
"public/detect_linux.sh",
|
||||||
"public/install_linux.sh"
|
"public/install_linux.sh"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,43 +1,48 @@
|
|||||||
// Modules to control application life and create native browser window
|
const {
|
||||||
|
app,
|
||||||
const {app, BrowserWindow, Tray, nativeImage, Menu, dialog} = require('electron');
|
BrowserWindow,
|
||||||
const {ipcMain} = require('electron');
|
dialog,
|
||||||
|
ipcMain,
|
||||||
|
Menu,
|
||||||
|
nativeImage,
|
||||||
|
Tray
|
||||||
|
} = require('electron');
|
||||||
|
const AutoLaunch = require('auto-launch');
|
||||||
const Constants = require('../src/constants');
|
const Constants = require('../src/constants');
|
||||||
|
const fs = require('fs');
|
||||||
|
const helpers = require('../src/helpers');
|
||||||
|
const os = require('os');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const url = require('url');
|
const url = require('url');
|
||||||
require('electron-debug/index')();
|
require('electron-debug/index')();
|
||||||
const os = require('os');
|
|
||||||
const helpers = require('../src/helpers');
|
|
||||||
const fs = require('fs');
|
|
||||||
const unzip = require('unzipper');
|
|
||||||
const AutoLaunch = require('auto-launch');
|
|
||||||
|
|
||||||
require.extensions['.sh'] = function (module, filename) {
|
require.extensions['.sh'] = function (module, filename) {
|
||||||
module.exports = fs.readFileSync(filename, 'utf8');
|
module.exports = fs.readFileSync(filename, 'utf8');
|
||||||
};
|
};
|
||||||
const detectScript = require('./detect_linux.sh');
|
const detectScript = require('./detect_linux.sh');
|
||||||
|
|
||||||
// Keep a global reference of the window object, if you don't, the window will
|
const AppIPC = require('../src/renderer/ipc/AppIPC');
|
||||||
// be closed automatically when the JavaScript object is garbage collected.
|
const ConfigIPC = require('../src/renderer/ipc/ConfigIPC');
|
||||||
let trayContextMenu;
|
const DaemonIPC = require('../src/renderer/ipc/DaemonIPC');
|
||||||
let mainWindow;
|
const DependencyIPC = require('../src/renderer/ipc/DependencyIPC');
|
||||||
let mainWindowTray;
|
const DownloadIPC = require('../src/renderer/ipc/DownloadIPC');
|
||||||
let mountedData = {};
|
const FilesystemIPC = require('../src/renderer/ipc/FilesystemIPC');
|
||||||
let mountedLocations = [];
|
const MountsIPC = require('../src/renderer/ipc/MountsIPC');
|
||||||
let expectedUnmount = {};
|
const PlatformIPC = require('../src/renderer/ipc/PlatformIPC');
|
||||||
let launchHidden = false;
|
const ReleaseIPC = require('../src/renderer/ipc/ReleaseIPC');
|
||||||
let firstMountCheck = true;
|
const StateIPC = require('../src/renderer/ipc/StateIPC');
|
||||||
let manualMountDetection = {};
|
const SystemIPC = require('../src/renderer/ipc/SystemIPC');
|
||||||
|
const UpgradeIPC = require('../src/renderer/ipc/UpgradeIPC');
|
||||||
|
|
||||||
let isShutdown = false;
|
let isShutdown = false;
|
||||||
let isQuiting = false;
|
let isQuiting = false;
|
||||||
let isInstalling = false;
|
let isInstalling = false;
|
||||||
|
let launchHidden = false;
|
||||||
|
let mainWindow;
|
||||||
|
let mainWindowTray;
|
||||||
|
let trayContextMenu;
|
||||||
|
|
||||||
app.on('before-quit', function () {
|
const closeApplication = () => {
|
||||||
isQuiting = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
function closeApplication() {
|
|
||||||
if (!isShutdown) {
|
if (!isShutdown) {
|
||||||
isShutdown = true;
|
isShutdown = true;
|
||||||
if (mainWindowTray) {
|
if (mainWindowTray) {
|
||||||
@@ -45,50 +50,23 @@ function closeApplication() {
|
|||||||
}
|
}
|
||||||
app.quit();
|
app.quit();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function setWindowVisibility(show) {
|
|
||||||
if (show) {
|
|
||||||
mainWindow.show();
|
|
||||||
if (os.platform() === 'darwin') {
|
|
||||||
app.dock.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mainWindow.isMinimized()) {
|
|
||||||
mainWindow.restore();
|
|
||||||
}
|
|
||||||
mainWindow.focus();
|
|
||||||
} else {
|
|
||||||
mainWindow.hide();
|
|
||||||
if (os.platform() === 'darwin') {
|
|
||||||
app.dock.hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trayContextMenu && mainWindowTray) {
|
|
||||||
trayContextMenu.items[0].checked = show;
|
|
||||||
mainWindowTray.setContextMenu(trayContextMenu)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const unmountAllDrives = () => {
|
|
||||||
// Reset mount states
|
|
||||||
for (const provider of Constants.PROVIDER_LIST) {
|
|
||||||
clearManualMountDetection(provider);
|
|
||||||
expectedUnmount[provider] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unmount all items
|
|
||||||
for (const i in mountedLocations) {
|
|
||||||
const data = mountedData[mountedLocations[i]];
|
|
||||||
helpers.stopMountProcessSync(data.Version, data.Provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
mountedLocations = [];
|
|
||||||
mountedData = {};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function createWindow() {
|
const configurePrimaryApp = () => {
|
||||||
|
app.on('second-instance', () => {
|
||||||
|
if (!isInstalling && mainWindow) {
|
||||||
|
setWindowVisibility(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on('ready', createWindow);
|
||||||
|
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
closeApplication();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const createWindow = () => {
|
||||||
loadUiSettings();
|
loadUiSettings();
|
||||||
|
|
||||||
let extra = {};
|
let extra = {};
|
||||||
@@ -140,7 +118,7 @@ function createWindow() {
|
|||||||
// when you should delete the corresponding element.
|
// when you should delete the corresponding element.
|
||||||
mainWindow = null;
|
mainWindow = null;
|
||||||
|
|
||||||
unmountAllDrives();
|
MountsIPC.unmountAllDrives();
|
||||||
});
|
});
|
||||||
|
|
||||||
const appPath = (os.platform() === 'win32') ? path.resolve(path.join(app.getAppPath(), '..\\..\\repertory-ui.exe')) :
|
const appPath = (os.platform() === 'win32') ? path.resolve(path.join(app.getAppPath(), '..\\..\\repertory-ui.exe')) :
|
||||||
@@ -203,39 +181,10 @@ function createWindow() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
mainWindow.loadURL(startUrl);
|
mainWindow.loadURL(startUrl);
|
||||||
}
|
|
||||||
|
|
||||||
let instanceLock = app.requestSingleInstanceLock();
|
|
||||||
const configurePrimaryApp = () => {
|
|
||||||
app.on('second-instance', () => {
|
|
||||||
if (!isInstalling && mainWindow) {
|
|
||||||
setWindowVisibility(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.on('ready', createWindow);
|
|
||||||
|
|
||||||
app.on('window-all-closed', () => {
|
|
||||||
closeApplication();
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
if (!instanceLock) {
|
|
||||||
setTimeout(() => {
|
|
||||||
if ((instanceLock = app.requestSingleInstanceLock())) {
|
|
||||||
configurePrimaryApp();
|
|
||||||
} else {
|
|
||||||
closeApplication();
|
|
||||||
}
|
|
||||||
}, 3000);
|
|
||||||
} else {
|
|
||||||
configurePrimaryApp();
|
|
||||||
}
|
|
||||||
|
|
||||||
const clearManualMountDetection = (provider) => {
|
const getMainWindow = () => {
|
||||||
if (manualMountDetection[provider]) {
|
return mainWindow;
|
||||||
clearInterval(manualMountDetection[provider]);
|
|
||||||
delete manualMountDetection[provider];
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadUiSettings = () => {
|
const loadUiSettings = () => {
|
||||||
@@ -244,49 +193,61 @@ const loadUiSettings = () => {
|
|||||||
if (fs.statSync(settingFile).isFile()) {
|
if (fs.statSync(settingFile).isFile()) {
|
||||||
const settings = JSON.parse(fs.readFileSync(settingFile, 'utf8'));
|
const settings = JSON.parse(fs.readFileSync(settingFile, 'utf8'));
|
||||||
launchHidden = settings.launch_hidden;
|
launchHidden = settings.launch_hidden;
|
||||||
|
PlatformIPC.setPlatformOverride(settings.platform_override);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const monitorMount = (sender, provider, version, pid, location) => {
|
|
||||||
manualMountDetection[provider] = setInterval(() => {
|
|
||||||
helpers
|
|
||||||
.detectRepertoryMounts(version)
|
|
||||||
.then(result => {
|
|
||||||
if (result[provider].PID !== pid) {
|
|
||||||
if (result[provider].PID === -1) {
|
|
||||||
clearManualMountDetection(provider);
|
|
||||||
sender.send(Constants.IPC_Unmount_Drive_Reply, {
|
|
||||||
data: {
|
|
||||||
Expected: expectedUnmount[provider],
|
|
||||||
Location: location,
|
|
||||||
Provider: provider,
|
|
||||||
Error: Error(provider + ' Unmounted').toString(),
|
|
||||||
Success: false,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
pid = result[provider].PID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(e => {
|
|
||||||
console.log(e);
|
|
||||||
});
|
|
||||||
},6000);
|
|
||||||
};
|
|
||||||
|
|
||||||
const saveUiSettings = () => {
|
const saveUiSettings = () => {
|
||||||
const settingFile = path.join(helpers.getDataDirectory(), 'ui.json');
|
const settingFile = path.join(helpers.getDataDirectory(), 'ui.json');
|
||||||
try {
|
try {
|
||||||
fs.writeFileSync(settingFile, JSON.stringify({
|
fs.writeFileSync(settingFile, JSON.stringify({
|
||||||
launch_hidden: launchHidden,
|
launch_hidden: launchHidden,
|
||||||
|
platform_override: PlatformIPC.getPlatformOverride(),
|
||||||
}), 'utf-8');
|
}), 'utf-8');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const setIsInstalling = installing => {
|
||||||
|
isInstalling = installing;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setTrayImage = driveInUse => {
|
||||||
|
let image;
|
||||||
|
if (driveInUse) {
|
||||||
|
image = nativeImage.createFromPath(path.join(__dirname, os.platform() === 'darwin' ? '../build/logo_both_mac.png' : '../build/logo_both.png'));
|
||||||
|
} else {
|
||||||
|
image = nativeImage.createFromPath(path.join(__dirname, os.platform() === 'darwin' ? '../build/logo_mac.png' : '../build/logo.png'));
|
||||||
|
}
|
||||||
|
mainWindowTray.setImage(image);
|
||||||
|
};
|
||||||
|
|
||||||
|
const setWindowVisibility = show => {
|
||||||
|
if (show) {
|
||||||
|
mainWindow.show();
|
||||||
|
if (os.platform() === 'darwin') {
|
||||||
|
app.dock.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mainWindow.isMinimized()) {
|
||||||
|
mainWindow.restore();
|
||||||
|
}
|
||||||
|
mainWindow.focus();
|
||||||
|
} else {
|
||||||
|
mainWindow.hide();
|
||||||
|
if (os.platform() === 'darwin') {
|
||||||
|
app.dock.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trayContextMenu && mainWindowTray) {
|
||||||
|
trayContextMenu.items[0].checked = show;
|
||||||
|
mainWindowTray.setContextMenu(trayContextMenu)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const standardIPCReply = (event, channel, data, error) => {
|
const standardIPCReply = (event, channel, data, error) => {
|
||||||
if (mainWindow) {
|
if (mainWindow) {
|
||||||
event.sender.send(channel, {
|
event.sender.send(channel, {
|
||||||
@@ -299,677 +260,36 @@ const standardIPCReply = (event, channel, data, error) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ipcMain.on(Constants.IPC_Browse_Directory + '_sync', (event, data) => {
|
|
||||||
dialog.showOpenDialog(mainWindow, {
|
|
||||||
defaultPath: data.Location,
|
|
||||||
properties: ['openDirectory'],
|
app.on('before-quit', function () {
|
||||||
title: data.Title,
|
isQuiting = true;
|
||||||
}, (filePaths) => {
|
});
|
||||||
if (filePaths && (filePaths.length > 0)) {
|
|
||||||
event.returnValue = filePaths[0];
|
let instanceLock = app.requestSingleInstanceLock();
|
||||||
|
if (!instanceLock) {
|
||||||
|
setTimeout(() => {
|
||||||
|
if ((instanceLock = app.requestSingleInstanceLock())) {
|
||||||
|
configurePrimaryApp();
|
||||||
} else {
|
} else {
|
||||||
event.returnValue = '';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on(Constants.IPC_Check_Daemon_Version, (event, data) => {
|
|
||||||
helpers
|
|
||||||
.checkDaemonVersion(data.Version, data.Provider)
|
|
||||||
.then(code => {
|
|
||||||
standardIPCReply(event, Constants.IPC_Check_Daemon_Version_Reply, {
|
|
||||||
Valid: (code === 0),
|
|
||||||
Code: code,
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(e => {
|
|
||||||
standardIPCReply(event, Constants.IPC_Check_Daemon_Version_Reply, {
|
|
||||||
Valid: false,
|
|
||||||
}, e);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on(Constants.IPC_Check_Daemon_Version + '_sync', (event, data) => {
|
|
||||||
helpers
|
|
||||||
.checkDaemonVersion(data.Version, data.Provider)
|
|
||||||
.then(code => {
|
|
||||||
event.returnValue = {
|
|
||||||
data: {
|
|
||||||
Success: true,
|
|
||||||
Valid: (code === 0),
|
|
||||||
Code: code,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.catch(e => {
|
|
||||||
event.returnValue = {
|
|
||||||
data: {
|
|
||||||
Error: e.toString(),
|
|
||||||
Success: false,
|
|
||||||
Valid: false
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on(Constants.IPC_Check_Dependency_Installed, (event, data) => {
|
|
||||||
try {
|
|
||||||
const exists = fs.lstatSync(data.File).isFile();
|
|
||||||
standardIPCReply(event, Constants.IPC_Check_Dependency_Installed_Reply, {
|
|
||||||
data: {
|
|
||||||
Exists: exists,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
standardIPCReply(event, Constants.IPC_Check_Dependency_Installed_Reply, {
|
|
||||||
data : {
|
|
||||||
Exists: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on(Constants.IPC_Check_Dependency_Installed + '_sync', (event, data) => {
|
|
||||||
try {
|
|
||||||
const ls = fs.lstatSync(data.File);
|
|
||||||
event.returnValue = {
|
|
||||||
data: {
|
|
||||||
Exists: ls.isFile() || ls.isSymbolicLink(),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
} catch (e) {
|
|
||||||
event.returnValue = {
|
|
||||||
data: {
|
|
||||||
Exists: false
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on(Constants.IPC_Check_Installed, (event, data) => {
|
|
||||||
const destination = path.join(helpers.getDataDirectory(), data.Version);
|
|
||||||
helpers
|
|
||||||
.getMissingDependencies(data.Dependencies)
|
|
||||||
.then((dependencies) => {
|
|
||||||
let exists = false;
|
|
||||||
try {
|
|
||||||
exists = fs.existsSync(destination) && fs.lstatSync(destination).isDirectory();
|
|
||||||
} catch (e) {
|
|
||||||
}
|
|
||||||
standardIPCReply(event, Constants.IPC_Check_Installed_Reply, {
|
|
||||||
Dependencies: dependencies,
|
|
||||||
Exists: exists,
|
|
||||||
Version: data.Version,
|
|
||||||
});
|
|
||||||
}).catch(error => {
|
|
||||||
standardIPCReply(event, Constants.IPC_Check_Installed_Reply, {
|
|
||||||
Dependencies: [],
|
|
||||||
Version: data.Version,
|
|
||||||
}, error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on(Constants.IPC_Check_Mount_Location + '_sync', (event, data) => {
|
|
||||||
let response = {
|
|
||||||
Success: true,
|
|
||||||
Error: ''
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (fs.existsSync(data.Location) && fs.statSync(data.Location).isDirectory()) {
|
|
||||||
if (fs.readdirSync(data.Location).length !== 0) {
|
|
||||||
response.Success = false;
|
|
||||||
response.Error = 'Directory not empty: ' + data.Location;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
response.Success = false;
|
|
||||||
response.Error = 'Directory not found: ' + data.Location;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
response.Success = false;
|
|
||||||
response.Error = e.toString();
|
|
||||||
}
|
|
||||||
event.returnValue = response;
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on(Constants.IPC_Delete_File, (event, data) => {
|
|
||||||
try {
|
|
||||||
if (fs.existsSync(data.FilePath)) {
|
|
||||||
fs.unlinkSync(data.FilePath);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on(Constants.IPC_Delete_File + '_sync', (event, data) => {
|
|
||||||
try {
|
|
||||||
if (fs.existsSync(data.FilePath)) {
|
|
||||||
fs.unlinkSync(data.FilePath);
|
|
||||||
}
|
|
||||||
event.returnValue = {
|
|
||||||
data: true,
|
|
||||||
};
|
|
||||||
} catch (e) {
|
|
||||||
event.returnValue = {
|
|
||||||
data: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on(Constants.IPC_Detect_Mounts, (event, data) => {
|
|
||||||
let driveLetters = {};
|
|
||||||
for (const provider of Constants.PROVIDER_LIST) {
|
|
||||||
driveLetters[provider] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const grabDriveLetters = (locations) => {
|
|
||||||
for (let i = 'c'.charCodeAt(0); i <= 'z'.charCodeAt(0); i++) {
|
|
||||||
const drive = (String.fromCharCode(i) + ':').toUpperCase();
|
|
||||||
let driveInUse;
|
|
||||||
if (Object.keys(locations).length > 0) {
|
|
||||||
for (const provider of Constants.PROVIDER_LIST) {
|
|
||||||
driveInUse = locations[provider].startsWith(drive);
|
|
||||||
if (driveInUse)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!driveInUse) {
|
|
||||||
try {
|
|
||||||
if (!fs.existsSync(drive)) {
|
|
||||||
for (const provider of Constants.PROVIDER_LIST) {
|
|
||||||
driveLetters[provider].push(drive);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Object.keys(locations).length > 0) {
|
|
||||||
for (const provider of Constants.PROVIDER_LIST) {
|
|
||||||
if (locations[provider].length > 0) {
|
|
||||||
if (!driveLetters[provider].find((driveLetter) => {
|
|
||||||
return driveLetter === locations[provider];
|
|
||||||
})) {
|
|
||||||
driveLetters[provider].push(locations[provider]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const setImage = (locations) => {
|
|
||||||
let driveInUse;
|
|
||||||
if (Object.keys(locations).length > 0) {
|
|
||||||
for (const provider of Constants.PROVIDER_LIST) {
|
|
||||||
driveInUse = locations[provider].length > 0;
|
|
||||||
if (driveInUse)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let image;
|
|
||||||
if (driveInUse) {
|
|
||||||
image = nativeImage.createFromPath(path.join(__dirname, os.platform() === 'darwin' ? '../build/logo_both_mac.png' : '../build/logo_both.png'));
|
|
||||||
} else {
|
|
||||||
image = nativeImage.createFromPath(path.join(__dirname, os.platform() === 'darwin' ? '../build/logo_mac.png' : '../build/logo.png'));
|
|
||||||
}
|
|
||||||
|
|
||||||
mainWindowTray.setImage(image);
|
|
||||||
};
|
|
||||||
|
|
||||||
helpers
|
|
||||||
.detectRepertoryMounts(data.Version)
|
|
||||||
.then((results) => {
|
|
||||||
let storageData = {};
|
|
||||||
let locations = {};
|
|
||||||
for (const provider of Constants.PROVIDER_LIST) {
|
|
||||||
storageData[provider] = results[provider] ? results[provider] : {
|
|
||||||
Active: false,
|
|
||||||
Location: '',
|
|
||||||
PID: -1,
|
|
||||||
};
|
|
||||||
locations[provider] = storageData[provider].Location;
|
|
||||||
|
|
||||||
if (storageData[provider].PID !== -1) {
|
|
||||||
expectedUnmount[provider] = false;
|
|
||||||
if (firstMountCheck) {
|
|
||||||
monitorMount(event.sender, provider, data.Version, storageData[provider].PID, storageData[provider].Location);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (os.platform() === 'win32') {
|
|
||||||
grabDriveLetters(locations);
|
|
||||||
}
|
|
||||||
|
|
||||||
setImage(locations);
|
|
||||||
if (firstMountCheck) {
|
|
||||||
firstMountCheck = false;
|
|
||||||
}
|
|
||||||
standardIPCReply(event, Constants.IPC_Detect_Mounts_Reply, {
|
|
||||||
DriveLetters: driveLetters,
|
|
||||||
Locations: locations,
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
if (os.platform() === 'win32') {
|
|
||||||
grabDriveLetters({});
|
|
||||||
}
|
|
||||||
setImage({});
|
|
||||||
standardIPCReply(event, Constants.IPC_Detect_Mounts_Reply, {
|
|
||||||
DriveLetters: driveLetters,
|
|
||||||
}, error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on(Constants.IPC_Download_File, (event, data) => {
|
|
||||||
const destination = path.join(helpers.getDataDirectory(), data.Filename);
|
|
||||||
helpers.downloadFile(data.URL, destination, (progress) => {
|
|
||||||
standardIPCReply(event, Constants.IPC_Download_File_Progress, {
|
|
||||||
Destination: destination,
|
|
||||||
Progress: progress,
|
|
||||||
URL: data.URL,
|
|
||||||
});
|
|
||||||
}, error => {
|
|
||||||
standardIPCReply(event, Constants.IPC_Download_File_Complete, {
|
|
||||||
Destination: destination,
|
|
||||||
URL: data.URL,
|
|
||||||
}, error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on(Constants.IPC_Extract_Release, (event, data) => {
|
|
||||||
const destination = path.join(helpers.getDataDirectory(), data.Version);
|
|
||||||
helpers.mkDirByPathSync(destination);
|
|
||||||
|
|
||||||
const stream = fs.createReadStream(data.Source);
|
|
||||||
stream
|
|
||||||
.pipe(unzip.Extract({ path: destination }))
|
|
||||||
.on('error', error => {
|
|
||||||
try {
|
|
||||||
helpers.removeDirectoryRecursively(destination);
|
|
||||||
} catch (e) {
|
|
||||||
}
|
|
||||||
stream.close();
|
|
||||||
standardIPCReply(event, Constants.IPC_Extract_Release_Complete, {
|
|
||||||
Source: data.Source,
|
|
||||||
}, error);
|
|
||||||
})
|
|
||||||
.on('finish', () => {
|
|
||||||
stream.close();
|
|
||||||
if (os.platform() !== 'win32') {
|
|
||||||
helpers
|
|
||||||
.executeAndWait("chmod +x \"" + path.join(destination, 'repertory') + "\"")
|
|
||||||
.then(() => {
|
|
||||||
standardIPCReply(event, Constants.IPC_Extract_Release_Complete, {
|
|
||||||
Source: data.Source,
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
standardIPCReply(event, Constants.IPC_Extract_Release_Complete, {
|
|
||||||
Source: data.Source,
|
|
||||||
}, error);
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
standardIPCReply(event, Constants.IPC_Extract_Release_Complete, {
|
|
||||||
Source: data.Source,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on(Constants.IPC_Get_Config, (event, data) => {
|
|
||||||
helpers
|
|
||||||
.getConfig(data.Version, data.Provider)
|
|
||||||
.then((data) => {
|
|
||||||
if (data.Code === 0) {
|
|
||||||
standardIPCReply(event, Constants.IPC_Get_Config_Reply, {
|
|
||||||
Config: data.Data,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
standardIPCReply(event, Constants.IPC_Get_Config_Reply, {}, data.Code);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
standardIPCReply(event, Constants.IPC_Get_Config_Reply, {}, error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on(Constants.IPC_Get_Config_Template, (event, data) => {
|
|
||||||
helpers
|
|
||||||
.getConfigTemplate(data.Version, data.Provider)
|
|
||||||
.then((data) => {
|
|
||||||
standardIPCReply(event, Constants.IPC_Get_Config_Template_Reply, {
|
|
||||||
Template: data,
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
standardIPCReply(event, Constants.IPC_Get_Config_Template_Reply, {}, error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on(Constants.IPC_Get_Platform, (event) => {
|
|
||||||
const sendResponse = (appPlatform, platform) => {
|
|
||||||
event.sender.send(Constants.IPC_Get_Platform_Reply, {
|
|
||||||
AppPlatform: appPlatform,
|
|
||||||
Platform: platform,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const platform = os.platform();
|
|
||||||
if (platform === 'linux') {
|
|
||||||
const scriptFile = path.join(os.tmpdir(), 'repertory_detect_linux.sh');
|
|
||||||
fs.writeFileSync(scriptFile, detectScript);
|
|
||||||
|
|
||||||
helpers
|
|
||||||
.executeScript(scriptFile)
|
|
||||||
.then(data => {
|
|
||||||
let appPlatform = data.replace(/(\r\n|\n|\r)/gm,"");
|
|
||||||
if (appPlatform === 'unknown') {
|
|
||||||
helpers
|
|
||||||
.downloadFile(Constants.LINUX_DETECT_SCRIPT_URL, scriptFile, null, err => {
|
|
||||||
if (err) {
|
|
||||||
sendResponse(appPlatform, platform);
|
|
||||||
} else {
|
|
||||||
helpers
|
|
||||||
.executeScript(scriptFile)
|
|
||||||
.then(data => {
|
|
||||||
appPlatform = data.replace(/(\r\n|\n|\r)/gm, "");
|
|
||||||
sendResponse(appPlatform, platform);
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
sendResponse(appPlatform, platform);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
sendResponse(appPlatform, platform);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
sendResponse(platform, platform);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
sendResponse(platform, platform);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on(Constants.IPC_Get_State, event => {
|
|
||||||
helpers.mkDirByPathSync(helpers.getDataDirectory());
|
|
||||||
const configFile = path.join(helpers.getDataDirectory(), 'settings.json');
|
|
||||||
if (fs.existsSync(configFile)) {
|
|
||||||
event.sender.send(Constants.IPC_Get_State_Reply, {
|
|
||||||
data: JSON.parse(fs.readFileSync(configFile, 'utf8')),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
event.sender.send(Constants.IPC_Get_State_Reply, {
|
|
||||||
data: null,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on(Constants.IPC_Install_Dependency, (event, data) => {
|
|
||||||
if (data.Source.toLowerCase().endsWith('.dmg')) {
|
|
||||||
helpers
|
|
||||||
.executeAsync('open', ['-a', 'Finder', '-W', data.Source])
|
|
||||||
.then(() => {
|
|
||||||
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
|
||||||
Source: data.Source,
|
|
||||||
URL: data.URL,
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(error=> {
|
|
||||||
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
|
||||||
Source: data.Source,
|
|
||||||
URL: data.URL,
|
|
||||||
}, error);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const execInstall = () => {
|
|
||||||
helpers
|
|
||||||
.executeAndWait(data.Source)
|
|
||||||
.then(() => {
|
|
||||||
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
|
||||||
Source: data.Source,
|
|
||||||
URL: data.URL,
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
|
||||||
Source: data.Source,
|
|
||||||
URL: data.URL,
|
|
||||||
}, error);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
if (data.IsWinFSP) {
|
|
||||||
helpers
|
|
||||||
.performWindowsUninstall(["WinFsp 2019.3 B1", "WinFsp 2019.3 B2"])
|
|
||||||
.then(uninstalled => {
|
|
||||||
if (uninstalled) {
|
|
||||||
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
|
||||||
RebootRequired: true,
|
|
||||||
Source: data.Source,
|
|
||||||
URL: data.URL,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
execInstall();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
|
||||||
Source: data.Source,
|
|
||||||
URL: data.URL,
|
|
||||||
}, error);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
execInstall();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on(Constants.IPC_Install_Upgrade, (event, data) => {
|
|
||||||
let allowSkipVerification = true;
|
|
||||||
|
|
||||||
unmountAllDrives();
|
|
||||||
|
|
||||||
let tempSig;
|
|
||||||
let tempPub;
|
|
||||||
const cleanupFiles = () => {
|
|
||||||
try {
|
|
||||||
if (tempSig) {
|
|
||||||
fs.unlinkSync(tempSig);
|
|
||||||
}
|
|
||||||
if (tempPub) {
|
|
||||||
fs.unlinkSync(tempPub);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const errorHandler = err => {
|
|
||||||
cleanupFiles();
|
|
||||||
standardIPCReply(event, Constants.IPC_Install_Upgrade_Reply, {
|
|
||||||
AllowSkipVerification: allowSkipVerification,
|
|
||||||
Source: data.Source,
|
|
||||||
}, err);
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO Enable verification in 1.0.4
|
|
||||||
const hasSignature = false;//!data.SkipVerification && data.Signature && (data.Signature.length > 0);
|
|
||||||
const hasHash = false;//!data.SkipVerification && data.Sha256 && (data.Sha256.length > 0);
|
|
||||||
if (hasSignature) {
|
|
||||||
try {
|
|
||||||
const files = helpers.createSignatureFiles(data.Signature, Constants.DEV_PUBLIC_KEY);
|
|
||||||
tempPub = files.PublicKeyFile;
|
|
||||||
tempSig = files.SignatureFile;
|
|
||||||
} catch (e) {
|
|
||||||
errorHandler(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let command;
|
|
||||||
let args;
|
|
||||||
const platform = os.platform();
|
|
||||||
if (platform === 'win32') {
|
|
||||||
command = data.Source;
|
|
||||||
} else if (platform === 'darwin') {
|
|
||||||
command = 'open';
|
|
||||||
args = ['-a', 'Finder', data.Source];
|
|
||||||
} else if (platform === 'linux') {
|
|
||||||
try {
|
|
||||||
command = data.Source;
|
|
||||||
fs.chmodSync(command, '750');
|
|
||||||
} catch (e) {
|
|
||||||
errorHandler(e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
errorHandler(Error('Platform not supported: ' + os.platform()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (command) {
|
|
||||||
const executeInstall = () => {
|
|
||||||
isInstalling = true;
|
|
||||||
helpers
|
|
||||||
.executeAsync(command, args)
|
|
||||||
.then(() => {
|
|
||||||
cleanupFiles();
|
|
||||||
standardIPCReply(event, Constants.IPC_Install_Upgrade_Reply)
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
isInstalling = false;
|
|
||||||
errorHandler(error);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
if (hasSignature) {
|
|
||||||
helpers
|
|
||||||
.verifySignature(data.Source, tempSig, tempPub)
|
|
||||||
.then(() => {
|
|
||||||
executeInstall();
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
errorHandler(Error('Failed to verify installation package signature'));
|
|
||||||
});
|
|
||||||
} else if (hasHash) {
|
|
||||||
helpers
|
|
||||||
.verifyHash(data.Source, data.Sha256)
|
|
||||||
.then(()=> {
|
|
||||||
executeInstall();
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
errorHandler(Error('Failed to verify installation package hash'));
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
if (platform === 'darwin') {
|
|
||||||
setTimeout(executeInstall, 3000);
|
|
||||||
} else {
|
|
||||||
executeInstall();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
errorHandler(Error('Unsupported upgrade: ' + data.Source));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on(Constants.IPC_Mount_Drive, (event, data) => {
|
|
||||||
expectedUnmount[data.Provider] = false;
|
|
||||||
|
|
||||||
if (mountedLocations.indexOf(data.Location) !== -1) {
|
|
||||||
console.log(data.Provider + ' already mounted: ' + data.Location);
|
|
||||||
} else {
|
|
||||||
mountedLocations.push(data.Location);
|
|
||||||
mountedData[data.Location] = {
|
|
||||||
Version: data.Version,
|
|
||||||
Provider: data.Provider,
|
|
||||||
};
|
|
||||||
const errorHandler = (pid, error) => {
|
|
||||||
if (mountedLocations.indexOf(data.Location) !== -1) {
|
|
||||||
mountedLocations.splice(mountedLocations.indexOf(data.Location), 1);
|
|
||||||
delete mountedData[data.Location];
|
|
||||||
}
|
|
||||||
|
|
||||||
standardIPCReply(event, Constants.IPC_Unmount_Drive_Reply, {
|
|
||||||
Expected: expectedUnmount[data.Provider],
|
|
||||||
Location: data.Location,
|
|
||||||
Provider: data.Provider,
|
|
||||||
}, error || Error(data.Provider + ' Unmounted'));
|
|
||||||
};
|
|
||||||
helpers
|
|
||||||
.executeMount(data.Version, data.Provider, data.Location, data.NoConsoleSupported, (error, pid) => {
|
|
||||||
errorHandler(pid, error);
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
standardIPCReply(event, Constants.IPC_Mount_Drive_Reply, {
|
|
||||||
Provider: data.Provider,
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
errorHandler(-1, error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on(Constants.IPC_Reboot_System, () => {
|
|
||||||
if (os.platform() === 'win32') {
|
|
||||||
helpers.executeAsync('shutdown.exe', ['/r', '/t', '30']);
|
|
||||||
}
|
|
||||||
closeApplication();
|
closeApplication();
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on(Constants.IPC_Save_State, (event, data) => {
|
|
||||||
helpers.mkDirByPathSync(helpers.getDataDirectory());
|
|
||||||
const configFile = path.join(helpers.getDataDirectory(), 'settings.json');
|
|
||||||
fs.writeFileSync(configFile, JSON.stringify(data.State), 'utf8');
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on(Constants.IPC_Set_Config_Values, (event, data) => {
|
|
||||||
const setConfigValue = (i) => {
|
|
||||||
if (i < data.Items.length) {
|
|
||||||
helpers
|
|
||||||
.setConfigValue(data.Items[i].Name, data.Items[i].Value, data.Provider, data.Version)
|
|
||||||
.then(() => {
|
|
||||||
setConfigValue(++i);
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
setConfigValue(++i);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
standardIPCReply(event, Constants.IPC_Set_Config_Values_Reply, {});
|
|
||||||
}
|
}
|
||||||
};
|
}, 3000);
|
||||||
setConfigValue(0);
|
} else {
|
||||||
});
|
configurePrimaryApp();
|
||||||
|
}
|
||||||
|
|
||||||
ipcMain.on(Constants.IPC_Shutdown, () => {
|
|
||||||
closeApplication();
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on(Constants.IPC_Show_Window, () => {
|
AppIPC.addListeners(ipcMain, closeApplication, setWindowVisibility);
|
||||||
setWindowVisibility(true);
|
ConfigIPC.addListeners(ipcMain, standardIPCReply);
|
||||||
});
|
DaemonIPC.addListeners(ipcMain, standardIPCReply);
|
||||||
|
DependencyIPC.addListeners(ipcMain, standardIPCReply);
|
||||||
ipcMain.on(Constants.IPC_Show_Window + '_sync', event => {
|
DownloadIPC.addListeners(ipcMain, standardIPCReply);
|
||||||
setWindowVisibility(true);
|
FilesystemIPC.addListeners(ipcMain, getMainWindow, dialog);
|
||||||
event.returnValue = true;
|
MountsIPC.addListeners(ipcMain, setTrayImage, standardIPCReply);
|
||||||
});
|
PlatformIPC.addListeners(ipcMain, detectScript, saveUiSettings);
|
||||||
|
ReleaseIPC.addListeners(ipcMain, standardIPCReply);
|
||||||
ipcMain.on(Constants.IPC_Unmount_All_Drives, (event, data) => {
|
StateIPC.addListeners(ipcMain);
|
||||||
unmountAllDrives();
|
SystemIPC.addListeners(ipcMain, closeApplication);
|
||||||
standardIPCReply(event, Constants.IPC_Unmount_All_Drives_Reply);
|
UpgradeIPC.addListeners(ipcMain, setIsInstalling, MountsIPC.unmountAllDrives, standardIPCReply);
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on(Constants.IPC_Unmount_Drive, (event, data) => {
|
|
||||||
clearManualMountDetection(data.Provider);
|
|
||||||
|
|
||||||
expectedUnmount[data.Provider] = true;
|
|
||||||
helpers
|
|
||||||
.stopMountProcess(data.Version, data.Provider)
|
|
||||||
.then(result => {
|
|
||||||
console.log(result);
|
|
||||||
})
|
|
||||||
.catch(e => {
|
|
||||||
console.log(e);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
192
releases.json
192
releases.json
@@ -1,220 +1,220 @@
|
|||||||
{
|
{
|
||||||
"Locations": {
|
"Locations": {
|
||||||
"arch": {
|
"arch": {
|
||||||
"1.0.7": {
|
"1.0.8": {
|
||||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||||
"urls": [
|
"urls": [
|
||||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"centos7": {
|
"centos7": {
|
||||||
"1.0.7": {
|
"1.0.8": {
|
||||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||||
"urls": [
|
"urls": [
|
||||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"darwin": {
|
"darwin": {
|
||||||
"1.0.7": {
|
"1.0.8": {
|
||||||
"sha256": "e4f5cf9765224d4c25472310089e0996f59772573dc59c1baa065810a16c19ba",
|
"sha256": "fa978eeb6f5456c1fcea902cafb039eeda6d13f93770150564a0253341cb3d63",
|
||||||
"sig": "A11yvEkveuPo2yyJaDhw9xt/+/xw7/4T3D2Kd/Px1LwCREio25gCr5BWPSIef5yALCS1nDHIzG8CIaDS+OHc4w87YAqIqVOcQaDi2E2t1El7B1noW8yXs+Ew/Ro3AwqN0lnJrtr8fZWVFKqxUTvxLLOJmh5jiud9vdrFzlaI2MNEvC0dY62T0hS1o4uij5/NIXHrZJuz43sa8WftL1RSD/z0lQELF43MaFYCfcDeyCZn2N/htyyvlOEi0bVbjZg1N2cyWAhKbAZu47t5Z5uyoV+VYcIPJT0IsGK2Vr/Js6ziSr3IqdpWl44ztXRLGp4Es17MMnjne30AbhOt+qIOPIcwyRQ7ENEu6MEgT3nA35y5fd1YK7Nz3IkJMxMe1XwyjLE82MgXg9tywb46zKeEJ9zzWk4No71Z6CPwo7kGEl7kzKLw61GYL+1AY+o2dmiDrO+l+DmTzHqGJ3GqBuCnG+5yKM+6klEKU+zmtuaQsPHamY5YLa302G59ecnH90+XIP9veB8jj0ipID8UoGZqJNZgUvkNN3CFoV3TMqA01M5VH7xqWTGPib+aoxCwFsaYiaKTbZBYjw9PQ/ECGXakfX3YpkR1YniNq+Y6UHpfnQNznqZBC+lrud67R2SmRN5JO6wIKiqaKwUT5B5k1ze3Ltdfb1i8bkhk1yNJZBmnr3MA4n5w7wvS/Fw4Uq1zkeUb+No4lP3nH1TcAwU+shesB44MUaLiTlnWUii1AGivEsTtqNp1YoSKVdX1c5GOia0F3iJBqyO1T++bgRpm433AkwaFLqvOr66CirCRtelhZaZtZPStBXATzSBlXEn1J2NbEA6rS185Twco4Cp92+otMFfACm59Ew94E0I8/NSXWEtGkaF7OadMdjS9WPf/5jHWoMnqA8dpYZZXXnZN3xU1eUaVxlu7bdoQxwjllkVMElLp30nOE7Gg2sHuV9xTZ5L2zaueDhZToiItZqce1mlG7zqN0fPlJ8SY0V5nGkm91L90rVi7/9YLKa3jE63Kkv6rMd/o1MAqaFIu1KOgcEbVzexIh1f3ikphIfgxT0PdEuhYa5OGhXwHI/7oaNT8I9XebFRVXCIRHoaYz+zxqCIDQVqDWnW62aTKBwdmGBAp0b9RsCNekCheR2SHfiJi2qAvMWbQR1c3MZpC9A5xAIJZ+FJpTqpagR5U09RIkMjfewpCrfXQYdIWXDJ7CDm2pYGxVn2IIrxvc5kpbsh7VpvNh8bA/TaHyxEKqRWFbua9JZcGP17jliBx3R2ZLt45BYET63Z7z6C8A/Js4bfEspXDd8KfF+rmu83crc1txaJx4WRpbVx8KTLlU/b9o+B5PaoV+BTt/CV3Jgf6uLLXKLB/EXU=",
|
"sig": "CfzV0Jl/Saq6Yqtwz21Qm5F7C/geGtmotifZrUcSFpGTaniYbtWtwJSap1tAep1EzL43l4wtxmpDM9EJ3qkquD6JMQjKK89twYotzMoWneZyyEB7obhpi/M3mfih8fYrPCgxaUkVm4DZ4DNbZn2GwjMmdCV698OnUfg2PKhVH4LnjqekqOEsU02B/cvlym2zPLLoEhjJoL8+s2ICIV3WBVDHpcF4ZF3lnI8HgfjjpvhQ+V8LQCk+LQTzIwwBDj6C1sH5V9om7ZUyZZEQk8ALcvo6EJHhhOoQ6extou5NIfBSkDir9IJW8hnTVykgYwoFXSUSAf7tvLn/fx+xpvp27hh+MQqA7KPhVyUD0I2qobm87KV9RBUuW0eqC/ijkcfacyhBnTEikSrHbew3cy69KtBTs4xaicIErQogJXcRfn0bQsVYxk1H3lRyoZnnaFliLwBw/8NQnrvjZqMiqlVXijZj6w0gWZjfrJ/s7UZ0K+yofVAyp3Qzf8JsdlUeCS+lqsv65ANWOBrUeF2Tz2neIWWISnVADmBMeacp/Xuz/bwuGLc4FnMWyhIBjBGwYLBTiaq0nk0oC6wn7a+LZoib8WtU9CAJ4v82k0e8YgiwBDPZPfU03wWWVJoRC2yUu89/6x8AQaClwNh364XWmF7bgbCyjThjC70iz2Feu0ORkj4D0vjClYnP1Kz5HOAvzCRlJTtwVnB9xrEBtV45ONaw6wRwVPkADLg/624FTHzwpi7BTTV2xCAn3kx2JvSH7n9ISySu8ZG6Z2pZ5IBs7+7jWQKmtbC8b6wB0VpYwoCcLjGIduaYtx2YKv0FvjMxOeMmrfu3X33Ab9KL/T4meu5LhqcW01JDP2MlzZ8UYebykd+0KI2mts+hGHNhCT3/d7fEh/ccmaJQ1sNl8VoKos1DlwUL+U8t7PVUNj6e4SXZK+Na9pPLI3pMPKvaoPZimbXRKShF+mYUGlLEcQLcjFTTmOnFSkIP39pa98K7mtTwy50dgcqroTm9rAoBGLcicjdlOi76XcSikYrYrBupx2LtAiWUuXrD0Zm9lQ/Lfwp3smUaC6aFNmnyxPmDJ1XscbQr3m/5oxfNopBNliZCvlGLUc/HGUpy0XcEZymPA77AZog4cHcjgAi9tsdnPHfxMmFTniThDD/SgVjTolzSu4Sm/RY2K2hCJ8qFeSuvbhmgPPWOBbNMOfsv9Nswa4Rd57uEqxxSrpAo1dzxdJPklrDsCxeexVz1/6xW3Qj+I12abMacCCa8oX+PLfpdT6hDqBSlzT3KbVz6ApWNRheM/z8kwpDCDHKGIKPZ5OjRm0SRn/SlogRCUHZ93TSOClIPRr37TDYDpvzeoSjAxnwQ2jTxuIs=",
|
||||||
"urls": [
|
"urls": [
|
||||||
"https://pixeldrain.com/api/file/gBW5TSR0",
|
"https://pixeldrain.com/api/file/6NjT6uEl",
|
||||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_mac.dmg"
|
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_mac.dmg"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"debian9": {
|
"debian9": {
|
||||||
"1.0.7": {
|
"1.0.8": {
|
||||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||||
"urls": [
|
"urls": [
|
||||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"debian10": {
|
"debian10": {
|
||||||
"1.0.7": {
|
"1.0.8": {
|
||||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||||
"urls": [
|
"urls": [
|
||||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fedora28": {
|
"fedora28": {
|
||||||
"1.0.7": {
|
"1.0.8": {
|
||||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||||
"urls": [
|
"urls": [
|
||||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fedora29": {
|
"fedora29": {
|
||||||
"1.0.7": {
|
"1.0.8": {
|
||||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||||
"urls": [
|
"urls": [
|
||||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fedora30": {
|
"fedora30": {
|
||||||
"1.0.7": {
|
"1.0.8": {
|
||||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||||
"urls": [
|
"urls": [
|
||||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"opensuse15": {
|
"opensuse15": {
|
||||||
"1.0.7": {
|
"1.0.8": {
|
||||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||||
"urls": [
|
"urls": [
|
||||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"opensuse15.1": {
|
"opensuse15.1": {
|
||||||
"1.0.7": {
|
"1.0.8": {
|
||||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||||
"urls": [
|
"urls": [
|
||||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"solus": {
|
"solus": {
|
||||||
"1.0.7": {
|
"1.0.8": {
|
||||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||||
"urls": [
|
"urls": [
|
||||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tumbleweed": {
|
"tumbleweed": {
|
||||||
"1.0.7": {
|
"1.0.8": {
|
||||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||||
"urls": [
|
"urls": [
|
||||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ubuntu18.04": {
|
"ubuntu18.04": {
|
||||||
"1.0.7": {
|
"1.0.8": {
|
||||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||||
"urls": [
|
"urls": [
|
||||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ubuntu18.10": {
|
"ubuntu18.10": {
|
||||||
"1.0.7": {
|
"1.0.8": {
|
||||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||||
"urls": [
|
"urls": [
|
||||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ubuntu19.04": {
|
"ubuntu19.04": {
|
||||||
"1.0.7": {
|
"1.0.8": {
|
||||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||||
"urls": [
|
"urls": [
|
||||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"win32": {
|
"win32": {
|
||||||
"1.0.7": {
|
"1.0.8": {
|
||||||
"sha256": "fbf7611bca712413bd6e6900bcbd49bd3a1545b4d4e70afb2ee9bd59f74b8f97",
|
"sha256": "1dcf2ca95ee9ce1893166e7966e4aaa465735d00476d99414c57d18e7232212f",
|
||||||
"sig": "B3URP0wqwJcxuisX/qkoLg19Tm1tUu0rQbkBrCtpscaSa5PhUS/p+6ID/eApKMy91SWqCeqw0C071OvTVfTmWRoB/v+9Kkftqs9IISIMDBZgJEAcwf5h0CYqRp/cLyl5XfZLnZoMDR6x7cIVejBaDu1EWtWtACTxfDy3SvtbHkXTfo5ojKk5DScTSNAeDVSL1dY7BBsGuy5WDR0GYpB+519//V4uNCeLSxmHMekEQdyMmjpaO4iKDOkqccwYNSrw3LpL6TQ6YpTX8g2I1tD1ucTKob5Z44LANceL/PMjk7XYRCplufZBIiAnK6mBQFjFFMm4dDTSWqFQKn+pJboTE1E20Gvs/1MFwO1S30mwOIuYebZ4Xfa/D26rFjjxsA8a62Xrxw5YenKczRWs1iNRK+BZUUNw3pbm0KtEwvJZX/XhaVBBuHwT4CDTLIK0tvVsVF6cMNXLdgJEBmItkSw8LdDta81SwHVco0oMxwExqFbwhXqZf7hQBx4NaytBft0QeXNGF0T1B7GTi+D2qr9F5YcIALzYPh5b6RC8yTuTuVgIW+f3LSY8yPTvJaFS3idjTMbzebWAC2aR0BNW1dPyEEoLzsQEfBDbXqSN4m7j+Nt2l5HGfpy370uOaVeKhIFgASJTvhp6FJ0+3FdJfv5E6E0h6EXCXsGCXmh51kcz5kPpmeLXa3OaoF8G5277hICztyUfqskmgz6cu5udRglW57ZwVM8nWRYo9yO5oiLn9ygq4ALOhUfQhbaCpICsDO5nG1R3rAj0t4a2yzQg+CqN9GXzf0+xlbuO0wdg92s2Tgs1O2F5U8yPvgp7fJIil8/GYmmJHj9zqj+kWjFm+ZPdreXns5m+jr58/hepaVyu7KVV/I/o5Q2dse5Xf+jvt7B8u2TC+JWmitzBJkDGRM0Rml+3QIb2F1lKMfPSs34aI7HJHjrfvExAcFiXDVsFXudVZqayjKWreA4gsgZ07GUi1lZ6qX00K7trxWz0BmlZqtXGofrDUQGgsiZ5FoGW5tFSs9t7DqUnpQAZCiVfPki8bphbPMeRsPXBMXsHKTK6TzbU8nukq8urMJWURetWQP5N4/dSI5zrgByBVI7n1TQvdE2bzMQrJP/xTLWGZUCRXfi2J7FmW7fbUtcAStVC2TPWPuzEC9Lvb3ybg0wepgEbMn1kGfb7mohJ5jeLHqhGzY9mx9fO191cduH9zI+yV5wrnYqWd5wN9J4NY66ULxeGxt03rzjMd2hv2tRRVRsT+/4ACUZcIV8JwUZgK51s5DuUWUsl2e5DBPAND/RVpThXJVFyAtBo/vDqoY3lg/pc4RaQZ6gNMoFeHbXwD/yu6TDDTWq5u00ZwNCbR0PaBTwDabs=",
|
"sig": "AzXf0WkuGx4lXoGPgxsj2LDCAHwotKnvZHBFZv1f2A77sNtJaDQAgS3b4Hjg0AiWCRL9HzjJNprBv5lEUwc7AeRLXuj+4AI6Z7PeRaVs2NBgEHlIqldPwjime8bE2NBrkKfdDDdiAzhm3AqxgRzwhZ4sxkb3vNDdKIj4WnH79LsVCEcBgtuWalNvt3Q0i5ppBvu6+Iy/gZuGa7z+Jv2WU+Ijm7WjkmmmTdpcvP1UQTBL2UkriYOxVMIfrjHM0b2ch6RGBKUxS2h26h0xmJ7SzFoZ6lHcHDIxi8fsi7DIO/QDpottJPVgZLRuufSTyXLCbehLRI3dd1IWhQns0OTU11MBAUTRczJTaZ8nrjMesKdwbWqDDGMWOHyl39EuGIaGm3Mbi4iQWI3gz4RmX9kIWf0OSaT73okPvfjWA2Onn8IOs57TDw5fIyKKFjMkxqAPy0O+WonjJ5bd4Q/8HUpVx9M9NoClbztMQUhom2hVPkPiD3jQ8I9YcrmD9phZYkMf5As1G6RBsITsbpRA0bu9426y6K+nNJLPAM0TrW33oOziYV2z5HD1/Z+TsUMcusAPTbatjPLyLZ9kWIUqybPga8iPZW9iqszei2ywKl3EgAP/rZx2fn3qko9PvdpsoV6VBp9FxT2mguoRnkIo3lPGYXssBlfVBz0treGyjDoqcOrtciVLJbal54FTPU5o+Acuffi0Ft2F4qW7d3VglhEeA2i4zzPH2l8R0CuStei8ePMhOpebtByTPrclkvlbcOCg5adF+3/zTH9H261+P/IyrPct1ucvVpa6FlpcKfErWttRmxc9QhqiepyPUonLkHgB4Ur/ft6PzlE/+wD6arA7avSKdZqzeSksFSdnX/41fD8gL5CHfsCdbeqPvPd97CliiMCeGjVngQ5qFbC1+5DHuDopvs0yWcmDAO+nFrcQt3K01VjDYT+5plb263Ba3HKHqkT9N2gH8yWK/DdfT4Y8WAABomcgPeRSg6lAtNFv5RtWbSq9Q4dLFuhGM55EtXPG15zYAZqePCcyWYieP0wNuszcSsVNDScU8gqilwtn1oKO0ISZSYZUbdzI3fDc6SbaJNLwYdT/AlELZy0fAKILmJJN8MUXvcC7we6zyPOqwEf1ESLOb84Zw3+gPtH+Ao9dWHKdHOlyNyRzPvTYrcqSn2Uf3iHOLeoazqEEJ5Bh7jbDgVBkB4XEwijb+BvFV3cBcLdSg1Id3zZF02jkpaN4SMbEmqPbUv393CKRNs47p6ffFKKS5oUEpF6GpZq/wtjmKkdMSIzGVurbHPIaZI8JfLrEu/GAxAMGM7G3O5AiKOf0AH0wexhP5Vh6iE3MLNMA7n8SEQL5i/YUIL6b0tDL/wc=",
|
||||||
"urls": [
|
"urls": [
|
||||||
"https://pixeldrain.com/api/file/AcsttDQ_",
|
"https://pixeldrain.com/api/file/u_pP3IAk",
|
||||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_win.exe"
|
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_win.exe"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Versions": {
|
"Versions": {
|
||||||
"arch": [
|
"arch": [
|
||||||
"1.0.7"
|
"1.0.8"
|
||||||
],
|
],
|
||||||
"centos7": [
|
"centos7": [
|
||||||
"1.0.7"
|
"1.0.8"
|
||||||
],
|
],
|
||||||
"darwin": [
|
"darwin": [
|
||||||
"1.0.7"
|
"1.0.8"
|
||||||
],
|
],
|
||||||
"debian9": [
|
"debian9": [
|
||||||
"1.0.7"
|
"1.0.8"
|
||||||
],
|
],
|
||||||
"debian10": [
|
"debian10": [
|
||||||
"1.0.7"
|
"1.0.8"
|
||||||
],
|
],
|
||||||
"fedora28": [
|
"fedora28": [
|
||||||
"1.0.7"
|
"1.0.8"
|
||||||
],
|
],
|
||||||
"fedora29": [
|
"fedora29": [
|
||||||
"1.0.7"
|
"1.0.8"
|
||||||
],
|
],
|
||||||
"fedora30": [
|
"fedora30": [
|
||||||
"1.0.7"
|
"1.0.8"
|
||||||
],
|
],
|
||||||
"linux": [
|
"linux": [
|
||||||
"unavailable"
|
"unavailable"
|
||||||
],
|
],
|
||||||
"opensuse15": [
|
"opensuse15": [
|
||||||
"1.0.7"
|
"1.0.8"
|
||||||
],
|
],
|
||||||
"opensuse15.1": [
|
"opensuse15.1": [
|
||||||
"1.0.7"
|
"1.0.8"
|
||||||
],
|
],
|
||||||
"solus": [
|
"solus": [
|
||||||
"1.0.7"
|
"1.0.8"
|
||||||
],
|
],
|
||||||
"tumbleweed": [
|
"tumbleweed": [
|
||||||
"1.0.7"
|
"1.0.8"
|
||||||
],
|
],
|
||||||
"ubuntu18.04": [
|
"ubuntu18.04": [
|
||||||
"1.0.7"
|
"1.0.8"
|
||||||
],
|
],
|
||||||
"ubuntu18.10": [
|
"ubuntu18.10": [
|
||||||
"1.0.7"
|
"1.0.8"
|
||||||
],
|
],
|
||||||
"ubuntu19.04": [
|
"ubuntu19.04": [
|
||||||
"1.0.7"
|
"1.0.8"
|
||||||
],
|
],
|
||||||
"unknown": [
|
"unknown": [
|
||||||
"unavailable"
|
"unavailable"
|
||||||
],
|
],
|
||||||
"win32": [
|
"win32": [
|
||||||
"1.0.7"
|
"1.0.8"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
31
src/App.js
31
src/App.js
@@ -7,6 +7,7 @@ import DependencyList from './components/DependencyList/DependencyList';
|
|||||||
import DownloadProgress from './components/DownloadProgress/DownloadProgress';
|
import DownloadProgress from './components/DownloadProgress/DownloadProgress';
|
||||||
import ErrorDetails from './components/ErrorDetails/ErrorDetails';
|
import ErrorDetails from './components/ErrorDetails/ErrorDetails';
|
||||||
import Grid from './components/UI/Grid/Grid';
|
import Grid from './components/UI/Grid/Grid';
|
||||||
|
import InfoDetails from './components/InfoDetails/InfoDetails';
|
||||||
import IPCContainer from './containers/IPCContainer/IPCContainer';
|
import IPCContainer from './containers/IPCContainer/IPCContainer';
|
||||||
import Loading from './components/UI/Loading/Loading';
|
import Loading from './components/UI/Loading/Loading';
|
||||||
import Modal from './components/UI/Modal/Modal';
|
import Modal from './components/UI/Modal/Modal';
|
||||||
@@ -14,7 +15,11 @@ import MountItems from './containers/MountItems/MountItems';
|
|||||||
import {notifyError} from './redux/actions/error_actions';
|
import {notifyError} from './redux/actions/error_actions';
|
||||||
import Reboot from './components/Reboot/Reboot';
|
import Reboot from './components/Reboot/Reboot';
|
||||||
import ReleaseVersionDisplay from './components/ReleaseVersionDisplay/ReleaseVersionDisplay';
|
import ReleaseVersionDisplay from './components/ReleaseVersionDisplay/ReleaseVersionDisplay';
|
||||||
import {saveState} from './redux/actions/common_actions';
|
import {
|
||||||
|
displaySelectAppPlatform,
|
||||||
|
saveState
|
||||||
|
} from './redux/actions/common_actions';
|
||||||
|
import SelectAppPlatform from './containers/SelectAppPlatform/SelectAppPlatform';
|
||||||
import Text from './components/UI/Text/Text';
|
import Text from './components/UI/Text/Text';
|
||||||
import UpgradeIcon from './components/UpgradeIcon/UpgradeIcon';
|
import UpgradeIcon from './components/UpgradeIcon/UpgradeIcon';
|
||||||
import UpgradeUI from './components/UpgradeUI/UpgradeUI';
|
import UpgradeUI from './components/UpgradeUI/UpgradeUI';
|
||||||
@@ -30,13 +35,17 @@ class App extends IPCContainer {
|
|||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const detectUpgrades = () => {
|
const detectUpgrades = () => {
|
||||||
if (this.props.AppPlatform === 'unknown') {
|
if (this.props.AppPlatform === 'unknown') {
|
||||||
|
if (this.props.Platform === 'linux') {
|
||||||
|
this.props.displaySelectAppPlatform(true);
|
||||||
|
} else {
|
||||||
this.props.notifyError('Operating system is not supported.', true);
|
this.props.notifyError('Operating system is not supported.', true);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.props.loadReleases();
|
this.props.loadReleases();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.scheduledUpdateJob = Scheduler.scheduleJob('23 11 * * *', detectUpgrades);
|
|
||||||
detectUpgrades();
|
detectUpgrades();
|
||||||
|
this.scheduledUpdateJob = Scheduler.scheduleJob('23 11 * * *', detectUpgrades);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
@@ -113,15 +122,19 @@ class App extends IPCContainer {
|
|||||||
!this.props.DismissDependencies &&
|
!this.props.DismissDependencies &&
|
||||||
this.props.AllowMount;
|
this.props.AllowMount;
|
||||||
|
|
||||||
|
const infoDisplay = this.createModalConditionally(this.props.DisplayInfo, <InfoDetails/>, true);
|
||||||
const rebootDisplay = this.createModalConditionally(this.props.RebootRequired, <Reboot />);
|
const rebootDisplay = this.createModalConditionally(this.props.RebootRequired, <Reboot />);
|
||||||
const configDisplay = this.createModalConditionally(showConfig, <Configuration version={selectedVersion} />);
|
const configDisplay = this.createModalConditionally(showConfig, <Configuration version={selectedVersion} />);
|
||||||
const dependencyDisplay = this.createModalConditionally(showDependencies, <DependencyList/>);
|
const dependencyDisplay = this.createModalConditionally(showDependencies, <DependencyList/>);
|
||||||
const downloadDisplay = this.createModalConditionally(this.props.DownloadActive, <DownloadProgress/>);
|
const downloadDisplay = this.createModalConditionally(this.props.DownloadActive, <DownloadProgress/>);
|
||||||
const errorDisplay = this.createModalConditionally(this.props.DisplayError, <ErrorDetails/>, true);
|
const errorDisplay = this.createModalConditionally(this.props.DisplayError, <ErrorDetails/>, true);
|
||||||
const upgradeDisplay = this.createModalConditionally(showUpgrade, <UpgradeUI/>);
|
const upgradeDisplay = this.createModalConditionally(showUpgrade, <UpgradeUI/>);
|
||||||
|
const selectAppPlatformDisplay = this.createModalConditionally(this.props.DisplaySelectAppPlatform, <SelectAppPlatform/>);
|
||||||
|
|
||||||
let mainContent = [];
|
let mainContent = [];
|
||||||
if (this.props.AppReady) {
|
if (this.props.DisplaySelectAppPlatform || !this.props.AppReady) {
|
||||||
|
mainContent = <Loading/>
|
||||||
|
} else {
|
||||||
let key = 0;
|
let key = 0;
|
||||||
mainContent.push((
|
mainContent.push((
|
||||||
<div key={'rvd_' + key++}
|
<div key={'rvd_' + key++}
|
||||||
@@ -140,18 +153,18 @@ class App extends IPCContainer {
|
|||||||
</div>
|
</div>
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
mainContent = <Loading/>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'App'}>
|
<div className={'App'}>
|
||||||
{errorDisplay}
|
{selectAppPlatformDisplay}
|
||||||
{dependencyDisplay}
|
{dependencyDisplay}
|
||||||
{upgradeDisplay}
|
{upgradeDisplay}
|
||||||
{downloadDisplay}
|
|
||||||
{configDisplay}
|
{configDisplay}
|
||||||
|
{infoDisplay}
|
||||||
|
{downloadDisplay}
|
||||||
{rebootDisplay}
|
{rebootDisplay}
|
||||||
|
{errorDisplay}
|
||||||
<div className={'AppContainer'}>
|
<div className={'AppContainer'}>
|
||||||
<div className={'AppHeader'}>
|
<div className={'AppHeader'}>
|
||||||
<Box>
|
<Box>
|
||||||
@@ -193,12 +206,15 @@ const mapStateToProps = state => {
|
|||||||
DismissDependencies: state.install.DismissDependencies,
|
DismissDependencies: state.install.DismissDependencies,
|
||||||
DisplayConfiguration: state.mounts.DisplayConfiguration,
|
DisplayConfiguration: state.mounts.DisplayConfiguration,
|
||||||
DisplayError: state.error.DisplayError,
|
DisplayError: state.error.DisplayError,
|
||||||
|
DisplayInfo: state.error.DisplayInfo,
|
||||||
|
DisplaySelectAppPlatform: state.common.DisplaySelectAppPlatform,
|
||||||
DownloadActive: state.download.DownloadActive,
|
DownloadActive: state.download.DownloadActive,
|
||||||
InstallActive: state.install.InstallActive,
|
InstallActive: state.install.InstallActive,
|
||||||
InstalledVersion: state.relver.InstalledVersion,
|
InstalledVersion: state.relver.InstalledVersion,
|
||||||
LocationsLookup: state.relver.LocationsLookup,
|
LocationsLookup: state.relver.LocationsLookup,
|
||||||
MissingDependencies: state.install.MissingDependencies,
|
MissingDependencies: state.install.MissingDependencies,
|
||||||
MountsBusy: state.mounts.MountsBusy,
|
MountsBusy: state.mounts.MountsBusy,
|
||||||
|
Platform: state.common.Platform,
|
||||||
ProviderState: state.mounts.ProviderState,
|
ProviderState: state.mounts.ProviderState,
|
||||||
RebootRequired: state.common.RebootRequired,
|
RebootRequired: state.common.RebootRequired,
|
||||||
Release: state.relver.Release,
|
Release: state.relver.Release,
|
||||||
@@ -212,6 +228,7 @@ const mapStateToProps = state => {
|
|||||||
|
|
||||||
const mapDispatchToProps = dispatch => {
|
const mapDispatchToProps = dispatch => {
|
||||||
return {
|
return {
|
||||||
|
displaySelectAppPlatform: display => dispatch(displaySelectAppPlatform(display)),
|
||||||
loadReleases: ()=> dispatch(loadReleases()),
|
loadReleases: ()=> dispatch(loadReleases()),
|
||||||
notifyError: (msg, critical, callback) => dispatch(notifyError(msg, critical, callback)),
|
notifyError: (msg, critical, callback) => dispatch(notifyError(msg, critical, callback)),
|
||||||
saveState: () => dispatch(saveState()),
|
saveState: () => dispatch(saveState()),
|
||||||
|
|||||||
29
src/assets/settings.json
Normal file
29
src/assets/settings.json
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"HostConfig": {
|
||||||
|
"AgentString": "'User-Agent' used when communicating with Sia/SiaPrime's API.",
|
||||||
|
"ApiPassword": "Password used when communicating with Sia/SiaPrime's API.\n\nThis is not the same as your wallet's password, so please do not enter it here. Sia/SiaPrime typically auto-generate this value. It is exclusively used for API authentication purposes.",
|
||||||
|
"ApiPort": "API port used to connect to Sia/SiaPrime's daemon.",
|
||||||
|
"HostNameOrIp": "IP address or host name of Sia/SiaPrime daemon.",
|
||||||
|
"TimeoutMs": "Number of milliseconds to wait for Sia/SiaPrime API responses before timing out."
|
||||||
|
},
|
||||||
|
"Settings": {
|
||||||
|
"ApiAuth": "Password used to communicate with Repertory's API. Auto-generated by default.",
|
||||||
|
"ApiPort": "Repertory API port to use for JSON-RPC requests.",
|
||||||
|
"ApiUser": "Username used to communicate with Repertory's API.",
|
||||||
|
"ChunkDownloaderTimeoutSeconds": "Files that are not cached locally will download data in ChunkSize chunks when a read or write operation occurs. This timeout value specifies the amount of time chunks should continue downloading after the last file handle has been closed.",
|
||||||
|
"ChunkSize": "This is the minimum data size (converted to KiB - value of 8 means 8KiB) used for downloads. This value cannot be less than 8 and should also be a multiple of 8.",
|
||||||
|
"EnableChunkDownloaderTimeout": "This setting applies to full allocation downloads. When set to true, downloads will timeout after ChunkDownloaderTimeoutSeconds if the file has no more open handles. If set to false, the entire file will always download.",
|
||||||
|
"EnableDriveEvents": "When set to true, additional logging for FUSE on UNIX or WinFSP on Windows will occur. It's best to leave this value set to 'false' unless troubleshooting an issue as enabling it may have an adverse affect on performance.",
|
||||||
|
"EnableMaxCacheSize": "If set to true, files will begin to be removed from the local cache as soon as MaxCacheSizeBytes and MinimumRedundancy have been met. This does not mean further attempts to write will fail when MaxCacheSizeBytes is reached. Writes will continue as long as there is enough local drive space to accommodate the operation.\n\nIf set to false, files will begin to be removed from the local cache as soon as MinimumRedundancy has been met.\n\nIn both cases, files that do not have any open handles will be chosen by oldest modification date for removal.",
|
||||||
|
"EventLevel": "Internally, events are fired during certain operations. This setting determines which events should be logged to repertory.log. Valid values are Error, Warn, Normal, Debug, and Verbose.",
|
||||||
|
"EvictionDelaySeconds": "Number of seconds to wait after all file handles are closed before allowing file to be evicted from cache.",
|
||||||
|
"EvictionDelayMinutes": "Number of minutes to wait after all file handles are closed before allowing file to be evicted from cache.",
|
||||||
|
"MaxCacheSizeBytes": "This value specifies the maximum amount of local space to consume before files are removed from cache. EnableMaxCacheSize must also be set to true for this value to take affect.",
|
||||||
|
"MinimumRedundancy": "Files are elected for removal once this value has been reached. Be aware that this value cannot be set to less than 1.5x.",
|
||||||
|
"OnlineCheckRetrySeconds": "Number of seconds to wait for Sia/SiaPrime daemon to become available/connectable.",
|
||||||
|
"OrphanedFileRetentionDays": "Repertory attempts to keep modifications between Sia-UI and the mounted location in sync as much as possible. In the event a file is removed from Sia-UI, it will be marked as orphaned in Repertory and moved into an 'orphaned' directory within Repertory's data directory. This setting specifies the number of days this file is retained before final deletion.",
|
||||||
|
"PreferredDownloadType": "Repertory supports 3 download modes for reading files that are not cached locally: full file allocation, ring buffer mode and direct mode.\n\nFull file allocation mode pre-allocates the entire file prior to downloading. This mode is required for writes but also ensures the best performance when reading data.\n\nRing buffer mode utilizes a fixed size file buffer to enable a reasonable amount of seeking. This alleviates the need to fully allocate a file. By default, it is 512MiB. When the buffer is full, it attempts to maintain the ability to seek 50% ahead or behind the current read location without the need to re-download data from Sia/SiaPrime.\n\nDirect mode utilizes no disk space. All data is read directly from Sia/SiaPrime.\n\nPreferred download type modes are:\n\nFallback - If there isn't enough local space to allocate the full file, ring buffer mode is used. If there isn't enough local space to create the ring buffer's file, then direct mode is used.\nRingBuffer - Full file allocation is always bypassed; however, if there isn't enough space to create the ring buffer's file, then direct mode will be chosen.\nDirect - All files will be read directly from Sia/SiaPrime.",
|
||||||
|
"ReadAheadCount": "This value specifies the number of read-ahead chunks to use when downloading a file. This is a per-open file setting and will result in the creation of an equal number of threads.",
|
||||||
|
"RingBufferFileSize": "The size of the ring buffer file in MiB. Default is 512. Valid values are: 64, 128, 256, 512, 1024."
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,3 +34,7 @@ input.ConfigurationItemInput {
|
|||||||
border-color: rgba(10, 10, 20, 0.9);
|
border-color: rgba(10, 10, 20, 0.9);
|
||||||
color: var(--text_color);
|
color: var(--text_color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ConfigurationInfo {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
@@ -1,7 +1,18 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import './ConfigurationItem.css';
|
import './ConfigurationItem.css';
|
||||||
|
import settings from '../../assets/settings';
|
||||||
|
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
|
||||||
|
import {faInfoCircle} from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import {connect} from 'react-redux';
|
||||||
|
import {notifyInfo} from '../../redux/actions/error_actions';
|
||||||
|
|
||||||
export default props => {
|
const mapDispatchToProps = dispatch => {
|
||||||
|
return {
|
||||||
|
notifyInfo: (title, msg) => dispatch(notifyInfo(title, msg))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(null, mapDispatchToProps)(props => {
|
||||||
const handleChanged = (e) => {
|
const handleChanged = (e) => {
|
||||||
const target = e.target;
|
const target = e.target;
|
||||||
if (target.type === 'checkbox') {
|
if (target.type === 'checkbox') {
|
||||||
@@ -10,6 +21,18 @@ export default props => {
|
|||||||
props.changed(target);
|
props.changed(target);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let infoDisplay;
|
||||||
|
if (settings[props.grouping] && settings[props.grouping][props.label]) {
|
||||||
|
const displayInfo = () => {
|
||||||
|
const description = settings[props.grouping][props.label];
|
||||||
|
props.notifyInfo(props.label, description);
|
||||||
|
};
|
||||||
|
|
||||||
|
infoDisplay = <a href={void(0)}
|
||||||
|
className={'ConfigurationInfo'}
|
||||||
|
onClick={()=>{displayInfo(); return false;}}><FontAwesomeIcon icon={faInfoCircle}/></a>;
|
||||||
|
}
|
||||||
|
|
||||||
let data;
|
let data;
|
||||||
switch (props.template.type) {
|
switch (props.template.type) {
|
||||||
case "bool":
|
case "bool":
|
||||||
@@ -96,11 +119,13 @@ export default props => {
|
|||||||
width='100%'>
|
width='100%'>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td width='100%'>{props.label}</td>
|
{infoDisplay ?
|
||||||
|
<td width='100%'>{infoDisplay} {props.label}</td> :
|
||||||
|
<td width='100%'>{props.label}</td>}
|
||||||
<td>{data}</td>
|
<td>{data}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
@@ -22,8 +22,7 @@ export default connect(mapStateToProps)(props => {
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{props.AllowDownload ?
|
{props.AllowDownload ?
|
||||||
<a
|
<a href={void(0)}
|
||||||
href={void(0)}
|
|
||||||
className={'DependencyLink'}
|
className={'DependencyLink'}
|
||||||
onClick={()=>{props.onDownload(); return false;}}><u>Install</u></a> :
|
onClick={()=>{props.onDownload(); return false;}}><u>Install</u></a> :
|
||||||
'Installing...'}
|
'Installing...'}
|
||||||
|
|||||||
11
src/components/InfoDetails/InfoDetails.css
Normal file
11
src/components/InfoDetails/InfoDetails.css
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
.InfoDetailsHeading {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.InfoDetailsContent {
|
||||||
|
max-height: 60vh;
|
||||||
|
min-width: 80vw;
|
||||||
|
overflow-y: auto;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
30
src/components/InfoDetails/InfoDetails.js
Normal file
30
src/components/InfoDetails/InfoDetails.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {dismissInfo} from '../../redux/actions/error_actions';
|
||||||
|
import {connect} from 'react-redux';
|
||||||
|
import Box from '../UI/Box/Box';
|
||||||
|
import Button from '../UI/Button/Button';
|
||||||
|
import './InfoDetails.css';
|
||||||
|
|
||||||
|
const mapStateToProps = state => {
|
||||||
|
return {
|
||||||
|
InfoMessage: state.error.InfoStack.length > 0 ? state.error.InfoStack[0] : '',
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => {
|
||||||
|
return {
|
||||||
|
dismissInfo: () => dispatch(dismissInfo()),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(props => {
|
||||||
|
return (
|
||||||
|
<Box dxDark dxStyle={{padding: '8px'}}>
|
||||||
|
<h1 className={'InfoDetailsHeading'}>{props.InfoMessage.title}</h1>
|
||||||
|
<div className={'InfoDetailsContent'}>
|
||||||
|
<p style={{textAlign: 'left', whiteSpace: 'pre-line'}}>{props.InfoMessage.message}</p>
|
||||||
|
</div>
|
||||||
|
<Button clicked={props.dismissInfo}>Dismiss</Button>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
});
|
||||||
@@ -36,6 +36,12 @@ exports.UI_RELEASES_URL = 'https://bitbucket.org/blockstorage/repertory-ui/raw/'
|
|||||||
|
|
||||||
exports.LINUX_DETECT_SCRIPT_URL = 'https://bitbucket.org/blockstorage/repertory/raw/' + REPERTORY_BRANCH + '/detect_linux.sh';
|
exports.LINUX_DETECT_SCRIPT_URL = 'https://bitbucket.org/blockstorage/repertory/raw/' + REPERTORY_BRANCH + '/detect_linux.sh';
|
||||||
|
|
||||||
|
exports.LINUX_SELECTABLE_PLATFORMS = [
|
||||||
|
'ubuntu18.04',
|
||||||
|
'ubuntu18.10',
|
||||||
|
'ubuntu19.04'
|
||||||
|
];
|
||||||
|
|
||||||
exports.DATA_LOCATIONS = {
|
exports.DATA_LOCATIONS = {
|
||||||
linux: '~/.local/repertory/ui',
|
linux: '~/.local/repertory/ui',
|
||||||
darwin: '~/Library/Application Support/repertory/ui',
|
darwin: '~/Library/Application Support/repertory/ui',
|
||||||
@@ -62,6 +68,7 @@ exports.RELEASE_TYPES = [
|
|||||||
exports.INSTALL_TYPES = {
|
exports.INSTALL_TYPES = {
|
||||||
Dependency: 'dependency',
|
Dependency: 'dependency',
|
||||||
Release: 'release',
|
Release: 'release',
|
||||||
|
TestRelease: 'test_release',
|
||||||
Upgrade: 'upgrade',
|
Upgrade: 'upgrade',
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -120,8 +127,13 @@ exports.IPC_Show_Window = 'show_window';
|
|||||||
exports.IPC_Set_Config_Values = 'set_config_values';
|
exports.IPC_Set_Config_Values = 'set_config_values';
|
||||||
exports.IPC_Set_Config_Values_Reply = 'set_config_values_reply';
|
exports.IPC_Set_Config_Values_Reply = 'set_config_values_reply';
|
||||||
|
|
||||||
|
exports.IPC_Set_Linux_AppPlatform = 'IPC_Set_Linux_AppPlatform';
|
||||||
|
|
||||||
exports.IPC_Shutdown = 'shutdown';
|
exports.IPC_Shutdown = 'shutdown';
|
||||||
|
|
||||||
|
exports.IPC_Test_Release = 'test_release';
|
||||||
|
exports.IPC_Test_Release_Reply = 'test_release_reply';
|
||||||
|
|
||||||
exports.IPC_Unmount_All_Drives = 'unmount_all';
|
exports.IPC_Unmount_All_Drives = 'unmount_all';
|
||||||
exports.IPC_Unmount_All_Drives_Reply = 'unmount_all_reply';
|
exports.IPC_Unmount_All_Drives_Reply = 'unmount_all_reply';
|
||||||
|
|
||||||
|
|||||||
@@ -231,6 +231,7 @@ class Configuration extends IPCContainer {
|
|||||||
((this.state.ShowAdvanced && k.advanced) || !k.advanced) ?
|
((this.state.ShowAdvanced && k.advanced) || !k.advanced) ?
|
||||||
<ConfigurationItem advanced={k.advanced}
|
<ConfigurationItem advanced={k.advanced}
|
||||||
changed={e=>this.handleItemChanged(e, i)}
|
changed={e=>this.handleItemChanged(e, i)}
|
||||||
|
grouping={'Settings'}
|
||||||
items={this.state.Template[k.label].items}
|
items={this.state.Template[k.label].items}
|
||||||
key={i}
|
key={i}
|
||||||
label={k.label}
|
label={k.label}
|
||||||
@@ -251,6 +252,7 @@ class Configuration extends IPCContainer {
|
|||||||
((this.state.ShowAdvanced && k.advanced) || !k.advanced) ?
|
((this.state.ShowAdvanced && k.advanced) || !k.advanced) ?
|
||||||
<ConfigurationItem advanced={k.advanced}
|
<ConfigurationItem advanced={k.advanced}
|
||||||
changed={e=>this.handleObjectItemChanged(e, key, i)}
|
changed={e=>this.handleObjectItemChanged(e, key, i)}
|
||||||
|
grouping={key}
|
||||||
items={this.state.Template[key].template[k.label].items}
|
items={this.state.Template[key].template[k.label].items}
|
||||||
key={i}
|
key={i}
|
||||||
label={k.label}
|
label={k.label}
|
||||||
|
|||||||
@@ -171,9 +171,13 @@ class MountItems extends IPCContainer {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
allowAction = false;
|
allowAction = false;
|
||||||
|
if (this.props.Platform === 'win32') {
|
||||||
|
this.props.notifyError('Failed to launch repertory. Please install Microsoft Visual C++ Redistributable for Visual Studio 2015, 2017 and 2019.');
|
||||||
|
} else {
|
||||||
this.displayRetryMount(provider, location, 'Version check failed: ' + result.Error);
|
this.displayRetryMount(provider, location, 'Version check failed: ' + result.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (allowAction) {
|
if (allowAction) {
|
||||||
this.props.setMountsBusy(true);
|
this.props.setMountsBusy(true);
|
||||||
|
|||||||
18
src/containers/SelectAppPlatform/SelectAppPlatform.css
Normal file
18
src/containers/SelectAppPlatform/SelectAppPlatform.css
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
.SAPHeading {
|
||||||
|
color: var(--text_color_error);
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SAPContent {
|
||||||
|
max-height: 60vh;
|
||||||
|
width: 255px;
|
||||||
|
overflow-y: auto;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SAPActions {
|
||||||
|
margin-top: 4px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
89
src/containers/SelectAppPlatform/SelectAppPlatform.js
Normal file
89
src/containers/SelectAppPlatform/SelectAppPlatform.js
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import './SelectAppPlatform.css';
|
||||||
|
import axios from 'axios';
|
||||||
|
import {connect} from 'react-redux';
|
||||||
|
import * as Constants from '../../constants';
|
||||||
|
import Box from '../../components/UI/Box/Box';
|
||||||
|
import Button from '../../components/UI/Button/Button';
|
||||||
|
import {
|
||||||
|
downloadItem,
|
||||||
|
setAllowDownload
|
||||||
|
} from '../../redux/actions/download_actions';
|
||||||
|
import DropDown from '../../components/UI/DropDown/DropDown';
|
||||||
|
import IPCContainer from '../IPCContainer/IPCContainer';
|
||||||
|
import {notifyError} from '../../redux/actions/error_actions';
|
||||||
|
import {setInstallTestActive} from '../../redux/actions/install_actions';
|
||||||
|
|
||||||
|
class SelectAppPlatform extends IPCContainer {
|
||||||
|
state = {
|
||||||
|
Selected: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
grabLatestRelease = appPlatform => {
|
||||||
|
const errorHandler = error => {
|
||||||
|
this.props.notifyError(error);
|
||||||
|
this.props.setInstallTestActive(false);
|
||||||
|
this.props.setAllowDownload(false);
|
||||||
|
};
|
||||||
|
axios
|
||||||
|
.get(Constants.RELEASES_URL)
|
||||||
|
.then(response => {
|
||||||
|
try {
|
||||||
|
const releases = response.data.Versions.Release[appPlatform];
|
||||||
|
const latestVersion = releases[releases.length - 1];
|
||||||
|
const release = response.data.Locations[appPlatform][latestVersion];
|
||||||
|
this.props.downloadItem(latestVersion + '.zip', Constants.INSTALL_TYPES.TestRelease, release.urls, false, latestVersion, appPlatform);
|
||||||
|
} catch (error) {
|
||||||
|
errorHandler(error);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
errorHandler(error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleTestClicked = () => {
|
||||||
|
this.props.setInstallTestActive(true);
|
||||||
|
this.props.setAllowDownload(true);
|
||||||
|
this.grabLatestRelease(Constants.LINUX_SELECTABLE_PLATFORMS[this.state.Selected])
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Box dxDark dxStyle={{padding: '8px'}}>
|
||||||
|
<h1 className={'SAPHeading'}>Select Linux Platform</h1>
|
||||||
|
<div className={'SAPContent'}>
|
||||||
|
<p>Repertory was unable to detect your Linux distribution. Please select one of the following and click <b>Test</b> to continue:</p>
|
||||||
|
</div>
|
||||||
|
<div className={'SAPActions'}>
|
||||||
|
<DropDown changed={e => this.setState({
|
||||||
|
...this.state,
|
||||||
|
Selected: e.target.value
|
||||||
|
})}
|
||||||
|
disabled={this.props.InstallTestActive}
|
||||||
|
items={Constants.LINUX_SELECTABLE_PLATFORMS}
|
||||||
|
selected={this.state.Selected}/>
|
||||||
|
<Button clicked={this.handleTestClicked}
|
||||||
|
disabled={this.props.InstallTestActive}>Test</Button>
|
||||||
|
</div>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = state => {
|
||||||
|
return {
|
||||||
|
InstallTestActive: state.install.InstallTestActive,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => {
|
||||||
|
return {
|
||||||
|
downloadItem: (name, type, urls, isWinFSP, testVersion, appPlatform) => dispatch(downloadItem(name, type, urls, isWinFSP, testVersion, appPlatform)),
|
||||||
|
notifyError: msg => dispatch(notifyError(msg)),
|
||||||
|
setAllowDownload: allow => dispatch(setAllowDownload(allow)),
|
||||||
|
setInstallTestActive: active => dispatch(setInstallTestActive(active)),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(SelectAppPlatform);
|
||||||
@@ -705,6 +705,23 @@ module.exports.stopMountProcessSync = (version, provider) => {
|
|||||||
process.unref();
|
process.unref();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module.exports.testRepertoryBinary = version => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const command = path.join(_getDataDirectory(), version, (os.platform() === 'win32') ? 'repertory.exe' : 'repertory');
|
||||||
|
_executeProcess(command, ['-dc'])
|
||||||
|
.then(code => {
|
||||||
|
if (code === 0) {
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
reject(Error('Invalid exit code: ' + code));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
module.exports.verifyHash = (file, hash) => {
|
module.exports.verifyHash = (file, hash) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const platform = os.platform();
|
const platform = os.platform();
|
||||||
|
|||||||
@@ -4,8 +4,17 @@ import {getIPCRenderer} from '../../utils';
|
|||||||
|
|
||||||
const ipcRenderer = getIPCRenderer();
|
const ipcRenderer = getIPCRenderer();
|
||||||
|
|
||||||
|
export const displaySelectAppPlatform = display => {
|
||||||
|
return dispatch => {
|
||||||
|
if (display) {
|
||||||
|
dispatch(showWindow());
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(setDisplaySelectAppPlatform(display));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const notifyRebootRequired = createAction('common/notifyRebootRequired');
|
export const notifyRebootRequired = createAction('common/notifyRebootRequired');
|
||||||
export const setAllowMount = createAction('common/setAllowMount');
|
|
||||||
|
|
||||||
export const rebootSystem = () => {
|
export const rebootSystem = () => {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
@@ -16,7 +25,19 @@ export const rebootSystem = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const setAllowMount = createAction('common/setAllowMount');
|
||||||
export const setApplicationReady = createAction('common/setApplicationReady');
|
export const setApplicationReady = createAction('common/setApplicationReady');
|
||||||
|
|
||||||
|
export const SET_DISPLAY_SELECT_APPPLATFORM = 'common/displaySelectAppPlatform';
|
||||||
|
export const setDisplaySelectAppPlatform = display => {
|
||||||
|
return {
|
||||||
|
type: SET_DISPLAY_SELECT_APPPLATFORM,
|
||||||
|
payload: display,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const setLinuxAppPlatform = createAction('common/setLinuxAppPlatform');
|
||||||
|
|
||||||
export const setRebootRequired = () => {
|
export const setRebootRequired = () => {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
dispatch(showWindow());
|
dispatch(showWindow());
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {createAction} from 'redux-starter-kit';
|
|||||||
import {getIPCRenderer} from '../../utils';
|
import {getIPCRenderer} from '../../utils';
|
||||||
import {notifyError} from './error_actions';
|
import {notifyError} from './error_actions';
|
||||||
import {
|
import {
|
||||||
|
installAndTestRelease,
|
||||||
installDependency,
|
installDependency,
|
||||||
installRelease,
|
installRelease,
|
||||||
installUpgrade
|
installUpgrade
|
||||||
@@ -25,7 +26,7 @@ export const setDownloadBegin = (name, type, url) => {
|
|||||||
export const setDownloadEnd = createAction('download/setDownloadEnd');
|
export const setDownloadEnd = createAction('download/setDownloadEnd');
|
||||||
export const setDownloadProgress = createAction('download/setDownloadProgress');
|
export const setDownloadProgress = createAction('download/setDownloadProgress');
|
||||||
|
|
||||||
export const downloadItem = (name, type, urls, isWinFSP) => {
|
export const downloadItem = (name, type, urls, isWinFSP, testVersion, appPlatform) => {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
if (!Array.isArray(urls)) {
|
if (!Array.isArray(urls)) {
|
||||||
urls = [urls];
|
urls = [urls];
|
||||||
@@ -40,6 +41,9 @@ export const downloadItem = (name, type, urls, isWinFSP) => {
|
|||||||
case Constants.INSTALL_TYPES.Release:
|
case Constants.INSTALL_TYPES.Release:
|
||||||
dispatch(installRelease(result.Destination));
|
dispatch(installRelease(result.Destination));
|
||||||
break;
|
break;
|
||||||
|
case Constants.INSTALL_TYPES.TestRelease:
|
||||||
|
dispatch(installAndTestRelease(result.Destination, testVersion, appPlatform));
|
||||||
|
break;
|
||||||
case Constants.INSTALL_TYPES.Upgrade:
|
case Constants.INSTALL_TYPES.Upgrade:
|
||||||
//const info = this.props.LocationsLookup[this.props.AppPlatform][this.props.VersionLookup[this.props.AppPlatform][0]];
|
//const info = this.props.LocationsLookup[this.props.AppPlatform][this.props.VersionLookup[this.props.AppPlatform][0]];
|
||||||
const sha256 = null;//info.sha256;
|
const sha256 = null;//info.sha256;
|
||||||
@@ -51,6 +55,9 @@ export const downloadItem = (name, type, urls, isWinFSP) => {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (type === Constants.INSTALL_TYPES.TestRelease) {
|
||||||
|
this.props.setAllowDownload(false);
|
||||||
|
}
|
||||||
dispatch(notifyError(result.Error));
|
dispatch(notifyError(result.Error));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,6 +13,14 @@ export const clearError = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const CLEAR_INFO = 'error/clearInfo';
|
||||||
|
export const clearInfo = () => {
|
||||||
|
return {
|
||||||
|
type: CLEAR_INFO,
|
||||||
|
payload: null,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const dismissError = () => {
|
export const dismissError = () => {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
dispatch(clearError());
|
dispatch(clearError());
|
||||||
@@ -27,6 +35,12 @@ export const dismissError = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const dismissInfo = () => {
|
||||||
|
return dispatch => {
|
||||||
|
dispatch(clearInfo());
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const notifyError = (msg, critical, callback) => {
|
export const notifyError = (msg, critical, callback) => {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
ErrorActions = [callback, ...ErrorActions];
|
ErrorActions = [callback, ...ErrorActions];
|
||||||
@@ -36,6 +50,14 @@ export const notifyError = (msg, critical, callback) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const notifyInfo = (title, msg) => {
|
||||||
|
return dispatch => {
|
||||||
|
title = title ? title.toString() : 'Information';
|
||||||
|
msg = msg ? msg.toString() : '';
|
||||||
|
dispatch(setInfo(title, msg));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const SET_ERROR_INFO = 'error/setErrorInfo';
|
export const SET_ERROR_INFO = 'error/setErrorInfo';
|
||||||
export const setErrorInfo = (msg, critical) => {
|
export const setErrorInfo = (msg, critical) => {
|
||||||
return {
|
return {
|
||||||
@@ -46,3 +68,15 @@ export const setErrorInfo = (msg, critical) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const SET_INFO = 'error/setInfo';
|
||||||
|
export const setInfo = (title, msg) => {
|
||||||
|
return {
|
||||||
|
type: SET_INFO,
|
||||||
|
payload: {
|
||||||
|
title,
|
||||||
|
msg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -7,13 +7,16 @@ import {
|
|||||||
import {notifyError} from './error_actions';
|
import {notifyError} from './error_actions';
|
||||||
import {setAllowDownload} from './download_actions';
|
import {setAllowDownload} from './download_actions';
|
||||||
import {
|
import {
|
||||||
|
loadReleases,
|
||||||
setActiveRelease,
|
setActiveRelease,
|
||||||
setInstalledVersion,
|
setInstalledVersion,
|
||||||
setReleaseUpgradeAvailable
|
setReleaseUpgradeAvailable
|
||||||
} from './release_version_actions';
|
} from './release_version_actions';
|
||||||
import {
|
import {
|
||||||
|
displaySelectAppPlatform,
|
||||||
setAllowMount,
|
setAllowMount,
|
||||||
setApplicationReady,
|
setApplicationReady,
|
||||||
|
setLinuxAppPlatform,
|
||||||
setRebootRequired,
|
setRebootRequired,
|
||||||
showWindow,
|
showWindow,
|
||||||
shutdownApplication
|
shutdownApplication
|
||||||
@@ -134,6 +137,43 @@ export const installDependency = (source, url, isWinFSP) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const installAndTestRelease = (source, version, appPlatform) => {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
if (ipcRenderer && getState().install.InstallTestActive) {
|
||||||
|
const extractReleaseComplete = (event, arg) => {
|
||||||
|
ipcRenderer.send(Constants.IPC_Delete_File, {
|
||||||
|
FilePath: source,
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcRenderer.once(Constants.IPC_Test_Release_Reply, (event, arg) => {
|
||||||
|
if (arg.data.Success) {
|
||||||
|
ipcRenderer.sendSync(Constants.IPC_Set_Linux_AppPlatform, {
|
||||||
|
AppPlatform: appPlatform,
|
||||||
|
});
|
||||||
|
dispatch(setLinuxAppPlatform(appPlatform));
|
||||||
|
dispatch(setInstallTestActive(false));
|
||||||
|
dispatch(displaySelectAppPlatform(false));
|
||||||
|
dispatch(setAllowDownload(false));
|
||||||
|
dispatch(loadReleases());
|
||||||
|
} else {
|
||||||
|
dispatch(notifyError(arg.data.Error));
|
||||||
|
dispatch(setInstallTestActive(false));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ipcRenderer.send(Constants.IPC_Test_Release, {
|
||||||
|
Version: version,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
ipcRenderer.once(Constants.IPC_Extract_Release_Complete, extractReleaseComplete);
|
||||||
|
ipcRenderer.send(Constants.IPC_Extract_Release, {
|
||||||
|
Source: source,
|
||||||
|
Version: version,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const installRelease = source => {
|
export const installRelease = source => {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
if (ipcRenderer && !getState().install.InstallActive) {
|
if (ipcRenderer && !getState().install.InstallActive) {
|
||||||
@@ -193,5 +233,6 @@ export const installUpgrade = (source, sha256, signature, skipVerification) => {
|
|||||||
|
|
||||||
export const setDismissDependencies = createAction('install/setDismissDependencies');
|
export const setDismissDependencies = createAction('install/setDismissDependencies');
|
||||||
export const setInstallActive = createAction('install/setInstallActive');
|
export const setInstallActive = createAction('install/setInstallActive');
|
||||||
|
export const setInstallTestActive = createAction('install/setInstallTestActive');
|
||||||
export const setInstallComplete = createAction('install/setInstallComplete');
|
export const setInstallComplete = createAction('install/setInstallComplete');
|
||||||
export const setMissingDependencies = createAction('install/setMissingDependencies');
|
export const setMissingDependencies = createAction('install/setMissingDependencies');
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import {
|
|||||||
notifyRebootRequired,
|
notifyRebootRequired,
|
||||||
setAllowMount,
|
setAllowMount,
|
||||||
setApplicationReady,
|
setApplicationReady,
|
||||||
|
setLinuxAppPlatform,
|
||||||
|
SET_DISPLAY_SELECT_APPPLATFORM
|
||||||
} from '../actions/common_actions';
|
} from '../actions/common_actions';
|
||||||
|
|
||||||
export const createCommonReducer = (platform, appPlatform, version) => {
|
export const createCommonReducer = (platform, appPlatform, version) => {
|
||||||
@@ -10,10 +12,17 @@ export const createCommonReducer = (platform, appPlatform, version) => {
|
|||||||
AllowMount: false,
|
AllowMount: false,
|
||||||
AppPlatform: appPlatform,
|
AppPlatform: appPlatform,
|
||||||
AppReady: false,
|
AppReady: false,
|
||||||
|
DisplaySelectAppPlatform: false,
|
||||||
Platform: platform,
|
Platform: platform,
|
||||||
RebootRequired: false,
|
RebootRequired: false,
|
||||||
Version: version,
|
Version: version,
|
||||||
}, {
|
}, {
|
||||||
|
[SET_DISPLAY_SELECT_APPPLATFORM]: (state, action) => {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
DisplaySelectAppPlatform: action.payload,
|
||||||
|
}
|
||||||
|
},
|
||||||
[setAllowMount]: (state, action) => {
|
[setAllowMount]: (state, action) => {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
@@ -26,6 +35,12 @@ export const createCommonReducer = (platform, appPlatform, version) => {
|
|||||||
AppReady: action.payload,
|
AppReady: action.payload,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
[setLinuxAppPlatform]: (state, action) => {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
AppPlatform: action.payload,
|
||||||
|
}
|
||||||
|
},
|
||||||
[notifyRebootRequired]: (state, action) => {
|
[notifyRebootRequired]: (state, action) => {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
import {createReducer} from 'redux-starter-kit';
|
import {createReducer} from 'redux-starter-kit';
|
||||||
import {
|
import {
|
||||||
CLEAR_ERROR,
|
CLEAR_ERROR,
|
||||||
SET_ERROR_INFO
|
CLEAR_INFO,
|
||||||
|
SET_ERROR_INFO,
|
||||||
|
SET_INFO
|
||||||
} from '../actions/error_actions';
|
} from '../actions/error_actions';
|
||||||
|
|
||||||
export const errorReducer = createReducer({
|
export const errorReducer = createReducer({
|
||||||
DisplayError: false,
|
DisplayError: false,
|
||||||
|
DisplayInfo: false,
|
||||||
ErrorCritical: false,
|
ErrorCritical: false,
|
||||||
ErrorStack: [],
|
ErrorStack: [],
|
||||||
|
InfoStack: [],
|
||||||
}, {
|
}, {
|
||||||
[CLEAR_ERROR]: state => {
|
[CLEAR_ERROR]: state => {
|
||||||
const errorStack = (state.ErrorStack.length > 0) ? state.ErrorStack.slice(1) : [];
|
const errorStack = (state.ErrorStack.length > 0) ? state.ErrorStack.slice(1) : [];
|
||||||
@@ -17,6 +21,14 @@ export const errorReducer = createReducer({
|
|||||||
ErrorStack: errorStack,
|
ErrorStack: errorStack,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
[CLEAR_INFO]: state => {
|
||||||
|
const infoStack = (state.InfoStack.length > 0) ? state.InfoStack.slice(1) : [];
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
DisplayInfo: (infoStack.length > 0),
|
||||||
|
InfoStack: infoStack,
|
||||||
|
}
|
||||||
|
},
|
||||||
[SET_ERROR_INFO]: (state, action) => {
|
[SET_ERROR_INFO]: (state, action) => {
|
||||||
const errorStack = [action.payload.msg, ...state.ErrorStack];
|
const errorStack = [action.payload.msg, ...state.ErrorStack];
|
||||||
return {
|
return {
|
||||||
@@ -25,5 +37,16 @@ export const errorReducer = createReducer({
|
|||||||
ErrorCritical: state.ErrorCritical || action.payload.critical,
|
ErrorCritical: state.ErrorCritical || action.payload.critical,
|
||||||
ErrorStack: errorStack,
|
ErrorStack: errorStack,
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
[SET_INFO]: (state, action) => {
|
||||||
|
const infoStack = [{
|
||||||
|
title: action.payload.title,
|
||||||
|
message: action.payload.msg
|
||||||
|
}, ...state.InfoStack];
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
DisplayInfo: true,
|
||||||
|
InfoStack: infoStack,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -3,6 +3,7 @@ import {
|
|||||||
setDismissDependencies,
|
setDismissDependencies,
|
||||||
setInstallActive,
|
setInstallActive,
|
||||||
setInstallComplete,
|
setInstallComplete,
|
||||||
|
setInstallTestActive,
|
||||||
setMissingDependencies
|
setMissingDependencies
|
||||||
} from '../actions/install_actions';
|
} from '../actions/install_actions';
|
||||||
|
|
||||||
@@ -10,6 +11,7 @@ export const installReducer = createReducer({
|
|||||||
DismissDependencies: false,
|
DismissDependencies: false,
|
||||||
InstallActive: false,
|
InstallActive: false,
|
||||||
InstallResult: null,
|
InstallResult: null,
|
||||||
|
InstallTestActive: false,
|
||||||
InstallType: null,
|
InstallType: null,
|
||||||
MissingDependencies: [],
|
MissingDependencies: [],
|
||||||
}, {
|
}, {
|
||||||
@@ -35,6 +37,12 @@ export const installReducer = createReducer({
|
|||||||
InstallType: null,
|
InstallType: null,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
[setInstallTestActive]: (state, action) => {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
InstallTestActive: action.payload,
|
||||||
|
}
|
||||||
|
},
|
||||||
[setMissingDependencies]: (state, action) => {
|
[setMissingDependencies]: (state, action) => {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
|||||||
20
src/renderer/ipc/AppIPC.js
Normal file
20
src/renderer/ipc/AppIPC.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
const Constants = require('../../constants');
|
||||||
|
|
||||||
|
const addListeners = (ipcMain, closeApplication, setWindowVisibility) => {
|
||||||
|
ipcMain.on(Constants.IPC_Shutdown, () => {
|
||||||
|
closeApplication();
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on(Constants.IPC_Show_Window, () => {
|
||||||
|
setWindowVisibility(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on(Constants.IPC_Show_Window + '_sync', event => {
|
||||||
|
setWindowVisibility(true);
|
||||||
|
event.returnValue = true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
addListeners
|
||||||
|
};
|
||||||
56
src/renderer/ipc/ConfigIPC.js
Normal file
56
src/renderer/ipc/ConfigIPC.js
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
const Constants = require('../../constants');
|
||||||
|
const helpers = require('../../helpers');
|
||||||
|
|
||||||
|
const addListeners = (ipcMain, standardIPCReply) => {
|
||||||
|
ipcMain.on(Constants.IPC_Get_Config, (event, data) => {
|
||||||
|
helpers
|
||||||
|
.getConfig(data.Version, data.Provider)
|
||||||
|
.then((data) => {
|
||||||
|
if (data.Code === 0) {
|
||||||
|
standardIPCReply(event, Constants.IPC_Get_Config_Reply, {
|
||||||
|
Config: data.Data,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
standardIPCReply(event, Constants.IPC_Get_Config_Reply, {}, data.Code);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
standardIPCReply(event, Constants.IPC_Get_Config_Reply, {}, error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on(Constants.IPC_Get_Config_Template, (event, data) => {
|
||||||
|
helpers
|
||||||
|
.getConfigTemplate(data.Version, data.Provider)
|
||||||
|
.then((data) => {
|
||||||
|
standardIPCReply(event, Constants.IPC_Get_Config_Template_Reply, {
|
||||||
|
Template: data,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
standardIPCReply(event, Constants.IPC_Get_Config_Template_Reply, {}, error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on(Constants.IPC_Set_Config_Values, (event, data) => {
|
||||||
|
const setConfigValue = (i) => {
|
||||||
|
if (i < data.Items.length) {
|
||||||
|
helpers
|
||||||
|
.setConfigValue(data.Items[i].Name, data.Items[i].Value, data.Provider, data.Version)
|
||||||
|
.then(() => {
|
||||||
|
setConfigValue(++i);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setConfigValue(++i);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
standardIPCReply(event, Constants.IPC_Set_Config_Values_Reply, {});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
setConfigValue(0);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
addListeners
|
||||||
|
};
|
||||||
47
src/renderer/ipc/DaemonIPC.js
Normal file
47
src/renderer/ipc/DaemonIPC.js
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
const Constants = require('../../constants');
|
||||||
|
const helpers = require('../../helpers');
|
||||||
|
|
||||||
|
const addListeners = (ipcMain, standardIPCReply) => {
|
||||||
|
ipcMain.on(Constants.IPC_Check_Daemon_Version, (event, data) => {
|
||||||
|
helpers
|
||||||
|
.checkDaemonVersion(data.Version, data.Provider)
|
||||||
|
.then(code => {
|
||||||
|
standardIPCReply(event, Constants.IPC_Check_Daemon_Version_Reply, {
|
||||||
|
Valid: (code === 0),
|
||||||
|
Code: code,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
standardIPCReply(event, Constants.IPC_Check_Daemon_Version_Reply, {
|
||||||
|
Valid: false,
|
||||||
|
}, e);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on(Constants.IPC_Check_Daemon_Version + '_sync', (event, data) => {
|
||||||
|
helpers
|
||||||
|
.checkDaemonVersion(data.Version, data.Provider)
|
||||||
|
.then(code => {
|
||||||
|
event.returnValue = {
|
||||||
|
data: {
|
||||||
|
Success: true,
|
||||||
|
Valid: (code === 0),
|
||||||
|
Code: code,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
event.returnValue = {
|
||||||
|
data: {
|
||||||
|
Error: e.toString(),
|
||||||
|
Success: false,
|
||||||
|
Valid: false
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
addListeners
|
||||||
|
};
|
||||||
102
src/renderer/ipc/DependencyIPC.js
Normal file
102
src/renderer/ipc/DependencyIPC.js
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
const Constants = require('../../constants');
|
||||||
|
const fs = require('fs');
|
||||||
|
const helpers = require('../../helpers');
|
||||||
|
|
||||||
|
const addListeners = (ipcMain, standardIPCReply) => {
|
||||||
|
ipcMain.on(Constants.IPC_Check_Dependency_Installed, (event, data) => {
|
||||||
|
try {
|
||||||
|
const exists = fs.lstatSync(data.File).isFile();
|
||||||
|
standardIPCReply(event, Constants.IPC_Check_Dependency_Installed_Reply, {
|
||||||
|
data: {
|
||||||
|
Exists: exists,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
standardIPCReply(event, Constants.IPC_Check_Dependency_Installed_Reply, {
|
||||||
|
data : {
|
||||||
|
Exists: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on(Constants.IPC_Check_Dependency_Installed + '_sync', (event, data) => {
|
||||||
|
try {
|
||||||
|
const ls = fs.lstatSync(data.File);
|
||||||
|
event.returnValue = {
|
||||||
|
data: {
|
||||||
|
Exists: ls.isFile() || ls.isSymbolicLink(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
event.returnValue = {
|
||||||
|
data: {
|
||||||
|
Exists: false
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on(Constants.IPC_Install_Dependency, (event, data) => {
|
||||||
|
if (data.Source.toLowerCase().endsWith('.dmg')) {
|
||||||
|
helpers
|
||||||
|
.executeAsync('open', ['-a', 'Finder', '-W', data.Source])
|
||||||
|
.then(() => {
|
||||||
|
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
||||||
|
Source: data.Source,
|
||||||
|
URL: data.URL,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(error=> {
|
||||||
|
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
||||||
|
Source: data.Source,
|
||||||
|
URL: data.URL,
|
||||||
|
}, error);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const execInstall = () => {
|
||||||
|
helpers
|
||||||
|
.executeAndWait(data.Source)
|
||||||
|
.then(() => {
|
||||||
|
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
||||||
|
Source: data.Source,
|
||||||
|
URL: data.URL,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
||||||
|
Source: data.Source,
|
||||||
|
URL: data.URL,
|
||||||
|
}, error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
if (data.IsWinFSP) {
|
||||||
|
helpers
|
||||||
|
.performWindowsUninstall(["WinFsp 2019.1", "WinFsp 2019.2", "WinFsp 2019.3 B1", "WinFsp 2019.3 B2"])
|
||||||
|
.then(uninstalled => {
|
||||||
|
if (uninstalled) {
|
||||||
|
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
||||||
|
RebootRequired: true,
|
||||||
|
Source: data.Source,
|
||||||
|
URL: data.URL,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
execInstall();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
||||||
|
Source: data.Source,
|
||||||
|
URL: data.URL,
|
||||||
|
}, error);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
execInstall();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
addListeners
|
||||||
|
};
|
||||||
25
src/renderer/ipc/DownloadIPC.js
Normal file
25
src/renderer/ipc/DownloadIPC.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
const Constants = require('../../constants');
|
||||||
|
const helpers = require('../../helpers');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const addListeners = (ipcMain, standardIPCReply) => {
|
||||||
|
ipcMain.on(Constants.IPC_Download_File, (event, data) => {
|
||||||
|
const destination = path.join(helpers.getDataDirectory(), data.Filename);
|
||||||
|
helpers.downloadFile(data.URL, destination, (progress) => {
|
||||||
|
standardIPCReply(event, Constants.IPC_Download_File_Progress, {
|
||||||
|
Destination: destination,
|
||||||
|
Progress: progress,
|
||||||
|
URL: data.URL,
|
||||||
|
});
|
||||||
|
}, error => {
|
||||||
|
standardIPCReply(event, Constants.IPC_Download_File_Complete, {
|
||||||
|
Destination: destination,
|
||||||
|
URL: data.URL,
|
||||||
|
}, error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
addListeners
|
||||||
|
};
|
||||||
31
src/renderer/ipc/FilesystemIPC.js
Normal file
31
src/renderer/ipc/FilesystemIPC.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
const Constants = require('../../constants');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
const addListeners = (ipcMain, getMainWindow, dialog) => {
|
||||||
|
ipcMain.on(Constants.IPC_Browse_Directory + '_sync', (event, data) => {
|
||||||
|
dialog.showOpenDialog(getMainWindow(), {
|
||||||
|
defaultPath: data.Location,
|
||||||
|
properties: ['openDirectory'],
|
||||||
|
title: data.Title,
|
||||||
|
}, (filePaths) => {
|
||||||
|
if (filePaths && (filePaths.length > 0)) {
|
||||||
|
event.returnValue = filePaths[0];
|
||||||
|
} else {
|
||||||
|
event.returnValue = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on(Constants.IPC_Delete_File, (event, data) => {
|
||||||
|
try {
|
||||||
|
if (fs.existsSync(data.FilePath)) {
|
||||||
|
fs.unlinkSync(data.FilePath);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
addListeners
|
||||||
|
};
|
||||||
249
src/renderer/ipc/MountsIPC.js
Normal file
249
src/renderer/ipc/MountsIPC.js
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
const Constants = require('../../constants');
|
||||||
|
const fs = require('fs');
|
||||||
|
const helpers = require('../../helpers');
|
||||||
|
const os = require('os');
|
||||||
|
|
||||||
|
let expectedUnmount = {};
|
||||||
|
let firstMountCheck = true;
|
||||||
|
let manualMountDetection = {};
|
||||||
|
let mountedData = {};
|
||||||
|
let mountedLocations = [];
|
||||||
|
|
||||||
|
const clearManualMountDetection = provider => {
|
||||||
|
if (manualMountDetection[provider]) {
|
||||||
|
clearInterval(manualMountDetection[provider]);
|
||||||
|
delete manualMountDetection[provider];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const monitorMount = (sender, provider, version, pid, location) => {
|
||||||
|
manualMountDetection[provider] = setInterval(() => {
|
||||||
|
helpers
|
||||||
|
.detectRepertoryMounts(version)
|
||||||
|
.then(result => {
|
||||||
|
if (result[provider].PID !== pid) {
|
||||||
|
if (result[provider].PID === -1) {
|
||||||
|
clearManualMountDetection(provider);
|
||||||
|
sender.send(Constants.IPC_Unmount_Drive_Reply, {
|
||||||
|
data: {
|
||||||
|
Expected: expectedUnmount[provider],
|
||||||
|
Location: location,
|
||||||
|
Provider: provider,
|
||||||
|
Error: Error(provider + ' Unmounted').toString(),
|
||||||
|
Success: false,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
pid = result[provider].PID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
console.log(e);
|
||||||
|
});
|
||||||
|
},6000);
|
||||||
|
};
|
||||||
|
|
||||||
|
const unmountAllDrives = () => {
|
||||||
|
// Reset mount states
|
||||||
|
for (const provider of Constants.PROVIDER_LIST) {
|
||||||
|
clearManualMountDetection(provider);
|
||||||
|
expectedUnmount[provider] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmount all items
|
||||||
|
for (const i in mountedLocations) {
|
||||||
|
const data = mountedData[mountedLocations[i]];
|
||||||
|
helpers.stopMountProcessSync(data.Version, data.Provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
mountedLocations = [];
|
||||||
|
mountedData = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
const addListeners = (ipcMain, setTrayImage, standardIPCReply) => {
|
||||||
|
ipcMain.on(Constants.IPC_Check_Mount_Location + '_sync', (event, data) => {
|
||||||
|
let response = {
|
||||||
|
Success: true,
|
||||||
|
Error: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (fs.existsSync(data.Location) && fs.statSync(data.Location).isDirectory()) {
|
||||||
|
if (fs.readdirSync(data.Location).length !== 0) {
|
||||||
|
response.Success = false;
|
||||||
|
response.Error = 'Directory not empty: ' + data.Location;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
response.Success = false;
|
||||||
|
response.Error = 'Directory not found: ' + data.Location;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
response.Success = false;
|
||||||
|
response.Error = e.toString();
|
||||||
|
}
|
||||||
|
event.returnValue = response;
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on(Constants.IPC_Detect_Mounts, (event, data) => {
|
||||||
|
let driveLetters = {};
|
||||||
|
for (const provider of Constants.PROVIDER_LIST) {
|
||||||
|
driveLetters[provider] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const grabDriveLetters = (locations) => {
|
||||||
|
for (let i = 'c'.charCodeAt(0); i <= 'z'.charCodeAt(0); i++) {
|
||||||
|
const drive = (String.fromCharCode(i) + ':').toUpperCase();
|
||||||
|
let driveInUse;
|
||||||
|
if (Object.keys(locations).length > 0) {
|
||||||
|
for (const provider of Constants.PROVIDER_LIST) {
|
||||||
|
driveInUse = locations[provider].startsWith(drive);
|
||||||
|
if (driveInUse)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!driveInUse) {
|
||||||
|
try {
|
||||||
|
if (!fs.existsSync(drive)) {
|
||||||
|
for (const provider of Constants.PROVIDER_LIST) {
|
||||||
|
driveLetters[provider].push(drive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Object.keys(locations).length > 0) {
|
||||||
|
for (const provider of Constants.PROVIDER_LIST) {
|
||||||
|
if (locations[provider].length > 0) {
|
||||||
|
if (!driveLetters[provider].find((driveLetter) => {
|
||||||
|
return driveLetter === locations[provider];
|
||||||
|
})) {
|
||||||
|
driveLetters[provider].push(locations[provider]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const setImage = (locations) => {
|
||||||
|
let driveInUse;
|
||||||
|
if (Object.keys(locations).length > 0) {
|
||||||
|
for (const provider of Constants.PROVIDER_LIST) {
|
||||||
|
driveInUse = locations[provider].length > 0;
|
||||||
|
if (driveInUse)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setTrayImage(driveInUse)
|
||||||
|
};
|
||||||
|
|
||||||
|
helpers
|
||||||
|
.detectRepertoryMounts(data.Version)
|
||||||
|
.then((results) => {
|
||||||
|
let storageData = {};
|
||||||
|
let locations = {};
|
||||||
|
for (const provider of Constants.PROVIDER_LIST) {
|
||||||
|
storageData[provider] = results[provider] ? results[provider] : {
|
||||||
|
Active: false,
|
||||||
|
Location: '',
|
||||||
|
PID: -1,
|
||||||
|
};
|
||||||
|
locations[provider] = storageData[provider].Location;
|
||||||
|
|
||||||
|
if (storageData[provider].PID !== -1) {
|
||||||
|
expectedUnmount[provider] = false;
|
||||||
|
if (firstMountCheck) {
|
||||||
|
monitorMount(event.sender, provider, data.Version, storageData[provider].PID, storageData[provider].Location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (os.platform() === 'win32') {
|
||||||
|
grabDriveLetters(locations);
|
||||||
|
}
|
||||||
|
|
||||||
|
setImage(locations);
|
||||||
|
if (firstMountCheck) {
|
||||||
|
firstMountCheck = false;
|
||||||
|
}
|
||||||
|
standardIPCReply(event, Constants.IPC_Detect_Mounts_Reply, {
|
||||||
|
DriveLetters: driveLetters,
|
||||||
|
Locations: locations,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (os.platform() === 'win32') {
|
||||||
|
grabDriveLetters({});
|
||||||
|
}
|
||||||
|
setImage({});
|
||||||
|
standardIPCReply(event, Constants.IPC_Detect_Mounts_Reply, {
|
||||||
|
DriveLetters: driveLetters,
|
||||||
|
}, error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on(Constants.IPC_Mount_Drive, (event, data) => {
|
||||||
|
expectedUnmount[data.Provider] = false;
|
||||||
|
|
||||||
|
if (mountedLocations.indexOf(data.Location) !== -1) {
|
||||||
|
console.log(data.Provider + ' already mounted: ' + data.Location);
|
||||||
|
} else {
|
||||||
|
mountedLocations.push(data.Location);
|
||||||
|
mountedData[data.Location] = {
|
||||||
|
Version: data.Version,
|
||||||
|
Provider: data.Provider,
|
||||||
|
};
|
||||||
|
const errorHandler = (pid, error) => {
|
||||||
|
if (mountedLocations.indexOf(data.Location) !== -1) {
|
||||||
|
mountedLocations.splice(mountedLocations.indexOf(data.Location), 1);
|
||||||
|
delete mountedData[data.Location];
|
||||||
|
}
|
||||||
|
|
||||||
|
standardIPCReply(event, Constants.IPC_Unmount_Drive_Reply, {
|
||||||
|
Expected: expectedUnmount[data.Provider],
|
||||||
|
Location: data.Location,
|
||||||
|
Provider: data.Provider,
|
||||||
|
}, error || Error(data.Provider + ' Unmounted'));
|
||||||
|
};
|
||||||
|
helpers
|
||||||
|
.executeMount(data.Version, data.Provider, data.Location, data.NoConsoleSupported, (error, pid) => {
|
||||||
|
errorHandler(pid, error);
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
standardIPCReply(event, Constants.IPC_Mount_Drive_Reply, {
|
||||||
|
Provider: data.Provider,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
errorHandler(-1, error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on(Constants.IPC_Unmount_All_Drives, (event, data) => {
|
||||||
|
unmountAllDrives();
|
||||||
|
standardIPCReply(event, Constants.IPC_Unmount_All_Drives_Reply);
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on(Constants.IPC_Unmount_Drive, (event, data) => {
|
||||||
|
clearManualMountDetection(data.Provider);
|
||||||
|
|
||||||
|
expectedUnmount[data.Provider] = true;
|
||||||
|
helpers
|
||||||
|
.stopMountProcess(data.Version, data.Provider)
|
||||||
|
.then(result => {
|
||||||
|
console.log(result);
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
console.log(e);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
addListeners,
|
||||||
|
unmountAllDrives
|
||||||
|
};
|
||||||
79
src/renderer/ipc/PlatformIPC.js
Normal file
79
src/renderer/ipc/PlatformIPC.js
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
const Constants = require('../../constants');
|
||||||
|
const fs = require('fs');
|
||||||
|
const helpers = require('../../helpers');
|
||||||
|
const os = require('os');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
let _platformOverride;
|
||||||
|
|
||||||
|
const getPlatformOverride = () => {
|
||||||
|
return _platformOverride;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setPlatformOverride = platformOverride => {
|
||||||
|
_platformOverride = platformOverride;
|
||||||
|
};
|
||||||
|
|
||||||
|
const addListeners = (ipcMain, detectScript, saveUiSettings) => {
|
||||||
|
ipcMain.on(Constants.IPC_Get_Platform, (event) => {
|
||||||
|
const sendResponse = (appPlatform, platform) => {
|
||||||
|
event.sender.send(Constants.IPC_Get_Platform_Reply, {
|
||||||
|
AppPlatform: appPlatform,
|
||||||
|
Platform: platform,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const platform = os.platform();
|
||||||
|
if (platform === 'linux') {
|
||||||
|
if (_platformOverride && (_platformOverride.length > 0)) {
|
||||||
|
sendResponse(_platformOverride, 'linux');
|
||||||
|
} else {
|
||||||
|
const scriptFile = path.join(os.tmpdir(), 'repertory_detect_linux.sh');
|
||||||
|
fs.writeFileSync(scriptFile, detectScript);
|
||||||
|
|
||||||
|
helpers
|
||||||
|
.executeScript(scriptFile)
|
||||||
|
.then(data => {
|
||||||
|
let appPlatform = data.replace(/(\r\n|\n|\r)/gm, "");
|
||||||
|
if (appPlatform === 'unknown') {
|
||||||
|
helpers
|
||||||
|
.downloadFile(Constants.LINUX_DETECT_SCRIPT_URL, scriptFile, null, err => {
|
||||||
|
if (err) {
|
||||||
|
sendResponse(appPlatform, platform);
|
||||||
|
} else {
|
||||||
|
helpers
|
||||||
|
.executeScript(scriptFile)
|
||||||
|
.then(data => {
|
||||||
|
appPlatform = data.replace(/(\r\n|\n|\r)/gm, "");
|
||||||
|
sendResponse(appPlatform, platform);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
sendResponse(appPlatform, platform);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
sendResponse(appPlatform, platform);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
sendResponse(platform, platform);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sendResponse(platform, platform);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on(Constants.IPC_Set_Linux_AppPlatform, (event, data) => {
|
||||||
|
setPlatformOverride(data.AppPlatform);
|
||||||
|
saveUiSettings();
|
||||||
|
event.returnValue = true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getPlatformOverride,
|
||||||
|
setPlatformOverride,
|
||||||
|
addListeners
|
||||||
|
};
|
||||||
87
src/renderer/ipc/ReleaseIPC.js
Normal file
87
src/renderer/ipc/ReleaseIPC.js
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
const Constants = require('../../constants');
|
||||||
|
const fs = require('fs');
|
||||||
|
const helpers = require('../../helpers');
|
||||||
|
const os = require('os');
|
||||||
|
const path = require('path');
|
||||||
|
const unzip = require('unzipper');
|
||||||
|
|
||||||
|
const addListeners = (ipcMain, standardIPCReply) => {
|
||||||
|
ipcMain.on(Constants.IPC_Check_Installed, (event, data) => {
|
||||||
|
const destination = path.join(helpers.getDataDirectory(), data.Version);
|
||||||
|
helpers
|
||||||
|
.getMissingDependencies(data.Dependencies)
|
||||||
|
.then((dependencies) => {
|
||||||
|
let exists = false;
|
||||||
|
try {
|
||||||
|
exists = fs.existsSync(destination) && fs.lstatSync(destination).isDirectory();
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
standardIPCReply(event, Constants.IPC_Check_Installed_Reply, {
|
||||||
|
Dependencies: dependencies,
|
||||||
|
Exists: exists,
|
||||||
|
Version: data.Version,
|
||||||
|
});
|
||||||
|
}).catch(error => {
|
||||||
|
standardIPCReply(event, Constants.IPC_Check_Installed_Reply, {
|
||||||
|
Dependencies: [],
|
||||||
|
Version: data.Version,
|
||||||
|
}, error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on(Constants.IPC_Extract_Release, (event, data) => {
|
||||||
|
const destination = path.join(helpers.getDataDirectory(), data.Version);
|
||||||
|
helpers.removeDirectoryRecursively(destination);
|
||||||
|
helpers.mkDirByPathSync(destination);
|
||||||
|
|
||||||
|
const stream = fs.createReadStream(data.Source);
|
||||||
|
stream
|
||||||
|
.pipe(unzip.Extract({ path: destination }))
|
||||||
|
.on('error', error => {
|
||||||
|
try {
|
||||||
|
helpers.removeDirectoryRecursively(destination);
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
stream.close();
|
||||||
|
standardIPCReply(event, Constants.IPC_Extract_Release_Complete, {
|
||||||
|
Source: data.Source,
|
||||||
|
}, error);
|
||||||
|
})
|
||||||
|
.on('finish', () => {
|
||||||
|
stream.close();
|
||||||
|
if (os.platform() !== 'win32') {
|
||||||
|
helpers
|
||||||
|
.executeAndWait("chmod +x \"" + path.join(destination, 'repertory') + "\"")
|
||||||
|
.then(() => {
|
||||||
|
standardIPCReply(event, Constants.IPC_Extract_Release_Complete, {
|
||||||
|
Source: data.Source,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
standardIPCReply(event, Constants.IPC_Extract_Release_Complete, {
|
||||||
|
Source: data.Source,
|
||||||
|
}, error);
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
standardIPCReply(event, Constants.IPC_Extract_Release_Complete, {
|
||||||
|
Source: data.Source,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on(Constants.IPC_Test_Release, (event, data) => {
|
||||||
|
helpers
|
||||||
|
.testRepertoryBinary(data.Version)
|
||||||
|
.then(() => {
|
||||||
|
standardIPCReply(event, Constants.IPC_Test_Release_Reply, {});
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
standardIPCReply(event, Constants.IPC_Test_Release_Reply, {}, error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
addListeners
|
||||||
|
};
|
||||||
30
src/renderer/ipc/StateIPC.js
Normal file
30
src/renderer/ipc/StateIPC.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
const Constants = require('../../constants');
|
||||||
|
const fs = require('fs');
|
||||||
|
const helpers = require('../../helpers');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const addListeners = ipcMain => {
|
||||||
|
ipcMain.on(Constants.IPC_Get_State, event => {
|
||||||
|
helpers.mkDirByPathSync(helpers.getDataDirectory());
|
||||||
|
const configFile = path.join(helpers.getDataDirectory(), 'settings.json');
|
||||||
|
if (fs.existsSync(configFile)) {
|
||||||
|
event.sender.send(Constants.IPC_Get_State_Reply, {
|
||||||
|
data: JSON.parse(fs.readFileSync(configFile, 'utf8')),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
event.sender.send(Constants.IPC_Get_State_Reply, {
|
||||||
|
data: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on(Constants.IPC_Save_State, (event, data) => {
|
||||||
|
helpers.mkDirByPathSync(helpers.getDataDirectory());
|
||||||
|
const configFile = path.join(helpers.getDataDirectory(), 'settings.json');
|
||||||
|
fs.writeFileSync(configFile, JSON.stringify(data.State), 'utf8');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
addListeners
|
||||||
|
};
|
||||||
16
src/renderer/ipc/SystemIPC.js
Normal file
16
src/renderer/ipc/SystemIPC.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
const Constants = require('../../constants');
|
||||||
|
const os = require('os');
|
||||||
|
const helpers = require('../../helpers');
|
||||||
|
|
||||||
|
const addListeners = (ipcMain, closeApplication) => {
|
||||||
|
ipcMain.on(Constants.IPC_Reboot_System, () => {
|
||||||
|
if (os.platform() === 'win32') {
|
||||||
|
helpers.executeAsync('shutdown.exe', ['/r', '/t', '30']);
|
||||||
|
}
|
||||||
|
closeApplication();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
addListeners
|
||||||
|
};
|
||||||
116
src/renderer/ipc/UpgradeIPC.js
Normal file
116
src/renderer/ipc/UpgradeIPC.js
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
const Constants = require('../../constants');
|
||||||
|
const fs = require('fs');
|
||||||
|
const helpers = require('../../helpers');
|
||||||
|
const os = require('os');
|
||||||
|
|
||||||
|
const addListeners = (ipcMain, setIsInstalling, unmountAllDrives, standardIPCReply) => {
|
||||||
|
ipcMain.on(Constants.IPC_Install_Upgrade, (event, data) => {
|
||||||
|
let allowSkipVerification = true;
|
||||||
|
|
||||||
|
unmountAllDrives();
|
||||||
|
|
||||||
|
let tempSig;
|
||||||
|
let tempPub;
|
||||||
|
const cleanupFiles = () => {
|
||||||
|
try {
|
||||||
|
if (tempSig) {
|
||||||
|
fs.unlinkSync(tempSig);
|
||||||
|
}
|
||||||
|
if (tempPub) {
|
||||||
|
fs.unlinkSync(tempPub);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const errorHandler = err => {
|
||||||
|
cleanupFiles();
|
||||||
|
setIsInstalling(false);
|
||||||
|
standardIPCReply(event, Constants.IPC_Install_Upgrade_Reply, {
|
||||||
|
AllowSkipVerification: allowSkipVerification,
|
||||||
|
Source: data.Source,
|
||||||
|
}, err);
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO Enable verification in 1.0.4
|
||||||
|
const hasSignature = false;//!data.SkipVerification && data.Signature && (data.Signature.length > 0);
|
||||||
|
const hasHash = false;//!data.SkipVerification && data.Sha256 && (data.Sha256.length > 0);
|
||||||
|
if (hasSignature) {
|
||||||
|
try {
|
||||||
|
const files = helpers.createSignatureFiles(data.Signature, Constants.DEV_PUBLIC_KEY);
|
||||||
|
tempPub = files.PublicKeyFile;
|
||||||
|
tempSig = files.SignatureFile;
|
||||||
|
} catch (e) {
|
||||||
|
errorHandler(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let command;
|
||||||
|
let args;
|
||||||
|
const platform = os.platform();
|
||||||
|
if (platform === 'win32') {
|
||||||
|
command = data.Source;
|
||||||
|
} else if (platform === 'darwin') {
|
||||||
|
command = 'open';
|
||||||
|
args = ['-a', 'Finder', data.Source];
|
||||||
|
} else if (platform === 'linux') {
|
||||||
|
try {
|
||||||
|
command = data.Source;
|
||||||
|
fs.chmodSync(command, '750');
|
||||||
|
} catch (e) {
|
||||||
|
errorHandler(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
errorHandler(Error('Platform not supported: ' + os.platform()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command) {
|
||||||
|
const executeInstall = () => {
|
||||||
|
setIsInstalling(true);
|
||||||
|
helpers
|
||||||
|
.executeAsync(command, args)
|
||||||
|
.then(() => {
|
||||||
|
cleanupFiles();
|
||||||
|
standardIPCReply(event, Constants.IPC_Install_Upgrade_Reply)
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
setIsInstalling(false);
|
||||||
|
errorHandler(error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (hasSignature) {
|
||||||
|
helpers
|
||||||
|
.verifySignature(data.Source, tempSig, tempPub)
|
||||||
|
.then(() => {
|
||||||
|
executeInstall();
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
errorHandler(Error('Failed to verify installation package signature'));
|
||||||
|
});
|
||||||
|
} else if (hasHash) {
|
||||||
|
helpers
|
||||||
|
.verifyHash(data.Source, data.Sha256)
|
||||||
|
.then(()=> {
|
||||||
|
executeInstall();
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
errorHandler(Error('Failed to verify installation package hash'));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (platform === 'darwin') {
|
||||||
|
setTimeout(executeInstall, 3000);
|
||||||
|
} else {
|
||||||
|
executeInstall();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
errorHandler(Error('Unsupported upgrade: ' + data.Source));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
addListeners
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user