import React from 'react'; import './MountItems.css'; import AddMount from '../AddMount/AddMount'; import Box from '../../components/UI/Box/Box'; import Button from '../../components/UI/Button/Button'; import IPCContainer from '../IPCContainer/IPCContainer'; import Modal from '../../components/UI/Modal/Modal'; import MountItem from './MountItem/MountItem'; import {connect} from 'react-redux'; import {notifyError} from '../../redux/actions/error_actions'; import { resetMountsState, setAllowMount, setAutoMountProcessed, setBusy, setMounted, setMountState, setProviderState, } from '../../redux/actions/mount_actions'; const Constants = require('../../constants'); class MountItems extends IPCContainer { retryIntervals = {}; activeDetections = []; state = { DisplayRetry: false, RetryItems: {}, }; addMountsBusy = (provider) => { this.props.setMountsBusy(true); this.activeDetections.push(provider); }; cancelRetryMount = (provider, stateCallback) => { clearInterval(this.retryIntervals[provider]); delete this.retryIntervals[provider]; if (stateCallback) { let retryItems = { ...this.state.RetryItems, }; delete retryItems[provider]; this.setState( { DisplayRetry: Object.keys(retryItems).length > 0, RetryItems: retryItems, }, () => { if (this.state.DisplayRetry) { this.sendRequest(Constants.IPC_Show_Window); } stateCallback(); } ); } }; componentDidMount() { this.setRequestHandler(Constants.IPC_Detect_Mount_Reply, this.onDetectMountReply); this.setRequestHandler(Constants.IPC_Mount_Drive_Reply, this.onMountDriveReply); this.setRequestHandler(Constants.IPC_Unmount_Drive_Reply, this.onUnmountDriveReply); this.props.resetMountsState(); this.detectMounts(); } componentWillUnmount() { Object.keys(this.state.RetryItems).forEach((provider) => { this.cancelRetryMount(provider); }); this.props.resetMountsState(); this.activeDetections = []; super.componentWillUnmount(); } detectMount = (provider) => { this.addMountsBusy(provider); this.sendRequest(Constants.IPC_Detect_Mount, { RemoteMounts: this.props.RemoteMounts, S3Mounts: this.props.S3Mounts, Provider: provider, Version: this.props.InstalledVersion, }); }; detectMounts = () => { if (!this.state.DisplayRetry) { this.getProviderList().forEach((provider) => { this.detectMount(provider); }); } }; displayRetryMount = (provider, remote, s3, mountLocation, msg) => { if (!this.state.RetryItems[provider]) { let retryItems = { ...this.state.RetryItems, }; retryItems[provider] = { RetrySeconds: 10, RetryMessage: msg ? msg.toString() : null, }; const mountState = { AllowMount: false, Mounted: false, }; this.props.setMountState(provider, mountState); this.setState( { DisplayRetry: true, RetryItems: retryItems, }, () => { this.sendRequest(Constants.IPC_Show_Window); this.retryIntervals[provider] = setInterval(() => { const retryItems = { ...this.state.RetryItems, }; const retrySeconds = retryItems[provider].RetrySeconds - 1; if (retrySeconds === 0) { this.cancelRetryMount(provider, () => { this.handleMountUnMount(provider, remote, s3, true, mountLocation); }); } else { retryItems[provider].RetrySeconds = retrySeconds; this.setState({ RetryItems: retryItems, }); } }, 1000); } ); } }; handleBrowseLocation = (provider, location) => { location = this.sendSyncRequest(Constants.IPC_Browse_Directory, { Title: provider + ' Mount Location', Location: location, }); if (location && location.length > 0) { this.handleMountLocationChanged(provider, location); } }; handleMountLocationChanged = (provider, mountLocation) => { const state = { ...this.props.ProviderState[provider], MountLocation: mountLocation, }; this.props.setProviderState(provider, state); }; handleMountUnMount = (provider, remote, s3, mount, location) => { if (!location || location.trim().length === 0) { this.props.notifyError('Mount location is not set'); } else { let allowAction = true; if (mount) { let result = remote || s3 || provider === 'Skynet' ? {Valid: true, Success: true} : this.sendSyncRequest(Constants.IPC_Check_Daemon_Version, { Provider: provider, Remote: remote, S3: s3, Version: this.props.InstalledVersion, }).data; const displayRetry = (msg) => { this.displayRetryMount(provider, remote, s3, location, msg); }; if (result.Success) { if (result.Valid) { if (this.props.Platform !== 'win32') { result = this.sendSyncRequest(Constants.IPC_Check_Mount_Location, { Location: location, }); if (!result.Success) { allowAction = false; this.props.notifyError(result.Error.toString()); } } } else { allowAction = false; if ( result.Code === new Uint32Array([-1])[0] || result.Code === new Uint8Array([-1])[0] ) { displayRetry('Failed to connect to ' + provider + ' daemon'); } else if ( result.Code === new Uint32Array([-3])[0] || result.Code === new Uint8Array([-3])[0] ) { displayRetry( 'Incompatible ' + provider + ' daemon. Please upgrade ' + provider + '.' ); } else { displayRetry('Version check failed: ' + result.Error); } } } else { 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 { displayRetry('Version check failed: ' + result.Error); } } } if (allowAction) { this.addMountsBusy(provider); this.props.setAllowMount(provider, false); this.sendRequest(mount ? Constants.IPC_Mount_Drive : Constants.IPC_Unmount_Drive, { Location: location, Provider: provider, Remote: remote, S3: s3, Version: this.props.InstalledVersion, }); } } }; getProviderList = (providersOnly) => { const providerList = Constants.PROVIDER_LIST.filter((i) => { return ( (i === 'Skynet' && this.props.skynetSupported) || (i === 'ScPrime' && this.props.scPrimeSupported) || (i === 'Sia' && this.props.siaSupported) ); }); let remoteList = []; if (this.props.remoteSupported && !providersOnly) { remoteList = [...this.props.RemoteMounts]; } let s3List = []; if (this.props.s3Supported && !providersOnly) { s3List = [...this.props.S3Mounts]; } return [...providerList, ...remoteList, ...s3List]; }; hasActiveMount = () => { return !!Object.keys(this.props.MountState).find((provider) => { return this.props.MountState[provider].Mounted; }); }; onDetectMountReply = (_, arg) => { const provider = arg.data.Provider; if (!this.state.RetryItems[provider]) { if ( arg.data.Success && (!arg.data.Active || (arg.data.Location && arg.data.Location.length > 0)) ) { const mountState = { AllowMount: true, DriveLetters: arg.data.DriveLetters, Mounted: arg.data.Active, }; this.props.setMountState(provider, mountState); this.updateMountLocation( provider, arg.data.Location, mountState.Mounted, arg.data.DriveLetters ); this.props.setAutoMountProcessed(provider, true); this.removeMountsBusy(provider); } else { this.detectMount(provider); this.removeMountsBusy(provider); } } }; onMountDriveReply = (_, arg) => { this.props.setMounted(arg.data.Provider, arg.data.Success); this.detectMount(arg.data.Provider); this.removeMountsBusy(arg.data.Provider); }; onUnmountDriveReply = (_, arg) => { if ( arg && arg.data && !arg.data.Expected && arg.data.Location && this.props.ProviderState[arg.data.Provider].AutoRestart ) { this.displayRetryMount(arg.data.Provider, arg.data.Remote, arg.data.Location); } else { this.detectMount(arg.data.Provider); } this.removeMountsBusy(arg.data.Provider); }; removeMountsBusy = (provider) => { const idx = this.activeDetections.indexOf(provider); if (idx > -1) { this.activeDetections.splice(idx, 1); } this.props.setMountsBusy(this.activeDetections.length > 0 || this.hasActiveMount()); }; updateMountLocation = (provider, location, mounted, driveLetters) => { const providerState = this.props.ProviderState[provider]; if (location.length === 0) { location = this.props.Platform === 'win32' ? !providerState.MountLocation || providerState.MountLocation.trim().length === 0 ? driveLetters[0] : providerState.MountLocation : providerState.MountLocation; } if (location !== providerState.MountLocation) { this.handleMountLocationChanged(provider, location); } if ( !this.props.AutoMountProcessed[provider] && this.props.ProviderState[provider].AutoMount && !mounted && location.length > 0 ) { this.handleMountUnMount( provider, this.props.RemoteMounts.includes(provider), this.props.S3Mounts.includes(provider), true, location ); } }; render() { let retryDisplay; if (this.state.DisplayRetry) { const retryList = []; let retryCount = 0; Object.keys(this.state.RetryItems).forEach((provider) => { if (this.state.RetryItems[provider].RetryMessage) { retryList.push(

{this.state.RetryItems[provider].RetryMessage}

); } retryList.push( ); if (++retryCount < Object.keys(this.state.RetryItems).length) { retryList.push(
); } }); retryDisplay = (

Mount Failed

{retryList}
); } const footerItems = []; if (this.props.remoteSupported || this.props.s3Supported) { footerItems.push( ); } else { footerItems.push(
); } const mountItems = []; const addMountItem = (provider, remote, s3) => { if (mountItems.length > 0) { mountItems.push(
); } mountItems.push( this.handleMountLocationChanged(provider, e.target.value)} clicked={this.handleMountUnMount} key={'it_' + mountItems.length} provider={provider} remote={remote} s3={s3} /> ); }; this.getProviderList(true).forEach((provider) => addMountItem(provider)); if (this.props.remoteSupported) { this.props.RemoteMounts.forEach((provider) => addMountItem(provider, true)); } if (this.props.s3Supported) { this.props.S3Mounts.forEach((provider) => addMountItem(provider, false, true)); } return (
{retryDisplay}
{mountItems}
{footerItems}
); } } const mapStateToProps = (state) => { return { AutoMountProcessed: state.mounts.AutoMountProcessed, InstalledVersion: state.relver.InstalledVersion, MountState: state.mounts.MountState, MountsBusy: state.mounts.MountsBusy, Platform: state.common.Platform, ProviderState: state.mounts.ProviderState, RemoteMounts: state.mounts.RemoteMounts, S3Mounts: state.mounts.S3Mounts, }; }; const mapDispatchToProps = (dispatch) => { return { notifyError: (msg, critical, callback) => dispatch(notifyError(msg, critical, callback)), resetMountsState: () => dispatch(resetMountsState()), setAllowMount: (provider, allow) => dispatch(setAllowMount(provider, allow)), setAutoMountProcessed: (provider, processed) => dispatch(setAutoMountProcessed(provider, processed)), setMounted: (provider, mounted) => dispatch(setMounted(provider, mounted)), setMountsBusy: (busy) => dispatch(setBusy(busy)), setMountState: (provider, state) => dispatch(setMountState(provider, state)), setProviderState: (provider, state) => dispatch(setProviderState(provider, state)), }; }; export default connect(mapStateToProps, mapDispatchToProps)(MountItems);