import React from 'react'; import AddRemoteMount from '../AddRemoteMount/AddRemoteMount'; import Box from '../../components/UI/Box/Box'; import Button from '../../components/UI/Button/Button'; import {connect} from 'react-redux'; import './MountItems.css'; import Modal from '../../components/UI/Modal/Modal'; import MountItem from '../../components/MountItem/MountItem'; import IPCContainer from '../IPCContainer/IPCContainer'; import { resetMountsState, setAllowMount, setAutoMountProcessed, setBusy, setMounted, setMountState, setProviderState } from '../../redux/actions/mount_actions'; import {notifyError} from '../../redux/actions/error_actions'; const Constants = require('../../constants'); class MountItems extends IPCContainer { retryIntervals = {}; state = { DisplayRetry: false, RetryItems: {}, }; 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_Mounts_Reply, this.onDetectMountsReply); this.setRequestHandler(Constants.IPC_Mount_Drive_Reply, this.onMountDriveReply); this.setRequestHandler(Constants.IPC_Unmount_Drive_Reply, this.onUnmountDriveReply); this.props.resetMountsState(); this.detectMounts(); } componentWillUnmount() { for (const provider in this.state.RetryItems) { if (this.state.RetryItems.hasOwnProperty(provider)) { this.cancelRetryMount(provider); } } this.props.resetMountsState(); super.componentWillUnmount(); }; detectMounts = ()=> { if (!this.state.DisplayRetry) { this.props.setMountsBusy(true); this.sendRequest(Constants.IPC_Detect_Mounts, { RemoteMounts: this.props.RemoteMounts, Version: this.props.InstalledVersion, }); } }; displayRetryMount = (provider, remote, 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(() => { let retryItems = { ...this.state.RetryItems, }; const retrySeconds = retryItems[provider].RetrySeconds - 1; if (retrySeconds === 0) { this.cancelRetryMount(provider, () => { this.handleMountUnMount(provider, remote,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, value) => { const location = (this.props.Platform === 'win32') ? this.props.MountState[provider].DriveLetters[value] : value; const state = { ...this.props.ProviderState[provider], MountLocation: location, }; this.props.setProviderState(provider, state); }; handleMountUnMount = (provider, remote, 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 ? {Valid: true, Success: true} : this.sendSyncRequest(Constants.IPC_Check_Daemon_Version, { Provider: provider, Remote: remote, Version: this.props.InstalledVersion }).data; 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])) { this.displayRetryMount(provider, remote, location, 'Failed to connect to ' + provider + ' daemon'); } else if ((result.Code === new Uint32Array([-3])[0]) || (result.Code === new Uint8Array([-3])[0])) { this.displayRetryMount(provider, remote, location, 'Incompatible ' + provider + ' daemon. Please upgrade ' + provider + '.'); } else { this.displayRetryMount(provider, remote, location, '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 { this.displayRetryMount(provider, remote, location, 'Version check failed: ' + result.Error); } } } if (allowAction) { this.props.setMountsBusy(true); this.props.setAllowMount(provider, false); if (mount) { this.sendRequest(Constants.IPC_Mount_Drive, { Location: location, NoConsoleSupported: this.props.noConsoleSupported, Provider: provider, Remote: remote, Version: this.props.InstalledVersion, }); } else { this.sendRequest(Constants.IPC_Unmount_Drive, { Location: location, Provider: provider, Remote: remote, Version: this.props.InstalledVersion, }); } } } }; getProviderList = () => { return [ ...Constants.PROVIDER_LIST, ...this.props.RemoteMounts, ]; }; onDetectMountsReply = (event, arg) => { if (!this.state.DisplayRetry && arg.data.Success) { let mountsBusy = false; let mountStates = {}; for (const provider of this.getProviderList()) { const mountState = { AllowMount: true, DriveLetters: (arg.data.DriveLetters[provider]), Mounted: (arg.data.Locations[provider].length > 0), }; this.props.setMountState(provider, mountState); mountsBusy = mountsBusy || mountState.Mounted; mountStates[provider] = mountState; } this.props.setMountsBusy(mountsBusy); const updateMountLocation = (data, provider) => { const providerState = this.props.ProviderState[provider]; let location = data.Locations[provider]; if (location.length === 0) { location = (this.props.Platform === 'win32') ? providerState.MountLocation || data.DriveLetters[provider][0] : providerState.MountLocation; } if (location !== providerState.MountLocation) { const value = (this.props.Platform === 'win32') ? data.DriveLetters[provider].indexOf(location) : location; this.handleMountLocationChanged(provider, value); } if (!this.props.AutoMountProcessed && this.props.ProviderState[provider].AutoMount && !mountStates[provider].Mounted && (location.length > 0)) { this.handleMountUnMount(provider, this.props.RemoteMounts.includes(provider),true, location); } }; for (const provider of this.getProviderList()) { updateMountLocation(arg.data, provider); } this.props.setAutoMountProcessed(true); } else { this.props.notifyError(arg.data.Error); } }; onMountDriveReply = (event, arg) => { this.props.setMounted(arg.data.Provider, arg.data.Success); this.detectMounts(); }; onUnmountDriveReply = (event, 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.detectMounts(); } }; render() { let retryDisplay; if (this.state.DisplayRetry) { let retryList = []; let retryCount = 0; for (const provider in this.state.RetryItems) { if (this.state.RetryItems.hasOwnProperty(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}
) } let footerItems = []; if (this.props.remoteSupported) { footerItems.push(); } else { footerItems.push(
); } let items = []; for (const provider of Constants.PROVIDER_LIST) { items.push(( this.handleMountLocationChanged(provider, e.target.value)} clicked={this.handleMountUnMount} key={'it_' + items.length} provider={provider}/> )); items.push(
) } if (this.props.remoteSupported) { for (const provider of this.props.RemoteMounts) { items.push(( this.handleMountLocationChanged(provider, e.target.value)} clicked={this.handleMountUnMount} key={'it_' + items.length} provider={provider} remote/> )); items.push(
) } items.splice(items.length - 1, 1); } else { items.splice(items.length - 1, 1) } return (
{retryDisplay}
{items}
{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, } }; const mapDispatchToProps = dispatch => { return { notifyError: (msg, critical, callback) => dispatch(notifyError(msg, critical, callback)), resetMountsState: () => dispatch(resetMountsState()), setAllowMount: (provider, allow) => dispatch(setAllowMount(provider, allow)), setAutoMountProcessed: processed => dispatch(setAutoMountProcessed(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);