multiparty-meeting/app/lib/components/FileSharing/FileEntry.jsx

196 lines
4.0 KiB
JavaScript

import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import magnet from 'magnet-uri';
import WebTorrent from 'webtorrent';
import * as requestActions from '../../redux/requestActions';
import { saveAs } from 'file-saver/FileSaver';
import { client } from './index';
const DEFAULT_PICTURE = 'resources/images/avatar-empty.jpeg';
class FileEntry extends Component
{
state = {
active : false,
numPeers : 0,
progress : 0,
files : null
};
saveFile = (file) =>
{
file.getBlob((err, blob) =>
{
if (err)
{
return this.props.notify({
text : 'An error occurred while saving a file'
});
}
saveAs(blob, file.name);
});
};
handleTorrent = (torrent) =>
{
// Torrent already done, this can happen if the
// same file was sent multiple times.
if (torrent.progress === 1)
{
this.setState({
files : torrent.files,
numPeers : torrent.numPeers,
progress : 1,
active : false,
timeout : false
});
return;
}
const onProgress = () =>
{
this.setState({
numPeers : torrent.numPeers,
progress : torrent.progress
});
};
onProgress();
setInterval(onProgress, 500);
torrent.on('done', () =>
{
onProgress();
clearInterval(onProgress);
this.setState({
files : torrent.files,
active : false
});
});
};
handleDownload = () =>
{
this.setState({
active : true
});
const magnetURI = this.props.data.file.magnet;
const existingTorrent = client.get(magnetURI);
if (existingTorrent)
{
// Never add duplicate torrents, use the existing one instead.
return this.handleTorrent(existingTorrent);
}
client.add(magnetURI, this.handleTorrent);
setTimeout(() =>
{
if (this.state.active && this.state.numPeers === 0)
{
this.setState({
timeout : true
});
}
}, 10 * 1000);
}
render()
{
return (
<div className='file-entry'>
<img className='file-avatar' src={this.props.data.picture || DEFAULT_PICTURE} />
<div className='file-content'>
{this.props.data.me ? (
<p>You shared a file.</p>
) : (
<p>{this.props.data.name} shared a file.</p>
)}
{!this.state.active && !this.state.files && (
<div className='file-info'>
{WebTorrent.WEBRTC_SUPPORT ? (
<span className='button' onClick={this.handleDownload}>
<img src='resources/images/download-icon.svg' />
</span>
) : (
<p>
Your browser does not support downloading files using WebTorrent.
</p>
)}
<p>{magnet.decode(this.props.data.file.magnet).dn}</p>
</div>
)}
{this.state.active && this.state.numPeers === 0 && (
<Fragment>
<p>
Locating peers
</p>
{this.state.timeout && (
<p>
If this process takes a long time, there might not be anyone seeding
this torrent. Try asking someone to reupload the file that you want.
</p>
)}
</Fragment>
)}
{this.state.active && this.state.numPeers > 0 && (
<progress value={this.state.progress} />
)}
{this.state.files && (
<Fragment>
<p>Torrent finished downloading.</p>
{this.state.files.map((file, i) => (
<div className='file-info' key={i}>
<span className='button' onClick={() => this.saveFile(file)}>
<img src='resources/images/save-icon.svg' />
</span>
<p>{file.name}</p>
</div>
))}
</Fragment>
)}
</div>
</div>
);
}
}
export const FileEntryProps = {
data : PropTypes.shape({
name : PropTypes.string.isRequired,
picture : PropTypes.string,
file : PropTypes.shape({
magnet : PropTypes.string.isRequired
}).isRequired,
me : PropTypes.bool
}).isRequired,
notify : PropTypes.func.isRequired
};
FileEntry.propTypes = FileEntryProps;
const mapDispatchToProps = {
notify : requestActions.notify
};
export default connect(
undefined,
mapDispatchToProps
)(FileEntry);