Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: speed limits #2310

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/renderer/controllers/prefs-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,12 @@ module.exports = class PrefsController {
dispatch('stateSaveImmediate')
dispatch('checkDownloadPath')
}

applyDownloadSpeedLimit (speed) {
ipcRenderer.send('wt-set-download-limit', speed)
}

applyUploadSpeedLimit (speed) {
ipcRenderer.send('wt-set-upload-limit', speed)
}
}
4 changes: 4 additions & 0 deletions src/renderer/lib/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ function setupStateSaved () {
autoAddTorrents: false,
torrentsFolderPath: '',
highestPlaybackPriority: true,
downloadSpeedLimitEnabled: false,
uploadSpeedLimitEnabled: false,
downloadSpeedLimit: 1000000,
uploadSpeedLimit: 1000000,
globalTrackers: defaultAnnounceList
},
torrents: config.DEFAULT_TORRENTS.map(createTorrentObject),
Expand Down
22 changes: 22 additions & 0 deletions src/renderer/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ function onState (err, _state) {
// Listen for messages from the main process
setupIpc()

// Apply the user's stored speed limits if they exist.
applySpeedLimits()

// Drag and drop files/text to start torrenting or seeding
dragDrop('body', {
onDrop: onOpen,
Expand Down Expand Up @@ -321,6 +324,10 @@ const dispatchHandlers = {
startFolderWatcher: () => controllers.folderWatcher().start(),
stopFolderWatcher: () => controllers.folderWatcher().stop(),

// Speed limits for transfers (in bytes per second)
updateDownloadSpeedLimit: (speed) => controllers.prefs().applyDownloadSpeedLimit(speed),
updateUploadSpeedLimit: (speed) => controllers.prefs().applyUploadSpeedLimit(speed),

// Update (check for new versions on Linux, where there's no auto updater)
updateAvailable: (version) => controllers.update().updateAvailable(version),
skipVersion: (version) => controllers.update().skipVersion(version),
Expand Down Expand Up @@ -398,6 +405,21 @@ function setupIpc () {
State.on('stateSaved', () => ipcRenderer.send('stateSaved'))
}

// Checks user config for speed limits and applies them to webtorrent.
function applySpeedLimits () {
// Check if the user has set an upload speed limit in the prefstore
if (state.saved.prefs.uploadSpeedLimitEnabled) {
// Apply the saved speed limit
controllers.prefs().applyUploadSpeedLimit(state.saved.prefs.uploadSpeedLimit)
}

// Check if the user has set an upload speed limit in the prefstore
if (state.saved.prefs.downloadSpeedLimitEnabled) {
// Apply the saved speed limit
controllers.prefs().applyDownloadSpeedLimit(state.saved.prefs.downloadSpeedLimit)
}
}

// Quits any modal popovers and returns to the torrent list screen
function backToList () {
// Exit any modals and screens with a back button
Expand Down
136 changes: 136 additions & 0 deletions src/renderer/pages/preferences-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,20 @@ class PreferencesPage extends React.Component {

const globalTrackers = this.props.state.getGlobalTrackers().join('\n')

// Upload Speed limits
this.handleUploadSpeedLimitToggle =
this.handleUploadSpeedLimitToggle.bind(this)

this.handleUploadSpeedLimitChange =
this.handleUploadSpeedLimitChange.bind(this)

// Download Speed limits
this.handleDownloadSpeedLimitToggle =
this.handleDownloadSpeedLimitToggle.bind(this)

this.handleDownloadSpeedLimitChange =
this.handleDownloadSpeedLimitChange.bind(this)

this.state = {
globalTrackers
}
Expand Down Expand Up @@ -272,6 +286,125 @@ class PreferencesPage extends React.Component {
dispatch('updateGlobalTrackers', announceList)
}

speedLimits () {
const DLspeedLimitInKBPS = this.props.state.saved.prefs.downloadSpeedLimit / 1000
const ULspeedLimitInKBPS = this.props.state.saved.prefs.uploadSpeedLimit / 1000

// Align the text fields
const textareaStyle = {
margin: 0
// marginTop: -40
}
const textFieldStyle = {
width: '25%',
marginTop: -12
}
const unitLabelStyle = {
marginTop: -0.01,
padding: 0.1,
marginLeft: 4
}

// webtorrent limits are in bytes, but our UI is in Kilobytes.
// So we do conversions in this file.
return (
<Preference>
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start' }}>
<div style={{ display: 'inline-flex', alignItems: 'flex-start' }}>
<Checkbox
className='control'
checked={this.props.state.saved.prefs.downloadSpeedLimitEnabled}
label='Limit Download:'
onCheck={this.handleDownloadSpeedLimitToggle}
/>
<TextField
className='control'
style={textFieldStyle}
textareaStyle={textareaStyle}
rows={1}
rowsMax={1}
type='number'
value={DLspeedLimitInKBPS}
onChange={this.handleDownloadSpeedLimitChange}
disabled={!this.props.state.saved.prefs.downloadSpeedLimitEnabled}
/>
<p style={unitLabelStyle}>KB/s</p>
</div>
<div style={{ display: 'inline-flex', alignItems: 'flex-start' }}>
<Checkbox
className='control'
checked={this.props.state.saved.prefs.uploadSpeedLimitEnabled}
label='Limit Upload:'
onCheck={this.handleUploadSpeedLimitToggle}
/>
<TextField
className='control'
style={textFieldStyle}
textareaStyle={textareaStyle}
rows={1}
rowsMax={1}
type='number'
value={ULspeedLimitInKBPS}
onChange={this.handleUploadSpeedLimitChange}
disabled={!this.props.state.saved.prefs.uploadSpeedLimitEnabled}
/>
<p style={unitLabelStyle}>KB/s</p>
</div>
</div>
</Preference>
)
}

// Download Speed Limit functions
handleDownloadSpeedLimitToggle (e, isChecked) {
// Store whether or not the limit is enabled
dispatch('updatePreferences', 'downloadSpeedLimitEnabled', isChecked)

// Adjust speedlimit in webtorrent (-1 means disabled)
dispatch('updateDownloadSpeedLimit', isChecked ? this.props.state.saved.prefs.downloadSpeedLimit : -1)
}

// Upload Speed Limit functions
handleUploadSpeedLimitToggle (e, isChecked) {
// Store whether or not the limit is enabled
dispatch('updatePreferences', 'uploadSpeedLimitEnabled', isChecked)

// Adjust speedlimit in webtorrent (-1 means disabled)
dispatch('updateUploadSpeedLimit', isChecked ? this.props.state.saved.prefs.uploadSpeedLimit : -1)
}

// This converts from KB to bytes and updates prefs and webtorrent.
handleDownloadSpeedLimitChange (e, speedLimitInKBPS) {
// First check if the number is too large. Over 1TBPS is too large.
if (speedLimitInKBPS > 1000000000) {
speedLimitInKBPS = 1000000000
}

const speedLimitInBPS = speedLimitInKBPS * 1000

// Store the new rate in the persistent prefstore
dispatch('updatePreferences', 'downloadSpeedLimit', speedLimitInBPS)

// Dispatch to call IPC
dispatch('updateDownloadSpeedLimit', speedLimitInBPS)
}

// This converts from KB to bytes and updates prefs and webtorrent.
handleUploadSpeedLimitChange (e, speedLimitInKBPS) {
// First check if the number is too large. Over 1TBPS is too large.
if (speedLimitInKBPS > 1000000000) {
speedLimitInKBPS = 1000000000
}

const speedLimitInBPS = speedLimitInKBPS * 1000

// Store the new rate in the persistent prefstore
dispatch('updatePreferences', 'uploadSpeedLimit', speedLimitInBPS)

// Dispatch to call IPC
dispatch('updateUploadSpeedLimit', speedLimitInBPS)
}

render () {
const style = {
color: colors.grey400,
Expand All @@ -290,6 +423,9 @@ class PreferencesPage extends React.Component {
{this.externalPlayerPathSelector()}
{this.highestPlaybackPriorityCheckbox()}
</PreferencesSection>
<PreferencesSection title='Speed Limits'>
{this.speedLimits()}
</PreferencesSection>
<PreferencesSection title='Default torrent app'>
{this.setDefaultAppButton()}
</PreferencesSection>
Expand Down
18 changes: 18 additions & 0 deletions src/renderer/webtorrent.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ function init () {
stopServer())
ipcRenderer.on('wt-select-files', (e, infoHash, selections) =>
selectFiles(infoHash, selections))
ipcRenderer.on('wt-set-download-limit', (e, speed) =>
setDownloadSpeedLimit(speed))
ipcRenderer.on('wt-set-upload-limit', (e, speed) =>
setUploadSpeedLimit(speed))

ipcRenderer.send('ipcReadyWebTorrent')

Expand Down Expand Up @@ -407,6 +411,20 @@ function selectFiles (torrentOrInfoHash, selections) {
})
}

function setDownloadSpeedLimit (speed) {
// var nodeConsole = require('console');
// var myConsole = new nodeConsole.Console(process.stdout, process.stderr);
// myConsole.log('Setting download speed limit (bytes/second): ' + speed);
client.throttleDownload(speed)
}

function setUploadSpeedLimit (speed) {
// var nodeConsole = require('console');
// var myConsole = new nodeConsole.Console(process.stdout, process.stderr);
// myConsole.log('Setting upload speed limit (bytes/second): ' + speed);
client.throttleUpload(speed)
}

// Gets a WebTorrent handle by torrentKey
// Throws an Error if we're not currently torrenting anything w/ that key
function getTorrent (torrentKey) {
Expand Down
13 changes: 13 additions & 0 deletions static/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -983,3 +983,16 @@ video::-webkit-media-text-track-container {
.control * {
cursor: default !important;
}

/*Remove spinner arrows from speed limits*/
/* Chrome, Safari, Edge, Opera */
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}

/* Firefox */
input[type=number] {
-moz-appearance: textfield;
}