import React, {Component} from 'react'; import axios from 'axios'; import styles from './App.css'; import Box from './components/UI/Box/Box'; import Configuration from './containers/Configuration/Configuration'; import CSSModules from 'react-css-modules'; import DependencyList from './components/DependencyList/DependencyList'; import DownloadProgress from './components/DownloadProgress/DownloadProgress'; import ErrorDetails from './components/ErrorDetails/ErrorDetails'; import Grid from './components/UI/Grid/Grid'; import Loading from './components/UI/Loading/Loading'; import Modal from './components/UI/Modal/Modal'; import MountItems from './containers/MountItems/MountItems'; import ReleaseVersionDisplay from './components/ReleaseVersionDisplay/ReleaseVersionDisplay'; import Text from './components/UI/Text/Text'; import UpgradeIcon from './components/UpgradeIcon/UpgradeIcon'; import UpgradeUI from './components/UpgradeUI/UpgradeUI'; const Constants = require('./constants'); const Scheduler = require('node-schedule'); let ipcRenderer = null; if (!process.versions.hasOwnProperty('electron')) { ipcRenderer = ((window && window.require) ? window.require('electron').ipcRenderer : null); } class App extends Component { constructor(props) { super(props); if (ipcRenderer) { ipcRenderer.on(Constants.IPC_Check_Installed_Reply, this.onCheckInstalledReply); ipcRenderer.on(Constants.IPC_Download_File_Complete, this.onDownloadFileComplete); ipcRenderer.on(Constants.IPC_Download_File_Progress, this.onDownloadFileProgress); ipcRenderer.on(Constants.IPC_Extract_Release_Complete, this.onExtractReleaseComplete); ipcRenderer.on(Constants.IPC_Get_State_Reply, this.onGetStateReply); ipcRenderer.on(Constants.IPC_Grab_Releases_Reply, this.onGrabReleasesReply); ipcRenderer.on(Constants.IPC_Grab_UI_Releases_Reply, this.onGrabUiReleasesReply); ipcRenderer.on(Constants.IPC_Install_Dependency_Reply, this.onInstallDependencyReply); ipcRenderer.on(Constants.IPC_Install_Upgrade_Reply, this.onInstallUpgradeReply); ipcRenderer.send(Constants.IPC_Get_State, Constants.DATA_LOCATIONS[this.props.platform]); Scheduler.scheduleJob('23 11 * * *', this.updateCheckScheduledJob); } } state = { AllowDownload: false, AutoMountProcessed: false, ConfigStorageType: null, DisplayError: false, DisplayMainContent: false, Error: null, ErrorAction: null, ErrorCritical: false, DownloadActive: false, DownloadProgress: 0.0, DownloadingDependency: false, DownloadName: '', DownloadingRelease: false, DownloadingUpgrade: false, ExtractActive: false, Hyperspace: { AutoMount: false, MountLocation: '', }, LocationsLookup: {}, MissingDependencies: [], MountsBusy: false, Platform: 'unknown', Release: 3, ReleaseTypes: [ 'Release', 'RC', 'Beta', 'Alpha', ], InstalledVersion: 'none', Sia: { AutoMount: false, MountLocation: '', }, UpgradeAvailable: false, UpgradeData: {}, UpgradeDismissed: false, Version: -1, VersionAvailable: false, VersionLookup: { Alpha: [ 'unavailable' ], Beta: [ 'unavailable' ], RC: [ 'unavailable' ], Release: [ 'unavailable' ], } }; checkVersionInstalled = (release, version, versionLookup) => { if (!versionLookup) { versionLookup = this.state.VersionLookup; } const selectedVersion = versionLookup[this.state.ReleaseTypes[release]][version]; this.setState({ AllowDownload: false, }); if (selectedVersion !== 'unavailable') { if (ipcRenderer) { let dependencies = []; if (this.state.LocationsLookup[selectedVersion] && this.state.LocationsLookup[selectedVersion].dependencies) { dependencies = this.state.LocationsLookup[selectedVersion].dependencies; } ipcRenderer.send(Constants.IPC_Check_Installed, { Dependencies: dependencies, Directory: Constants.DATA_LOCATIONS[this.props.platform], Version: selectedVersion, }); } } }; closeErrorDisplay = () => { if (this.state.ErrorAction) { this.state.ErrorAction(); } if (this.state.ErrorCritical) { if (ipcRenderer) { ipcRenderer.send(Constants.IPC_Shutdown); } } else { this.setState({ DisplayError: false, Error: null, }); } }; componentWillUnmount = () => { if (ipcRenderer) { ipcRenderer.removeListener(Constants.IPC_Check_Installed_Reply, this.onCheckInstalledReply); ipcRenderer.removeListener(Constants.IPC_Download_File_Complete, this.onDownloadFileComplete); ipcRenderer.removeListener(Constants.IPC_Download_File_Progress, this.onDownloadFileProgress); ipcRenderer.removeListener(Constants.IPC_Extract_Release_Complete, this.onExtractReleaseComplete); ipcRenderer.removeListener(Constants.IPC_Get_State_Reply, this.onGetStateReply); ipcRenderer.removeListener(Constants.IPC_Grab_Releases_Reply, this.onGrabReleasesReply); ipcRenderer.removeListener(Constants.IPC_Grab_UI_Releases_Reply, this.onGrabUiReleasesReply); ipcRenderer.removeListener(Constants.IPC_Install_Dependency_Reply, this.onInstallDependencyReply); ipcRenderer.removeListener(Constants.IPC_Install_Upgrade_Reply, this.onInstallUpgradeReply); } }; grabReleases = () => { if (this.props.platform !== 'unknown') { if (ipcRenderer) { ipcRenderer.send(Constants.IPC_Grab_Releases); ipcRenderer.send(Constants.IPC_Grab_UI_Releases); } } }; handleAutoMountChanged = (storageType, e) => { let sia = { ...this.state.Sia }; let hyperspace = { ...this.state.Hyperspace }; if (storageType === 'Hyperspace') { hyperspace.AutoMount = e.target.checked; this.setState({ Hyperspace: hyperspace, }); } else if (storageType === 'Sia') { sia.AutoMount = e.target.checked; this.setState({ Sia: sia, }); } this.saveState(this.state.Release, this.state.Version, sia, hyperspace); }; handleConfigClicked = (storageType) => { this.setState({ ConfigStorageType: storageType, }) }; handleConfigClosed = () => { this.setState({ ConfigStorageType: null, }); }; handleDependencyDownload = (url) => { if (ipcRenderer) { const items = url.split('/'); const fileName = items[items.length - 1]; this.setState({ DownloadActive: true, DownloadingDependency: true, DownloadName: fileName, }); ipcRenderer.send(Constants.IPC_Download_File, { Directory: Constants.DATA_LOCATIONS[this.props.platform], Filename: fileName, URL: url, }); } }; handleMountLocationChanged = (storageType, location) => { const state = { ...this.state[storageType], MountLocation: location, }; this.setState({ [storageType]: state, }); const hyperspace = (storageType === 'Hyperspace') ? state : { ...this.state.Hyperspace, }; const sia = storageType === 'Sia' ? state : { ...this.state.Sia, }; this.saveState(this.state.Release, this.state.Version, sia, hyperspace); }; handleReleaseChanged = (e) => { const val = parseInt(e.target.value, 10); const versionIndex = this.state.VersionLookup[this.state.ReleaseTypes[val]].length - 1; this.setState({ Release: val, Version: versionIndex }); this.saveState(val, versionIndex, this.state.Sia, this.state.Hyperspace); this.checkVersionInstalled(val, versionIndex); }; handleReleaseDownload = () => { const selectedVersion = this.state.VersionLookup[this.state.ReleaseTypes[this.state.Release]][this.state.Version]; const fileName = selectedVersion + '.zip'; if (ipcRenderer) { this.setState({ DownloadActive: true, DownloadingRelease: true, DownloadName: fileName, }); ipcRenderer.send(Constants.IPC_Download_File, { Directory: Constants.DATA_LOCATIONS[this.props.platform], Filename: fileName, URL: this.state.LocationsLookup[selectedVersion].urls[0], }); } }; handleUIDownload = () => { if (ipcRenderer) { this.setState({ DownloadActive: true, DownloadingUpgrade: true, DownloadName: 'UI Upgrade', }); ipcRenderer.send(Constants.IPC_Download_File, { Directory: Constants.DATA_LOCATIONS[this.props.platform], Filename: this.props.platform === 'win32' ? 'upgrade.exe' : 'upgrade', URL: this.state.UpgradeData.urls[0], }); } else { this.setState({UpgradeDismissed: true}); } }; handleVersionChanged = (e) => { const val = parseInt(e.target.value, 10); this.setState({ Version: val }); this.saveState(this.state.Release, val, this.state.Sia, this.state.Hyperspace); this.checkVersionInstalled(this.state.Release, val); }; notifyAutoMountProcessed = () => { this.setState({AutoMountProcessed: true}); }; notifyMountsBusy = (busy) => { this.setState({MountsBusy: busy}) }; onCheckInstalledReply = (event, arg) => { const action = () => { const installedVersion = arg.data.Success && arg.data.Exists ? arg.data.Version : 'none'; let versionAvailable = false; if (installedVersion !== 'none') { const latestVersion = this.state.VersionLookup[this.state.ReleaseTypes[this.state.Release]].length - 1; let version = this.state.Version; if (version === -1) { version = latestVersion; } versionAvailable = version !== latestVersion; } this.setState({ AllowDownload: true, DownloadingDependency: false, MissingDependencies: arg.data.Dependencies, InstalledVersion: installedVersion, VersionAvailable: versionAvailable, }); }; if (arg.data.Success) { action(); } else { this.setErrorState(arg.data.Error, action); } }; onDownloadFileComplete = (event, arg) => { if (this.state.DownloadingRelease) { if (arg.data.Success) { const selectedVersion = this.state.VersionLookup[this.state.ReleaseTypes[this.state.Release]][this.state.Version]; ipcRenderer.send(Constants.IPC_Extract_Release, { Directory: Constants.DATA_LOCATIONS[this.props.platform], Source: arg.data.Destination, Version: selectedVersion, }); } this.setState({ DownloadActive: false, DownloadProgress: 0.0, DownloadingRelease: false, ExtractActive: arg.data.Success, DownloadName: '', }); } else if (this.state.DownloadingDependency) { if (arg.data.Success) { ipcRenderer.send(Constants.IPC_Install_Dependency, { Source: arg.data.Destination, }); } this.setState({ DownloadActive: false, DownloadProgress: 0.0, DownloadingDependency: arg.data.Success, DownloadName: '', }); } else if (this.state.DownloadingUpgrade) { if (arg.data.Success) { ipcRenderer.send(Constants.IPC_Install_Upgrade, { Source: arg.data.Destination, }); } else { this.setState({ DownloadActive: false, DownloadProgress: 0.0, DownloadingUpgrade: false, DownloadName: '', }); } } else { this.setState({ DownloadActive: false, DownloadProgress: 0.0, DownloadName: '', }); } }; onDownloadFileProgress = (event, arg) => { this.setState({ DownloadProgress: arg.data.Progress, }); }; onExtractReleaseComplete = (event, arg) => { ipcRenderer.send(Constants.IPC_Delete_File, { FilePath: arg.data.Source, }); this.setState({ ExtractActive: false, }); this.checkVersionInstalled(this.state.Release, this.state.Version); }; onGetStateReply = (event, arg) => { if (arg.data) { if (arg.data.Hyperspace.AutoMount === undefined) { arg.data.Hyperspace['AutoMount'] = false; } if (arg.data.Sia.AutoMount === undefined) { arg.data.Sia['AutoMount'] = false; } this.setState({ Hyperspace: arg.data.Hyperspace, Release: arg.data.Release, Sia: arg.data.Sia, Version: arg.data.Version, }); } this.grabReleases(); }; onGrabReleasesReply = ()=> { const doUpdate = (locationsLookup, versionLookup) => { const latestVersion = versionLookup[this.state.ReleaseTypes[this.state.Release]].length - 1; let version = this.state.Version; if ((version === -1) || !versionLookup[this.state.ReleaseTypes[this.state.Release]][version]) { version = latestVersion; this.saveState(this.state.Release, version, this.state.Sia, this.state.Hyperspace); } this.setState({ DisplayMainContent: true, LocationsLookup: locationsLookup, Version: version, VersionAvailable: version !== latestVersion, VersionLookup: versionLookup, }); this.checkVersionInstalled(this.state.Release, version, versionLookup); }; axios.get(Constants.RELEASES_URL) .then(response => { const versionLookup = { Alpha: response.data.Versions.Alpha[this.props.platform], Beta: response.data.Versions.Beta[this.props.platform], RC: response.data.Versions.RC[this.props.platform], Release: response.data.Versions.Release[this.props.platform], }; const locationsLookup = { ...response.data.Locations[this.props.platform], }; window.localStorage.setItem('releases', JSON.stringify({ LocationsLookup: locationsLookup, VersionLookup: versionLookup })); doUpdate(locationsLookup, versionLookup); }).catch(error => { const releases = window.localStorage.getItem('releases'); if (releases && (releases.length > 0)) { const obj = JSON.parse(releases); const locationsLookup = obj.LocationsLookup; const versionLookup = obj.VersionLookup; doUpdate(locationsLookup, versionLookup); } else { this.setErrorState(error, null, true); } }); }; onGrabUiReleasesReply = ()=> { axios.get(Constants.UI_RELEASES_URL) .then(response => { const data = response.data; if (data.Versions && data.Versions[this.props.platform] && (data.Versions[this.props.platform].length > 0) && (data.Versions[this.props.platform][0] !== this.props.version)) { this.setState({ UpgradeAvailable: true, UpgradeDismissed: false, UpgradeData: data.Locations[this.props.platform][data.Versions[this.props.platform][0]], }); } }).catch(() => { this.setState({ UpgradeAvailable: false, UpgradeData: {}, }); }); }; onInstallDependencyReply = (event, arg) => { ipcRenderer.send(Constants.IPC_Delete_File, { FilePath: arg.data.Source, }); this.checkVersionInstalled(this.state.Release, this.state.Version); }; onInstallUpgradeReply = (event, arg) => { ipcRenderer.sendSync(Constants.IPC_Delete_File, { FilePath: arg.data.Source, }); this.setState({ DownloadActive: false, DownloadProgress: 0.0, DownloadName: '', }); }; saveState = (release, version, sia, hyperspace)=> { if (ipcRenderer) { ipcRenderer.send(Constants.IPC_Save_State, { Directory: Constants.DATA_LOCATIONS[this.props.platform], State: { Hyperspace: hyperspace, Release: release, Sia: sia, Version: version, } }); } }; setErrorState = (error, action, critical) => { this.setState({ DisplayError: true, Error: error, ErrorAction: action, ErrorCritical: critical, }); }; updateCheckScheduledJob = () => { if (this.props.platform !== 'unknown') { this.grabReleases(); } }; render() { const selectedVersion = (this.state.Version === -1) ? 'unavailable' : this.state.VersionLookup[this.state.ReleaseTypes[this.state.Release]][this.state.Version]; const downloadEnabled = this.state.AllowDownload && !this.state.MountsBusy && !this.state.DownloadActive && (selectedVersion !== 'unavailable') && (selectedVersion !== this.state.InstalledVersion); const allowMount = this.state.InstalledVersion !== 'none'; const missingDependencies = (this.state.MissingDependencies.length > 0); const allowConfig = this.state.LocationsLookup[selectedVersion] && this.state.LocationsLookup[selectedVersion].config_support; const showDependencies = missingDependencies && !this.state.DownloadActive; const showConfig = !missingDependencies && this.state.ConfigStorageType && allowConfig; const showUpgrade = this.state.UpgradeAvailable && !this.state.DisplayError && !showConfig && !missingDependencies && !this.state.DownloadActive && !this.state.UpgradeDismissed; let errorDisplay = null; if (this.state.DisplayError) { errorDisplay = ( ); } let configDisplay = null; if (showConfig) { configDisplay = ( ); } let dependencyDisplay = null; if (showDependencies) { dependencyDisplay = ( } ) } let downloadDisplay = null; if (this.state.DownloadActive) { downloadDisplay = ( ); } let upgradeDisplay = null; if (showUpgrade) { upgradeDisplay = ( this.setState({UpgradeDismissed: true})} upgrade={this.handleUIDownload}/> ); } let mainContent = []; if (this.state.DisplayMainContent) { let key = 0; mainContent.push((
)); if (allowMount) { mainContent.push((
)); } } else { mainContent = } return (
{errorDisplay} {dependencyDisplay} {upgradeDisplay} {downloadDisplay} {configDisplay}
this.setState({UpgradeDismissed: false})} col={dimensions => dimensions.columns - 6} colSpan={5} row={1} rowSpan={remain=>remain - 2}/>
{mainContent}
); } } export default CSSModules(App, styles, {allowMultiple: true});