mirror of
https://github.com/zoriya/flood.git
synced 2025-12-23 07:35:27 +00:00
Introduce client settings
This commit is contained in:
@@ -30,6 +30,11 @@ $checkbox--border--hover: $checkbox--border;
|
|||||||
|
|
||||||
$modal--body--foreground: desaturate(lighten($foreground, 20%), 10%);
|
$modal--body--foreground: desaturate(lighten($foreground, 20%), 10%);
|
||||||
|
|
||||||
|
$form--section--heading--margin: $spacing-unit * 2/5;
|
||||||
|
$form--section--margin: $spacing-unit;
|
||||||
|
$form--row--margin: $spacing-unit * 3/5;
|
||||||
|
$form--column--padding: $spacing-unit * 2/5;
|
||||||
|
|
||||||
.textbox,
|
.textbox,
|
||||||
.button,
|
.button,
|
||||||
.checkbox {
|
.checkbox {
|
||||||
@@ -191,17 +196,36 @@ $modal--body--foreground: desaturate(lighten($foreground, 20%), 10%);
|
|||||||
|
|
||||||
.form {
|
.form {
|
||||||
|
|
||||||
|
&__section {
|
||||||
|
|
||||||
|
&__heading {
|
||||||
|
margin-bottom: $form--section--heading--margin;
|
||||||
|
|
||||||
|
& + .form__section__sub-heading {
|
||||||
|
margin-bottom: $form--section--heading--margin;
|
||||||
|
margin-top: $form--section--heading--margin * -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& + .form__section {
|
||||||
|
margin-top: $form--section--margin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&__row {
|
&__row {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
& + .form__row {
|
& + .form__row {
|
||||||
margin-top: $spacing-unit;
|
margin-top: $form--row--margin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__column {
|
&__column {
|
||||||
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding: 0 $spacing-unit * 2/5;
|
flex-direction: column;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding: 0 $form--column--padding;
|
||||||
|
|
||||||
&:first-child {
|
&:first-child {
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
@@ -210,6 +234,38 @@ $modal--body--foreground: desaturate(lighten($foreground, 20%), 10%);
|
|||||||
&:last-child {
|
&:last-child {
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&--auto {
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 1;
|
||||||
|
flex-basis: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--half {
|
||||||
|
max-width: 50%;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
padding-right: $form--column--padding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--small {
|
||||||
|
max-width: 125px;
|
||||||
|
|
||||||
|
// For small columns which are the only column in the row, keep the
|
||||||
|
// column's padding.
|
||||||
|
&:first-child {
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
padding-right: $form--column--padding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--unlabled {
|
||||||
|
justify-content: center;
|
||||||
|
padding-top: $spacing-unit * 3/5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__label {
|
&__label {
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
$modal--background: #12191f;
|
$modal--background: #12191f;
|
||||||
|
|
||||||
$modal--heading--background: #161c24;
|
$modal--heading--background: #161c24;
|
||||||
$modal--heading--foreground: #7d95ab;
|
$modal--heading--foreground: #7d95ab;
|
||||||
$modal--heading--border: #0f151b;
|
$modal--heading--border: #0f151b;
|
||||||
|
|
||||||
|
$modal--sub-heading--foreground: desaturate(darken($modal--heading--foreground, 23%), 2%);
|
||||||
|
|
||||||
$modal--transition--duration: 0.5s;
|
$modal--transition--duration: 0.5s;
|
||||||
$modal--transition--scale: 0.85;
|
$modal--transition--scale: 0.85;
|
||||||
|
|
||||||
@@ -106,15 +109,6 @@ $modal--tabs--in-body--background: #11171d;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__tab {
|
|
||||||
|
|
||||||
&__introduction {
|
|
||||||
color: $modal--heading--foreground;
|
|
||||||
font-size: 0.9em;
|
|
||||||
margin-bottom: $spacing-unit * 3/4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__header {
|
&__header {
|
||||||
background: $modal--heading--background;
|
background: $modal--heading--background;
|
||||||
border-radius: $modal--border-radius $modal--border-radius 0 0;
|
border-radius: $modal--border-radius $modal--border-radius 0 0;
|
||||||
@@ -173,6 +167,7 @@ $modal--tabs--in-body--background: #11171d;
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__footer {
|
&__footer {
|
||||||
|
flex: 0 0 auto;
|
||||||
padding: 0 $modal--padding--horizontal $modal--padding--vertical $modal--padding--horizontal;
|
padding: 0 $modal--padding--horizontal $modal--padding--vertical $modal--padding--horizontal;
|
||||||
|
|
||||||
.modal {
|
.modal {
|
||||||
@@ -283,6 +278,10 @@ $modal--tabs--in-body--background: #11171d;
|
|||||||
|
|
||||||
&__content {
|
&__content {
|
||||||
flex: 1 0 auto;
|
flex: 1 0 auto;
|
||||||
|
|
||||||
|
& + .modal__footer {
|
||||||
|
margin-top: $spacing-unit * 3/5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -372,4 +371,21 @@ $modal--tabs--in-body--background: #11171d;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form {
|
||||||
|
|
||||||
|
&__section {
|
||||||
|
|
||||||
|
&__heading {
|
||||||
|
color: $modal--heading--foreground;
|
||||||
|
font-size: 0.9em;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__sub-heading {
|
||||||
|
color: $modal--sub-heading--foreground;
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -369,7 +369,7 @@ $more-info--border: $textbox-repeater--button--border;
|
|||||||
|
|
||||||
&--eta {
|
&--eta {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 1s, visibility 1s;
|
transition: color 0.25s, opacity 1s, visibility 1s;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
|
|
||||||
.torrent__details--segment {
|
.torrent__details--segment {
|
||||||
|
|||||||
@@ -1,9 +1,49 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
import AppDispatcher from '../dispatcher/AppDispatcher';
|
|
||||||
import ActionTypes from '../constants/ActionTypes';
|
import ActionTypes from '../constants/ActionTypes';
|
||||||
|
import AppDispatcher from '../dispatcher/AppDispatcher';
|
||||||
|
|
||||||
const ClientActions = {
|
const ClientActions = {
|
||||||
|
fetchSettings: (property) => {
|
||||||
|
return axios.get('/client/settings', {params: {property}})
|
||||||
|
.then((json = {}) => {
|
||||||
|
return json.data;
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
AppDispatcher.dispatchServerAction({
|
||||||
|
type: ActionTypes.CLIENT_SETTINGS_FETCH_REQUEST_SUCCESS,
|
||||||
|
data
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
AppDispatcher.dispatchServerAction({
|
||||||
|
type: ActionTypes.CLIENT_SETTINGS_FETCH_REQUEST_ERROR,
|
||||||
|
error
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
saveSettings: (settings, options) => {
|
||||||
|
return axios.patch('/client/settings', settings)
|
||||||
|
.then((json = {}) => {
|
||||||
|
return json.data;
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
AppDispatcher.dispatchServerAction({
|
||||||
|
type: ActionTypes.CLIENT_SETTINGS_SAVE_SUCCESS,
|
||||||
|
data,
|
||||||
|
options
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
AppDispatcher.dispatchServerAction({
|
||||||
|
type: ActionTypes.CLIENT_SETTINGS_SAVE_ERROR,
|
||||||
|
error,
|
||||||
|
options
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
setThrottle: (direction, throttle) => {
|
setThrottle: (direction, throttle) => {
|
||||||
return axios.put('/client/settings/speed-limits', {
|
return axios.put('/client/settings/speed-limits', {
|
||||||
direction,
|
direction,
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ const SettingsActions = {
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.trace(error);
|
|
||||||
AppDispatcher.dispatchServerAction({
|
AppDispatcher.dispatchServerAction({
|
||||||
type: ActionTypes.SETTINGS_FETCH_REQUEST_ERROR,
|
type: ActionTypes.SETTINGS_FETCH_REQUEST_ERROR,
|
||||||
error
|
error
|
||||||
@@ -37,7 +36,6 @@ const SettingsActions = {
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.trace(error);
|
|
||||||
AppDispatcher.dispatchServerAction({
|
AppDispatcher.dispatchServerAction({
|
||||||
type: ActionTypes.SETTINGS_SAVE_REQUEST_ERROR,
|
type: ActionTypes.SETTINGS_SAVE_REQUEST_ERROR,
|
||||||
error
|
error
|
||||||
|
|||||||
@@ -93,7 +93,6 @@ const TorrentActions = {
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.trace(error);
|
|
||||||
AppDispatcher.dispatchServerAction({
|
AppDispatcher.dispatchServerAction({
|
||||||
type: ActionTypes.CLIENT_FETCH_TORRENTS_ERROR,
|
type: ActionTypes.CLIENT_FETCH_TORRENTS_ERROR,
|
||||||
data: {
|
data: {
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ import TorrentListView from './components/panels/TorrentListView';
|
|||||||
|
|
||||||
class FloodApp extends React.Component {
|
class FloodApp extends React.Component {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
SettingsStore.fetchSettings();
|
SettingsStore.fetchClientSettings();
|
||||||
|
SettingsStore.fetchFloodSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ export default class AddTorrentsActions extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
let startTorrentsOnLoad = SettingsStore.getSettings('startTorrentsOnLoad');
|
let startTorrentsOnLoad = SettingsStore.getFloodSettings(
|
||||||
|
'startTorrentsOnLoad');
|
||||||
if (startTorrentsOnLoad !== true) {
|
if (startTorrentsOnLoad !== true) {
|
||||||
this.setState({startTorrentsOnLoad: false});
|
this.setState({startTorrentsOnLoad: false});
|
||||||
}
|
}
|
||||||
@@ -65,7 +66,7 @@ export default class AddTorrentsActions extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleStartTorrentsToggle(value) {
|
handleStartTorrentsToggle(value) {
|
||||||
SettingsStore.saveSettings({id: 'startTorrentsOnLoad', data: value});
|
SettingsStore.saveFloodSettings({id: 'startTorrentsOnLoad', data: value});
|
||||||
if (!!this.props.onStartTorrentsToggle) {
|
if (!!this.props.onStartTorrentsToggle) {
|
||||||
this.props.onStartTorrentsToggle(value);
|
this.props.onStartTorrentsToggle(value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ export default class AddTorrentsDestination extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
let destination = SettingsStore.getSettings('torrentDestination') || '';
|
let destination = SettingsStore.getFloodSettings('torrentDestination')
|
||||||
|
|| '';
|
||||||
if (this.props.suggested) {
|
if (this.props.suggested) {
|
||||||
destination = this.props.suggested;
|
destination = this.props.suggested;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
import BandwidthTab from '../settings/BandwidthTab';
|
||||||
|
import ConnectivityTab from '../settings/ConnectivityTab';
|
||||||
import EventTypes from '../../constants/EventTypes';
|
import EventTypes from '../../constants/EventTypes';
|
||||||
import LoadingIndicatorDots from '../icons/LoadingIndicatorDots';
|
import LoadingIndicatorDots from '../icons/LoadingIndicatorDots';
|
||||||
import Modal from './Modal';
|
import Modal from './Modal';
|
||||||
import SettingsStore from '../../stores/SettingsStore';
|
import SettingsStore from '../../stores/SettingsStore';
|
||||||
import SpeedLimitTab from '../settings/SpeedLimitTab';
|
import StorageTab from '../settings/StorageTab';
|
||||||
|
|
||||||
const METHODS_TO_BIND = [
|
const METHODS_TO_BIND = [
|
||||||
'handleSaveSettingsClick',
|
'handleSaveSettingsClick',
|
||||||
'handleSaveSettingsError',
|
'handleSaveSettingsError',
|
||||||
'handleSettingsChange',
|
'handleClientSettingsChange',
|
||||||
|
'handleFloodSettingsChange',
|
||||||
'handleSettingsStoreChange'
|
'handleSettingsStoreChange'
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -20,7 +23,10 @@ export default class SettingsModal extends React.Component {
|
|||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
isSavingSettings: false,
|
isSavingSettings: false,
|
||||||
settings: SettingsStore.getSettings()
|
changedClientSettings: {},
|
||||||
|
changedFloodSettings: {},
|
||||||
|
clientSettings: SettingsStore.getClientSettings(),
|
||||||
|
floodSettings: SettingsStore.getFloodSettings()
|
||||||
};
|
};
|
||||||
|
|
||||||
METHODS_TO_BIND.forEach((method) => {
|
METHODS_TO_BIND.forEach((method) => {
|
||||||
@@ -33,12 +39,14 @@ export default class SettingsModal extends React.Component {
|
|||||||
this.handleSettingsStoreChange);
|
this.handleSettingsStoreChange);
|
||||||
SettingsStore.listen(EventTypes.SETTINGS_SAVE_REQUEST_ERROR,
|
SettingsStore.listen(EventTypes.SETTINGS_SAVE_REQUEST_ERROR,
|
||||||
this.handleSaveSettingsError);
|
this.handleSaveSettingsError);
|
||||||
SettingsStore.fetchSettings('speedLimits');
|
SettingsStore.fetchFloodSettings('speedLimits');
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
SettingsStore.unlisten(EventTypes.SETTINGS_CHANGE,
|
SettingsStore.unlisten(EventTypes.SETTINGS_CHANGE,
|
||||||
this.handleSettingsStoreChange);
|
this.handleSettingsStoreChange);
|
||||||
|
SettingsStore.unlisten(EventTypes.SETTINGS_SAVE_REQUEST_ERROR,
|
||||||
|
this.handleSaveSettingsError);
|
||||||
}
|
}
|
||||||
|
|
||||||
getActions() {
|
getActions() {
|
||||||
@@ -75,14 +83,22 @@ export default class SettingsModal extends React.Component {
|
|||||||
handleSaveSettingsClick() {
|
handleSaveSettingsClick() {
|
||||||
this.setState({isSavingSettings: true});
|
this.setState({isSavingSettings: true});
|
||||||
|
|
||||||
let settingsToSave = Object.keys(this.state.settings).map((settingsKey) => {
|
let floodSettings = Object.keys(this.state.changedFloodSettings).map((settingsKey) => {
|
||||||
return {
|
return {
|
||||||
id: settingsKey,
|
id: settingsKey,
|
||||||
data: this.state.settings[settingsKey]
|
data: this.state.changedFloodSettings[settingsKey]
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
SettingsStore.saveSettings(settingsToSave, {dismissModal: true, notify: true});
|
let clientSettings = Object.keys(this.state.changedClientSettings).map((settingsKey) => {
|
||||||
|
return {
|
||||||
|
id: settingsKey,
|
||||||
|
data: this.state.changedClientSettings[settingsKey]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
SettingsStore.saveFloodSettings(floodSettings, {dismissModal: true, notify: true});
|
||||||
|
SettingsStore.saveClientSettings(clientSettings, {dismissModal: true, notify: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSaveSettingsError() {
|
handleSaveSettingsError() {
|
||||||
@@ -95,13 +111,23 @@ export default class SettingsModal extends React.Component {
|
|||||||
|
|
||||||
handleSettingsStoreChange() {
|
handleSettingsStoreChange() {
|
||||||
this.setState({
|
this.setState({
|
||||||
settings: SettingsStore.getSettings()
|
clientSettings: SettingsStore.getClientSettings(),
|
||||||
|
floodSettings: SettingsStore.getFloodSettings()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSettingsChange(changedSettings) {
|
handleFloodSettingsChange(changedSettings) {
|
||||||
let settings = this.mergeObjects(this.state.settings, changedSettings);
|
let floodSettings = this.mergeObjects(this.state.floodSettings, changedSettings);
|
||||||
this.setState({settings});
|
let changedFloodSettings = this.mergeObjects(this.state.changedFloodSettings, changedSettings);
|
||||||
|
|
||||||
|
this.setState({floodSettings, changedFloodSettings});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClientSettingsChange(changedSettings) {
|
||||||
|
let clientSettings = this.mergeObjects(this.state.clientSettings, changedSettings);
|
||||||
|
let changedClientSettings = this.mergeObjects(this.state.changedClientSettings, changedSettings);
|
||||||
|
|
||||||
|
this.setState({clientSettings, changedClientSettings});
|
||||||
}
|
}
|
||||||
|
|
||||||
mergeObjects(objA, objB) {
|
mergeObjects(objA, objB) {
|
||||||
@@ -123,13 +149,30 @@ export default class SettingsModal extends React.Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
let tabs = {
|
let tabs = {
|
||||||
'speed-limit': {
|
bandwidth: {
|
||||||
content: SpeedLimitTab,
|
content: BandwidthTab,
|
||||||
props: {
|
props: {
|
||||||
onSettingsChange: this.handleSettingsChange,
|
onClientSettingsChange: this.handleClientSettingsChange,
|
||||||
settings: this.state.settings
|
onSettingsChange: this.handleFloodSettingsChange,
|
||||||
|
settings: this.mergeObjects(this.state.floodSettings, this.state.clientSettings)
|
||||||
},
|
},
|
||||||
label: 'Speed Limits'
|
label: 'Bandwidth'
|
||||||
|
},
|
||||||
|
connectivity: {
|
||||||
|
content: ConnectivityTab,
|
||||||
|
props: {
|
||||||
|
onClientSettingsChange: this.handleClientSettingsChange,
|
||||||
|
settings: this.state.clientSettings
|
||||||
|
},
|
||||||
|
label: 'Connectivity'
|
||||||
|
},
|
||||||
|
storage: {
|
||||||
|
content: StorageTab,
|
||||||
|
props: {
|
||||||
|
onClientSettingsChange: this.handleClientSettingsChange,
|
||||||
|
settings: this.state.clientSettings
|
||||||
|
},
|
||||||
|
label: 'Storage'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
195
client/source/scripts/components/settings/BandwidthTab.js
Normal file
195
client/source/scripts/components/settings/BandwidthTab.js
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import SettingsTab from './SettingsTab';
|
||||||
|
|
||||||
|
const METHODS_TO_BIND = ['handleDownloadTextChange', 'handleUploadTextChange'];
|
||||||
|
|
||||||
|
export default class BandwidthTab extends SettingsTab {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
downloadValue: null,
|
||||||
|
uploadValue: null
|
||||||
|
};
|
||||||
|
|
||||||
|
METHODS_TO_BIND.forEach((method) => {
|
||||||
|
this[method] = this[method].bind(this);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
arrayToString(array) {
|
||||||
|
return array.join(', ');
|
||||||
|
}
|
||||||
|
|
||||||
|
getTextboxValue(input = []) {
|
||||||
|
if (Array.isArray(input)) {
|
||||||
|
return this.arrayToString(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleDownloadTextChange(event) {
|
||||||
|
this.setState({
|
||||||
|
downloadValue: event.target.value
|
||||||
|
});
|
||||||
|
|
||||||
|
this.props.onSettingsChange({
|
||||||
|
speedLimits: {
|
||||||
|
download: this.processSpeedsForSave(event.target.value),
|
||||||
|
upload: this.processSpeedsForSave(this.getUploadValue())
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleUploadTextChange(event) {
|
||||||
|
this.setState({
|
||||||
|
uploadValue: event.target.value
|
||||||
|
});
|
||||||
|
|
||||||
|
this.props.onSettingsChange({
|
||||||
|
speedLimits: {
|
||||||
|
download: this.processSpeedsForSave(this.getDownloadValue()),
|
||||||
|
upload: this.processSpeedsForSave(event.target.value)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getDownloadValue() {
|
||||||
|
let displayedValue = this.state.downloadValue;
|
||||||
|
|
||||||
|
if (displayedValue == null && this.props.settings.speedLimits != null) {
|
||||||
|
displayedValue = this.processSpeedsForDisplay(this.props.settings.speedLimits.download);
|
||||||
|
}
|
||||||
|
|
||||||
|
return displayedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
getUploadValue() {
|
||||||
|
let displayedValue = this.state.uploadValue;
|
||||||
|
|
||||||
|
if (displayedValue == null && this.props.settings.speedLimits != null) {
|
||||||
|
displayedValue = this.processSpeedsForDisplay(this.props.settings.speedLimits.upload);
|
||||||
|
}
|
||||||
|
|
||||||
|
return displayedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
processSpeedsForDisplay(speeds = []) {
|
||||||
|
if (!speeds || speeds.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.arrayToString(speeds.map((speed) => {
|
||||||
|
return Number(speed) / 1024;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
processSpeedsForSave(speeds = '') {
|
||||||
|
if (speeds === '') {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.stringToArray(speeds).map((speed) => {
|
||||||
|
return Number(speed) * 1024;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
stringToArray(string = '') {
|
||||||
|
return string.replace(/\s/g, '').split(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let downloadValue = this.getDownloadValue() || 0;
|
||||||
|
let uploadValue = this.getUploadValue() || 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="form">
|
||||||
|
<div className="form__section">
|
||||||
|
<p className="form__section__heading">
|
||||||
|
Speed Limit Dropdown Presets
|
||||||
|
</p>
|
||||||
|
<p className="form__section__sub-heading">
|
||||||
|
Enter a comma-separated list of speeds in kB. 0 represents unlimited.
|
||||||
|
</p>
|
||||||
|
<div className="form__row">
|
||||||
|
<div className="form__column">
|
||||||
|
<label className="form__label">
|
||||||
|
Download Presets
|
||||||
|
</label>
|
||||||
|
<input className="textbox" type="text"
|
||||||
|
onChange={this.handleDownloadTextChange}
|
||||||
|
value={downloadValue} />
|
||||||
|
</div>
|
||||||
|
<div className="form__column">
|
||||||
|
<label className="form__label">
|
||||||
|
Upload Presets
|
||||||
|
</label>
|
||||||
|
<input className="textbox" type="text"
|
||||||
|
onChange={this.handleUploadTextChange}
|
||||||
|
value={uploadValue} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="form__section">
|
||||||
|
<div className="form__section__heading">
|
||||||
|
Slot Availability
|
||||||
|
</div>
|
||||||
|
<div className="form__row">
|
||||||
|
<div className="form__column">
|
||||||
|
<label className="form__label">
|
||||||
|
Upload Slots Per Torrent
|
||||||
|
</label>
|
||||||
|
<input className="textbox" type="text"
|
||||||
|
onChange={this.handleClientSettingFieldChange.bind(this, 'throttleMaxUploads')}
|
||||||
|
value={this.getFieldValue('throttleMaxUploads')} />
|
||||||
|
</div>
|
||||||
|
<div className="form__column">
|
||||||
|
<label className="form__label">
|
||||||
|
Upload Slots Divider
|
||||||
|
</label>
|
||||||
|
<input className="textbox" type="text"
|
||||||
|
onChange={this.handleClientSettingFieldChange.bind(this, 'throttleMaxUploadsDiv')}
|
||||||
|
value={this.getFieldValue('throttleMaxUploadsDiv')} />
|
||||||
|
</div>
|
||||||
|
<div className="form__column">
|
||||||
|
<label className="form__label">
|
||||||
|
Upload Slots Global
|
||||||
|
</label>
|
||||||
|
<input className="textbox" type="text"
|
||||||
|
onChange={this.handleClientSettingFieldChange.bind(this, 'throttleMaxUploadsGlobal')}
|
||||||
|
value={this.getFieldValue('throttleMaxUploadsGlobal')} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="form__row">
|
||||||
|
<div className="form__column">
|
||||||
|
<label className="form__label">
|
||||||
|
Download Slots Per Torrent
|
||||||
|
</label>
|
||||||
|
<input className="textbox" type="text"
|
||||||
|
onChange={this.handleClientSettingFieldChange.bind(this, 'throttleMaxDownloads')}
|
||||||
|
value={this.getFieldValue('throttleMaxDownloads')} />
|
||||||
|
</div>
|
||||||
|
<div className="form__column">
|
||||||
|
<label className="form__label">
|
||||||
|
Download Slots Divider
|
||||||
|
</label>
|
||||||
|
<input className="textbox" type="text"
|
||||||
|
onChange={this.handleClientSettingFieldChange.bind(this, 'throttleMaxDownloadsDiv')}
|
||||||
|
value={this.getFieldValue('throttleMaxDownloadsDiv')} />
|
||||||
|
</div>
|
||||||
|
<div className="form__column">
|
||||||
|
<label className="form__label">
|
||||||
|
Download Slots Global
|
||||||
|
</label>
|
||||||
|
<input className="textbox" type="text"
|
||||||
|
onChange={this.handleClientSettingFieldChange.bind(this, 'throttleMaxDownloadsGlobal')}
|
||||||
|
value={this.getFieldValue('throttleMaxDownloadsGlobal')} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
115
client/source/scripts/components/settings/ConnectivityTab.js
Normal file
115
client/source/scripts/components/settings/ConnectivityTab.js
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import Checkbox from '../forms/Checkbox';
|
||||||
|
import SettingsTab from './SettingsTab';
|
||||||
|
|
||||||
|
export default class ConnectivityTab extends SettingsTab {
|
||||||
|
constructor() {
|
||||||
|
super(...arguments);
|
||||||
|
|
||||||
|
this.state = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="form">
|
||||||
|
<div className="form__section">
|
||||||
|
<div className="form__section__heading">
|
||||||
|
Listening Port
|
||||||
|
</div>
|
||||||
|
<div className="form__row">
|
||||||
|
<div className="form__column form__column--small">
|
||||||
|
<label className="form__label">
|
||||||
|
Port Range
|
||||||
|
</label>
|
||||||
|
<input className="textbox" type="text"
|
||||||
|
onChange={this.handleClientSettingFieldChange.bind(this, 'networkPortRange')}
|
||||||
|
value={this.getFieldValue('networkPortRange')} />
|
||||||
|
</div>
|
||||||
|
<div className="form__column form__column--auto form__column--unlabled">
|
||||||
|
<Checkbox
|
||||||
|
checked={this.getFieldValue('networkPortRandom') === '1'}
|
||||||
|
onChange={this.handleClientSettingCheckboxChange.bind(this, 'networkPortRandom')}>
|
||||||
|
Randomize Port
|
||||||
|
</Checkbox>
|
||||||
|
</div>
|
||||||
|
<div className="form__column form__column--auto form__column--unlabled">
|
||||||
|
<Checkbox
|
||||||
|
checked={this.getFieldValue('networkPortOpen') === '1'}
|
||||||
|
onChange={this.handleClientSettingCheckboxChange.bind(this, 'networkPortOpen')}>
|
||||||
|
Open Port
|
||||||
|
</Checkbox>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="form__section">
|
||||||
|
<div className="form__section__heading">
|
||||||
|
DHT
|
||||||
|
</div>
|
||||||
|
<div className="form__row">
|
||||||
|
<div className="form__column form__column--small">
|
||||||
|
<label className="form__label">
|
||||||
|
Port
|
||||||
|
</label>
|
||||||
|
<input className="textbox" type="text"
|
||||||
|
onChange={this.handleClientSettingFieldChange.bind(this, 'dhtPort')}
|
||||||
|
value={this.getFieldValue('dhtPort')} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="form__section">
|
||||||
|
<div className="form__section__heading">
|
||||||
|
Peers
|
||||||
|
</div>
|
||||||
|
<div className="form__row">
|
||||||
|
<div className="form__column">
|
||||||
|
<label className="form__label">
|
||||||
|
Minimum Peers
|
||||||
|
</label>
|
||||||
|
<input className="textbox" type="text"
|
||||||
|
onChange={this.handleClientSettingFieldChange.bind(this, 'throttleMinPeersNormal')}
|
||||||
|
value={this.getFieldValue('throttleMinPeersNormal')} />
|
||||||
|
</div>
|
||||||
|
<div className="form__column">
|
||||||
|
<label className="form__label">
|
||||||
|
Maximum Peers
|
||||||
|
</label>
|
||||||
|
<input className="textbox" type="text"
|
||||||
|
onChange={this.handleClientSettingFieldChange.bind(this, 'throttleMaxPeersNormal')}
|
||||||
|
value={this.getFieldValue('throttleMaxPeersNormal')} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="form__row">
|
||||||
|
<div className="form__column">
|
||||||
|
<label className="form__label">
|
||||||
|
Minimum Peers Seeding
|
||||||
|
</label>
|
||||||
|
<input className="textbox" type="text"
|
||||||
|
onChange={this.handleClientSettingFieldChange.bind(this, 'throttleMinPeersSeed')}
|
||||||
|
value={this.getFieldValue('throttleMinPeersSeed')} />
|
||||||
|
</div>
|
||||||
|
<div className="form__column">
|
||||||
|
<label className="form__label">
|
||||||
|
Maximum Peers Seeding
|
||||||
|
</label>
|
||||||
|
<input className="textbox" type="text"
|
||||||
|
onChange={this.handleClientSettingFieldChange.bind(this, 'throttleMaxPeersSeed')}
|
||||||
|
value={this.getFieldValue('throttleMaxPeersSeed')} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="form__row">
|
||||||
|
<div className="form__column form__column--half">
|
||||||
|
<label className="form__label">
|
||||||
|
Amount Desired
|
||||||
|
</label>
|
||||||
|
<input className="textbox" type="text"
|
||||||
|
onChange={this.handleClientSettingFieldChange.bind(this, 'trackersNumWant')}
|
||||||
|
value={this.getFieldValue('trackersNumWant')} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
36
client/source/scripts/components/settings/SettingsTab.js
Normal file
36
client/source/scripts/components/settings/SettingsTab.js
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const METHODS_TO_BIND = ['handleClientSettingFieldChange'];
|
||||||
|
|
||||||
|
export default class SettingsTab extends React.Component {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
METHODS_TO_BIND.forEach((method) => {
|
||||||
|
this[method] = this[method].bind(this);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getFieldValue(fieldName) {
|
||||||
|
if (this.state[fieldName] == null) {
|
||||||
|
return this.props.settings[fieldName] || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.state[fieldName];
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClientSettingFieldChange(fieldName, event) {
|
||||||
|
let newState = {[fieldName]: event.target.value};
|
||||||
|
|
||||||
|
this.setState(newState);
|
||||||
|
this.props.onClientSettingsChange(newState);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClientSettingCheckboxChange(fieldName, value) {
|
||||||
|
let checkedValue = value ? '1' : '0';
|
||||||
|
let newState = {[fieldName]: checkedValue};
|
||||||
|
|
||||||
|
this.setState(newState);
|
||||||
|
this.props.onClientSettingsChange(newState);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
const METHODS_TO_BIND = ['handleDownloadTextChange', 'handleUploadTextChange'];
|
|
||||||
|
|
||||||
export default class SpeedLimitTab extends React.Component {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
downloadValue: null,
|
|
||||||
uploadValue: null
|
|
||||||
};
|
|
||||||
|
|
||||||
METHODS_TO_BIND.forEach((method) => {
|
|
||||||
this[method] = this[method].bind(this);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
arrayToString(array) {
|
|
||||||
return array.join(', ');
|
|
||||||
}
|
|
||||||
|
|
||||||
getTextboxValue(input = []) {
|
|
||||||
if (Array.isArray(input)) {
|
|
||||||
return this.arrayToString(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleDownloadTextChange(event) {
|
|
||||||
this.setState({
|
|
||||||
downloadValue: event.target.value
|
|
||||||
});
|
|
||||||
|
|
||||||
this.props.onSettingsChange({
|
|
||||||
speedLimits: {
|
|
||||||
download: this.processSpeedsForSave(event.target.value)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleUploadTextChange(event) {
|
|
||||||
this.setState({
|
|
||||||
uploadValue: event.target.value
|
|
||||||
});
|
|
||||||
|
|
||||||
this.props.onSettingsChange({
|
|
||||||
speedLimits: {
|
|
||||||
upload: this.processSpeedsForSave(event.target.value)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getDownloadValue() {
|
|
||||||
let displayedValue = this.state.downloadValue;
|
|
||||||
|
|
||||||
if (displayedValue == null && this.props.settings.speedLimits != null) {
|
|
||||||
displayedValue = this.processSpeedsForDisplay(this.props.settings.speedLimits.download);
|
|
||||||
}
|
|
||||||
|
|
||||||
return displayedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
getUploadValue() {
|
|
||||||
let displayedValue = this.state.uploadValue;
|
|
||||||
|
|
||||||
if (displayedValue == null && this.props.settings.speedLimits != null) {
|
|
||||||
displayedValue = this.processSpeedsForDisplay(this.props.settings.speedLimits.upload);
|
|
||||||
}
|
|
||||||
|
|
||||||
return displayedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
processSpeedsForDisplay(speeds = []) {
|
|
||||||
if (!speeds || speeds.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.arrayToString(speeds.map((speed) => {
|
|
||||||
return Number(speed) / 1024;
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
processSpeedsForSave(speeds = '') {
|
|
||||||
if (speeds === '') {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.stringToArray(speeds).map((speed) => {
|
|
||||||
return Number(speed) * 1024;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
stringToArray(string = '') {
|
|
||||||
return string.replace(/\s/g, '').split(',');
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
let downloadValue = this.getDownloadValue() || 0;
|
|
||||||
let uploadValue = this.getUploadValue() || 0;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<p className="modal__tab__introduction">
|
|
||||||
Provide a comma-separated list of speed values (in kilobytes per second). 0 represents unlimited.
|
|
||||||
</p>
|
|
||||||
<div className="form">
|
|
||||||
<div className="form__row">
|
|
||||||
<div className="form__column">
|
|
||||||
<label className="form__label">
|
|
||||||
Download Presets
|
|
||||||
</label>
|
|
||||||
<input className="textbox" type="text"
|
|
||||||
onChange={this.handleDownloadTextChange}
|
|
||||||
value={downloadValue} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="form__row">
|
|
||||||
<div className="form__column">
|
|
||||||
<label className="form__label">
|
|
||||||
Upload Presets
|
|
||||||
</label>
|
|
||||||
<input className="textbox" type="text"
|
|
||||||
onChange={this.handleUploadTextChange}
|
|
||||||
value={uploadValue} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
35
client/source/scripts/components/settings/StorageTab.js
Normal file
35
client/source/scripts/components/settings/StorageTab.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import Checkbox from '../forms/Checkbox';
|
||||||
|
import SettingsTab from './SettingsTab';
|
||||||
|
|
||||||
|
export default class StorageTab extends SettingsTab {
|
||||||
|
constructor() {
|
||||||
|
super(...arguments);
|
||||||
|
|
||||||
|
this.state = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="form">
|
||||||
|
<div className="form__section">
|
||||||
|
<div className="form__section__heading">
|
||||||
|
Directories
|
||||||
|
</div>
|
||||||
|
<div className="form__row">
|
||||||
|
<div className="form__column">
|
||||||
|
<label className="form__label">
|
||||||
|
Default Download Directory
|
||||||
|
</label>
|
||||||
|
<input className="textbox" type="text"
|
||||||
|
onChange={this.handleClientSettingCheckboxChange.bind(this, 'directoryDefault')}
|
||||||
|
value={this.getFieldValue('directoryDefault')} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@ class SpeedLimitDropdown extends React.Component {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
speedLimits: SettingsStore.getSettings('speedLimits'),
|
speedLimits: SettingsStore.getFloodSettings('speedLimits'),
|
||||||
throttle: null
|
throttle: null
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ class SpeedLimitDropdown extends React.Component {
|
|||||||
this.handleSettingsFetchRequestSuccess);
|
this.handleSettingsFetchRequestSuccess);
|
||||||
TransferDataStore.listen(EventTypes.CLIENT_TRANSFER_DATA_REQUEST_SUCCESS,
|
TransferDataStore.listen(EventTypes.CLIENT_TRANSFER_DATA_REQUEST_SUCCESS,
|
||||||
this.onTransferDataRequestSuccess);
|
this.onTransferDataRequestSuccess);
|
||||||
SettingsStore.fetchSettings('speedLimits');
|
SettingsStore.fetchFloodSettings('speedLimits');
|
||||||
TransferDataStore.fetchTransferData();
|
TransferDataStore.fetchTransferData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,7 +129,7 @@ class SpeedLimitDropdown extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleSettingsFetchRequestSuccess() {
|
handleSettingsFetchRequestSuccess() {
|
||||||
let speedLimits = SettingsStore.getSettings('speedLimits');
|
let speedLimits = SettingsStore.getFloodSettings('speedLimits');
|
||||||
|
|
||||||
if (!!speedLimits) {
|
if (!!speedLimits) {
|
||||||
this.setState({speedLimits});
|
this.setState({speedLimits});
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export default class ActionBar extends React.Component {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
sortBy: SettingsStore.getSettings('sortTorrents')
|
sortBy: SettingsStore.getFloodSettings('sortTorrents')
|
||||||
};
|
};
|
||||||
|
|
||||||
METHODS_TO_BIND.forEach((method) => {
|
METHODS_TO_BIND.forEach((method) => {
|
||||||
@@ -40,7 +40,7 @@ export default class ActionBar extends React.Component {
|
|||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.onSortChange();
|
this.onSortChange();
|
||||||
SettingsStore.listen(EventTypes.SETTINGS_CHANGE, this.onSortChange);
|
SettingsStore.listen(EventTypes.SETTINGS_CHANGE, this.onSortChange);
|
||||||
SettingsStore.fetchSettings('sortTorrents');
|
SettingsStore.fetchFloodSettings('sortTorrents');
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
@@ -99,7 +99,7 @@ export default class ActionBar extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleSortChange(sortBy) {
|
handleSortChange(sortBy) {
|
||||||
SettingsStore.saveSettings({id: 'sortTorrents', data: sortBy});
|
SettingsStore.saveFloodSettings({id: 'sortTorrents', data: sortBy});
|
||||||
UIActions.setTorrentsSort(sortBy);
|
UIActions.setTorrentsSort(sortBy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +112,7 @@ export default class ActionBar extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onSortChange() {
|
onSortChange() {
|
||||||
let sortBy = SettingsStore.getSettings('sortTorrents');
|
let sortBy = SettingsStore.getFloodSettings('sortTorrents');
|
||||||
TorrentFilterStore.setTorrentsSort(sortBy);
|
TorrentFilterStore.setTorrentsSort(sortBy);
|
||||||
this.setState({sortBy});
|
this.setState({sortBy});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,9 +21,14 @@ const ActionTypes = {
|
|||||||
CLIENT_SET_FILE_PRIORITY_SUCCESS: 'CLIENT_SET_FILE_PRIORITY_SUCCESS',
|
CLIENT_SET_FILE_PRIORITY_SUCCESS: 'CLIENT_SET_FILE_PRIORITY_SUCCESS',
|
||||||
CLIENT_SET_THROTTLE_ERROR: 'CLIENT_SET_THROTTLE_ERROR',
|
CLIENT_SET_THROTTLE_ERROR: 'CLIENT_SET_THROTTLE_ERROR',
|
||||||
CLIENT_SET_THROTTLE_SUCCESS: 'CLIENT_SET_THROTTLE_SUCCESS',
|
CLIENT_SET_THROTTLE_SUCCESS: 'CLIENT_SET_THROTTLE_SUCCESS',
|
||||||
|
CLIENT_SETTINGS_FETCH_REQUEST_ERROR: 'CLIENT_SETTINGS_FETCH_REQUEST_ERROR',
|
||||||
|
CLIENT_SETTINGS_FETCH_REQUEST_SUCCESS: 'CLIENT_SETTINGS_FETCH_REQUEST_SUCCESS',
|
||||||
|
CLIENT_SETTINGS_SAVE_ERROR: 'CLIENT_SETTINGS_SAVE_ERROR',
|
||||||
|
CLIENT_SETTINGS_SAVE_SUCCESS: 'CLIENT_SETTINGS_SAVE_SUCCESS',
|
||||||
CLIENT_START_TORRENT_ERROR: 'CLIENT_START_TORRENT_ERROR',
|
CLIENT_START_TORRENT_ERROR: 'CLIENT_START_TORRENT_ERROR',
|
||||||
CLIENT_START_TORRENT_SUCCESS: 'CLIENT_START_TORRENT_SUCCESS',
|
CLIENT_START_TORRENT_SUCCESS: 'CLIENT_START_TORRENT_SUCCESS',
|
||||||
CLIENT_STOP_TORRENT_ERROR: 'CLIENT_STOP_TORRENT_ERROR',
|
CLIENT_STOP_TORRENT_ERROR: 'CLIENT_STOP_TORRENT_ERROR',
|
||||||
|
CLIENT_STOP_TORRENT_SUCCESS: 'CLIENT_STOP_TORRENT_SUCCESS',
|
||||||
SETTINGS_FETCH_REQUEST_SUCCESS: 'SETTINGS_FETCH_REQUEST_SUCCESS',
|
SETTINGS_FETCH_REQUEST_SUCCESS: 'SETTINGS_FETCH_REQUEST_SUCCESS',
|
||||||
SETTINGS_FETCH_REQUEST_ERROR: 'SETTINGS_FETCH_REQUEST_ERROR',
|
SETTINGS_FETCH_REQUEST_ERROR: 'SETTINGS_FETCH_REQUEST_ERROR',
|
||||||
SETTINGS_SAVE_REQUEST_SUCCESS: 'SETTINGS_SAVE_REQUEST_SUCCESS',
|
SETTINGS_SAVE_REQUEST_SUCCESS: 'SETTINGS_SAVE_REQUEST_SUCCESS',
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ const EventTypes = {
|
|||||||
CLIENT_SET_THROTTLE_SUCCESS: 'CLIENT_SET_THROTTLE_SUCCESS',
|
CLIENT_SET_THROTTLE_SUCCESS: 'CLIENT_SET_THROTTLE_SUCCESS',
|
||||||
CLIENT_MOVE_TORRENTS_REQUEST_ERROR: 'CLIENT_MOVE_TORRENTS_REQUEST_ERROR',
|
CLIENT_MOVE_TORRENTS_REQUEST_ERROR: 'CLIENT_MOVE_TORRENTS_REQUEST_ERROR',
|
||||||
CLIENT_MOVE_TORRENTS_SUCCESS: 'CLIENT_MOVE_TORRENTS_SUCCESS',
|
CLIENT_MOVE_TORRENTS_SUCCESS: 'CLIENT_MOVE_TORRENTS_SUCCESS',
|
||||||
|
CLIENT_SETTINGS_FETCH_REQUEST_ERROR: 'CLIENT_SETTINGS_FETCH_REQUEST_ERROR',
|
||||||
|
CLIENT_SETTINGS_FETCH_REQUEST_SUCCESS: 'CLIENT_SETTINGS_FETCH_REQUEST_SUCCESS',
|
||||||
|
CLIENT_SETTINGS_SAVE_REQUEST_ERROR: 'CLIENT_SETTINGS_SAVE_REQUEST_ERROR',
|
||||||
|
CLIENT_SETTINGS_SAVE_REQUEST_SUCCESS: 'CLIENT_SETTINGS_SAVE_REQUEST_SUCCESS',
|
||||||
CLIENT_TORRENTS_REQUEST_ERROR: 'CLIENT_TORRENTS_REQUEST_ERROR',
|
CLIENT_TORRENTS_REQUEST_ERROR: 'CLIENT_TORRENTS_REQUEST_ERROR',
|
||||||
CLIENT_TORRENT_STATUS_COUNT_CHANGE: 'CLIENT_TORRENT_STATUS_COUNT_CHANGE',
|
CLIENT_TORRENT_STATUS_COUNT_CHANGE: 'CLIENT_TORRENT_STATUS_COUNT_CHANGE',
|
||||||
CLIENT_TORRENT_STATUS_COUNT_REQUEST_ERROR: 'CLIENT_TORRENT_STATUS_COUNT_REQUEST_ERROR',
|
CLIENT_TORRENT_STATUS_COUNT_REQUEST_ERROR: 'CLIENT_TORRENT_STATUS_COUNT_REQUEST_ERROR',
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import ActionTypes from '../constants/ActionTypes';
|
import ActionTypes from '../constants/ActionTypes';
|
||||||
import AppDispatcher from '../dispatcher/AppDispatcher';
|
import AppDispatcher from '../dispatcher/AppDispatcher';
|
||||||
import BaseStore from './BaseStore';
|
import BaseStore from './BaseStore';
|
||||||
|
import ClientActions from '../actions/ClientActions';
|
||||||
import EventTypes from '../constants/EventTypes';
|
import EventTypes from '../constants/EventTypes';
|
||||||
import NotificationStore from './NotificationStore';
|
import NotificationStore from './NotificationStore';
|
||||||
import SettingsActions from '../actions/SettingsActions';
|
import SettingsActions from '../actions/SettingsActions';
|
||||||
@@ -10,8 +11,15 @@ class SettingsStoreClass extends BaseStore {
|
|||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
this.fetchStatus = {
|
||||||
|
clientSettingsFetched: false,
|
||||||
|
floodSettingsFetched: false
|
||||||
|
};
|
||||||
|
|
||||||
|
this.clientSettings = {};
|
||||||
|
|
||||||
// Default settings are overridden by settings stored in database.
|
// Default settings are overridden by settings stored in database.
|
||||||
this.settings = {
|
this.floodSettings = {
|
||||||
sortTorrents: {
|
sortTorrents: {
|
||||||
direction: 'desc',
|
direction: 'desc',
|
||||||
displayName: 'Date Added',
|
displayName: 'Date Added',
|
||||||
@@ -25,16 +33,61 @@ class SettingsStoreClass extends BaseStore {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchSettings(property) {
|
fetchClientSettings(property) {
|
||||||
|
ClientActions.fetchSettings(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchFloodSettings(property) {
|
||||||
SettingsActions.fetchSettings(property);
|
SettingsActions.fetchSettings(property);
|
||||||
}
|
}
|
||||||
|
|
||||||
getSettings(property) {
|
getClientSettings(property) {
|
||||||
if (property) {
|
if (property) {
|
||||||
return this.settings[property];
|
return this.clientSettings[property];
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.settings;
|
return Object.assign({}, this.clientSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
getFloodSettings(property) {
|
||||||
|
if (property) {
|
||||||
|
return this.floodSettings[property];
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.assign({}, this.floodSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClientSettingsFetchSuccess(settings) {
|
||||||
|
this.fetchStatus.clientSettingsFetched = true;
|
||||||
|
this.clientSettings = settings;
|
||||||
|
|
||||||
|
this.emit(EventTypes.CLIENT_SETTINGS_FETCH_REQUEST_SUCCESS);
|
||||||
|
this.processSettingsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClientSettingsFetchError(error) {
|
||||||
|
this.emit(EventTypes.CLIENT_SETTINGS_FETCH_REQUEST_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClientSettingsSaveRequestError() {
|
||||||
|
this.emit(EventTypes.CLIENT_SETTINGS_SAVE_REQUEST_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClientSettingsSaveRequestSuccess(data, options) {
|
||||||
|
this.emit(EventTypes.CLIENT_SETTINGS_SAVE_REQUEST_SUCCESS);
|
||||||
|
|
||||||
|
if (options.notify) {
|
||||||
|
NotificationStore.add({
|
||||||
|
adverb: 'Successfully',
|
||||||
|
action: 'saved',
|
||||||
|
subject: 'settings',
|
||||||
|
id: 'save-settings-success'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.dismissModal) {
|
||||||
|
UIStore.dismissModal();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSettingsFetchError(error) {
|
handleSettingsFetchError(error) {
|
||||||
@@ -42,12 +95,14 @@ class SettingsStoreClass extends BaseStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleSettingsFetchSuccess(settings) {
|
handleSettingsFetchSuccess(settings) {
|
||||||
|
this.fetchStatus.floodSettingsFetched = true;
|
||||||
|
|
||||||
Object.keys(settings).forEach((property) => {
|
Object.keys(settings).forEach((property) => {
|
||||||
this.settings[property] = settings[property];
|
this.floodSettings[property] = settings[property];
|
||||||
});
|
});
|
||||||
|
|
||||||
this.emit(EventTypes.SETTINGS_CHANGE);
|
|
||||||
this.emit(EventTypes.SETTINGS_FETCH_REQUEST_SUCCESS);
|
this.emit(EventTypes.SETTINGS_FETCH_REQUEST_SUCCESS);
|
||||||
|
this.processSettingsState();
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSettingsSaveRequestError() {
|
handleSettingsSaveRequestError() {
|
||||||
@@ -62,7 +117,7 @@ class SettingsStoreClass extends BaseStore {
|
|||||||
adverb: 'Successfully',
|
adverb: 'Successfully',
|
||||||
action: 'saved',
|
action: 'saved',
|
||||||
subject: 'settings',
|
subject: 'settings',
|
||||||
id: 'save-torrents-success'
|
id: 'save-settings-success'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,31 +126,70 @@ class SettingsStoreClass extends BaseStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
saveSettings(settings, options) {
|
processSettingsState() {
|
||||||
this.settings[settings.id] = settings.data;
|
if (this.fetchStatus.clientSettingsFetched
|
||||||
SettingsActions.saveSettings(settings, options);
|
&& this.fetchStatus.floodSettingsFetched) {
|
||||||
this.emit(EventTypes.SETTINGS_CHANGE);
|
this.emit(EventTypes.SETTINGS_CHANGE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
saveFloodSettings(settings, options) {
|
||||||
|
if (!Array.isArray(settings)) {
|
||||||
|
settings = [settings];
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsActions.saveSettings(settings, options);
|
||||||
|
this.updateLocalSettings(settings, 'floodSettings');
|
||||||
|
this.emit(EventTypes.SETTINGS_CHANGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
saveClientSettings(settings, options) {
|
||||||
|
if (!Array.isArray(settings)) {
|
||||||
|
settings = [settings];
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientActions.saveSettings(settings, options);
|
||||||
|
this.updateLocalSettings(settings, 'clientSettings');
|
||||||
|
this.emit(EventTypes.SETTINGS_CHANGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateLocalSettings(settings, settingsType) {
|
||||||
|
settings.forEach((setting) => {
|
||||||
|
this[settingsType][setting.id] = setting.data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let SettingsStore = new SettingsStoreClass();
|
let SettingsStore = new SettingsStoreClass();
|
||||||
|
|
||||||
SettingsStore.dispatcherID = AppDispatcher.register((payload) => {
|
SettingsStore.dispatcherID = AppDispatcher.register((payload) => {
|
||||||
const {action, source} = payload;
|
const {action, source} = payload;
|
||||||
|
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ActionTypes.SETTINGS_FETCH_REQUEST_SUCCESS:
|
case ActionTypes.CLIENT_SETTINGS_FETCH_REQUEST_ERROR:
|
||||||
SettingsStore.handleSettingsFetchSuccess(action.data);
|
SettingsStore.handleClientSettingsFetchError(action.error);
|
||||||
|
break;
|
||||||
|
case ActionTypes.CLIENT_SETTINGS_FETCH_REQUEST_SUCCESS:
|
||||||
|
SettingsStore.handleClientSettingsFetchSuccess(action.data);
|
||||||
break;
|
break;
|
||||||
case ActionTypes.SETTINGS_FETCH_REQUEST_ERROR:
|
case ActionTypes.SETTINGS_FETCH_REQUEST_ERROR:
|
||||||
SettingsStore.handleSettingsFetchError(action.error);
|
SettingsStore.handleSettingsFetchError(action.error);
|
||||||
break;
|
break;
|
||||||
|
case ActionTypes.SETTINGS_FETCH_REQUEST_SUCCESS:
|
||||||
|
SettingsStore.handleSettingsFetchSuccess(action.data);
|
||||||
|
break;
|
||||||
case ActionTypes.SETTINGS_SAVE_REQUEST_ERROR:
|
case ActionTypes.SETTINGS_SAVE_REQUEST_ERROR:
|
||||||
SettingsStore.handleSettingsSaveRequestError(action.error);
|
SettingsStore.handleSettingsSaveRequestError(action.error);
|
||||||
break;
|
break;
|
||||||
case ActionTypes.SETTINGS_SAVE_REQUEST_SUCCESS:
|
case ActionTypes.SETTINGS_SAVE_REQUEST_SUCCESS:
|
||||||
SettingsStore.handleSettingsSaveRequestSuccess(action.data, action.options);
|
SettingsStore.handleSettingsSaveRequestSuccess(action.data, action.options);
|
||||||
break;
|
break;
|
||||||
|
case ActionTypes.CLIENT_SETTINGS_SAVE_ERROR:
|
||||||
|
SettingsStore.handleClientSettingsSaveRequestError(action.error);
|
||||||
|
break;
|
||||||
|
case ActionTypes.CLIENT_SETTINGS_SAVE_SUCCESS:
|
||||||
|
SettingsStore.handleClientSettingsSaveRequestSuccess(action.data, action.options);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class TorrentFilterStoreClass extends BaseStore {
|
|||||||
this.searchFilter = null;
|
this.searchFilter = null;
|
||||||
this.statusFilter = 'all';
|
this.statusFilter = 'all';
|
||||||
this.trackerFilter = 'all';
|
this.trackerFilter = 'all';
|
||||||
this.sortTorrentsBy = SettingsStore.getSettings('sortTorrents');
|
this.sortTorrentsBy = SettingsStore.getFloodSettings('sortTorrents');
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchTorrentStatusCount() {
|
fetchTorrentStatusCount() {
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ class TorrentStoreClass extends BaseStore {
|
|||||||
handleAddTorrentSuccess(response) {
|
handleAddTorrentSuccess(response) {
|
||||||
this.emit(EventTypes.CLIENT_ADD_TORRENT_SUCCESS);
|
this.emit(EventTypes.CLIENT_ADD_TORRENT_SUCCESS);
|
||||||
|
|
||||||
SettingsStore.saveSettings({
|
SettingsStore.saveFloodSettings({
|
||||||
id: 'torrentDestination',
|
id: 'torrentDestination',
|
||||||
data: response.destination
|
data: response.destination
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
let util = require('util');
|
|
||||||
|
|
||||||
let clientUtil = require('../util/clientUtil');
|
|
||||||
let fs = require('fs');
|
let fs = require('fs');
|
||||||
let mv = require('mv');
|
let mv = require('mv');
|
||||||
let path = require('path');
|
let path = require('path');
|
||||||
|
let util = require('util');
|
||||||
|
|
||||||
|
let clientSettingsMap = require('../../shared/constants/clientSettingsMap');
|
||||||
|
let clientUtil = require('../util/clientUtil');
|
||||||
let rTorrentPropMap = require('../util/rTorrentPropMap');
|
let rTorrentPropMap = require('../util/rTorrentPropMap');
|
||||||
let scgi = require('../util/scgi');
|
let scgi = require('../util/scgi');
|
||||||
let stringUtil = require('../../shared/util/stringUtil');
|
let stringUtil = require('../../shared/util/stringUtil');
|
||||||
@@ -163,6 +164,27 @@ class ClientRequest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fetchSettingsMethodCall(options) {
|
||||||
|
let requestedSettings = [];
|
||||||
|
|
||||||
|
if (options.requestedSettings) {
|
||||||
|
requestedSettings = options.requestedSettings;
|
||||||
|
} else {
|
||||||
|
requestedSettings = clientSettingsMap.defaults.map((settingsKey) => {
|
||||||
|
return clientSettingsMap[settingsKey];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure client's response gets mapped to the correct requested property.
|
||||||
|
if (options.setPropertiesArr) {
|
||||||
|
options.setPropertiesArr(requestedSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
requestedSettings.forEach((settingsKey) => {
|
||||||
|
this.requests.push(this.getMethodCall(settingsKey));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
getTorrentDetailsMethodCall(options) {
|
getTorrentDetailsMethodCall(options) {
|
||||||
var peerParams = [options.hash, ''].concat(options.peerProps);
|
var peerParams = [options.hash, ''].concat(options.peerProps);
|
||||||
var fileParams = [options.hash, ''].concat(options.fileProps);
|
var fileParams = [options.hash, ''].concat(options.fileProps);
|
||||||
@@ -251,6 +273,16 @@ class ClientRequest {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setSettingsMethodCall(options) {
|
||||||
|
console.log(options);
|
||||||
|
let settings = this.getEnsuredArray(options.settings);
|
||||||
|
|
||||||
|
settings.forEach((setting) => {
|
||||||
|
this.requests.push(this.getMethodCall(`${clientSettingsMap[setting.id]}.set`,
|
||||||
|
['', setting.data]));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
setThrottleMethodCall(options) {
|
setThrottleMethodCall(options) {
|
||||||
let methodName = 'throttle.global_down.max_rate.set';
|
let methodName = 'throttle.global_down.max_rate.set';
|
||||||
if (options.direction === 'upload') {
|
if (options.direction === 'upload') {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ let fs = require('fs');
|
|||||||
let util = require('util');
|
let util = require('util');
|
||||||
|
|
||||||
let clientResponseUtil = require('../util/clientResponseUtil');
|
let clientResponseUtil = require('../util/clientResponseUtil');
|
||||||
|
let clientSettingsMap = require('../../shared/constants/clientSettingsMap');
|
||||||
let ClientRequest = require('./ClientRequest');
|
let ClientRequest = require('./ClientRequest');
|
||||||
let clientUtil = require('../util/clientUtil');
|
let clientUtil = require('../util/clientUtil');
|
||||||
let propsMap = require('../../shared/constants/propsMap');
|
let propsMap = require('../../shared/constants/propsMap');
|
||||||
@@ -61,6 +62,33 @@ var client = {
|
|||||||
request.send();
|
request.send();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getSettings: (options, callback) => {
|
||||||
|
let properties = [];
|
||||||
|
let request = new ClientRequest();
|
||||||
|
let response = {};
|
||||||
|
|
||||||
|
request.add('fetchSettings', {
|
||||||
|
options,
|
||||||
|
setPropertiesArr: (propertiesArr) => {
|
||||||
|
properties = propertiesArr;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
request.postProcess((data) => {
|
||||||
|
if (!data) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.forEach((datum, index) => {
|
||||||
|
response[clientSettingsMap[properties[index]]] = datum[0];
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
});
|
||||||
|
request.onComplete(callback);
|
||||||
|
request.send();
|
||||||
|
},
|
||||||
|
|
||||||
getTorrentStatusCount: (callback) => {
|
getTorrentStatusCount: (callback) => {
|
||||||
callback(_statusCount);
|
callback(_statusCount);
|
||||||
},
|
},
|
||||||
@@ -172,6 +200,19 @@ var client = {
|
|||||||
request.send();
|
request.send();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setSettings: (payloads, callback) => {
|
||||||
|
let request = new ClientRequest();
|
||||||
|
|
||||||
|
if (payloads.length === 0) {
|
||||||
|
callback({});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
request.add('setSettings', {settings: payloads});
|
||||||
|
request.onComplete(callback);
|
||||||
|
request.send();
|
||||||
|
},
|
||||||
|
|
||||||
setSpeedLimits: (data, callback) => {
|
setSpeedLimits: (data, callback) => {
|
||||||
let request = new ClientRequest();
|
let request = new ClientRequest();
|
||||||
|
|
||||||
|
|||||||
@@ -24,23 +24,28 @@ router.post('/add-files', upload.array('torrents'), function(req, res, next) {
|
|||||||
client.addFiles(req, ajaxUtil.getResponseFn(res));
|
client.addFiles(req, ajaxUtil.getResponseFn(res));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get('/settings', function(req, res, next) {
|
||||||
|
client.getSettings(req.query, ajaxUtil.getResponseFn(res));
|
||||||
|
});
|
||||||
|
|
||||||
|
router.patch('/settings', function(req, res, next) {
|
||||||
|
client.setSettings(req.body, ajaxUtil.getResponseFn(res));
|
||||||
|
});
|
||||||
|
|
||||||
router.put('/settings/speed-limits', function(req, res, next) {
|
router.put('/settings/speed-limits', function(req, res, next) {
|
||||||
client.setSpeedLimits(req.body, ajaxUtil.getResponseFn(res));
|
client.setSpeedLimits(req.body, ajaxUtil.getResponseFn(res));
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post('/start', function(req, res, next) {
|
router.post('/start', function(req, res, next) {
|
||||||
var hashes = req.body.hashes;
|
client.startTorrent(req.body.hashes, ajaxUtil.getResponseFn(res));
|
||||||
client.startTorrent(hashes, ajaxUtil.getResponseFn(res));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post('/stop', function(req, res, next) {
|
router.post('/stop', function(req, res, next) {
|
||||||
var hashes = req.body.hashes;
|
client.stopTorrent(req.body.hashes, ajaxUtil.getResponseFn(res));
|
||||||
client.stopTorrent(hashes, ajaxUtil.getResponseFn(res));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post('/torrent-details', function(req, res, next) {
|
router.post('/torrent-details', function(req, res, next) {
|
||||||
var hash = req.body.hash;
|
client.getTorrentDetails(req.body.hash, ajaxUtil.getResponseFn(res));
|
||||||
client.getTorrentDetails(hash, ajaxUtil.getResponseFn(res));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/torrents', function(req, res, next) {
|
router.get('/torrents', function(req, res, next) {
|
||||||
@@ -59,6 +64,10 @@ router.post('/torrents/move', function(req, res, next) {
|
|||||||
client.moveTorrents(req.body, ajaxUtil.getResponseFn(res));
|
client.moveTorrents(req.body, ajaxUtil.getResponseFn(res));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.post('/torrents/delete', function(req, res, next) {
|
||||||
|
client.deleteTorrents(req.body.hash, ajaxUtil.getResponseFn(res));
|
||||||
|
});
|
||||||
|
|
||||||
router.get('/torrents/status-count', function(req, res, next) {
|
router.get('/torrents/status-count', function(req, res, next) {
|
||||||
client.getTorrentStatusCount(ajaxUtil.getResponseFn(res));
|
client.getTorrentStatusCount(ajaxUtil.getResponseFn(res));
|
||||||
});
|
});
|
||||||
@@ -67,11 +76,6 @@ router.get('/torrents/tracker-count', function(req, res, next) {
|
|||||||
client.getTorrentTrackerCount(ajaxUtil.getResponseFn(res));
|
client.getTorrentTrackerCount(ajaxUtil.getResponseFn(res));
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post('/torrents/delete', function(req, res, next) {
|
|
||||||
var hash = req.body.hash;
|
|
||||||
client.deleteTorrents(hash, ajaxUtil.getResponseFn(res));
|
|
||||||
});
|
|
||||||
|
|
||||||
router.get('/methods.json', function(req, res, next) {
|
router.get('/methods.json', function(req, res, next) {
|
||||||
var type = req.query.type;
|
var type = req.query.type;
|
||||||
var args = req.query.args;
|
var args = req.query.args;
|
||||||
|
|||||||
105
shared/constants/clientSettingsMap.js
Normal file
105
shared/constants/clientSettingsMap.js
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
let objectUtil = require('../util/objectUtil');
|
||||||
|
|
||||||
|
const clientSettingsMap = objectUtil.reflect({
|
||||||
|
dhtPort: 'dht.port',
|
||||||
|
dhtStatus: 'dht.statistics',
|
||||||
|
directoryDefault: 'directory.default',
|
||||||
|
maxFileSize: 'system.file.max_size',
|
||||||
|
networkBindAddress: 'network.bind_address',
|
||||||
|
networkHttpCert: 'network.http.cacert',
|
||||||
|
networkHttpMaxOpen: 'network.http.max_open',
|
||||||
|
networkHttpPath: 'network.http.capath',
|
||||||
|
networkHttpProxy: 'network.http.proxy_address',
|
||||||
|
networkLocalAddress: 'network.local_address',
|
||||||
|
networkMaxOpenFiles: 'network.max_open_files',
|
||||||
|
networkMaxOpenSockets: 'network.max_open_sockets',
|
||||||
|
networkPortOpen: 'network.port_open',
|
||||||
|
networkPortRandom: 'network.port_random',
|
||||||
|
networkPortRange: 'network.port_range',
|
||||||
|
networkReceiveBufferSize: 'network.receive_buffer.size',
|
||||||
|
networkScgiDontRoute: 'network.scgi.dont_route',
|
||||||
|
networkSendBufferSize: 'network.send_buffer.size',
|
||||||
|
piecesHashOnCompletion: 'pieces.hash.on_completion',
|
||||||
|
piecesMemoryMax: 'pieces.memory.max',
|
||||||
|
piecesPreloadMinRate: 'pieces.preload.min_rate',
|
||||||
|
piecesPreloadMinSize: 'pieces.preload.min_size',
|
||||||
|
piecesPreloadType: 'pieces.preload.type',
|
||||||
|
piecesSyncAlwaysSafe: 'pieces.sync.always_safe',
|
||||||
|
piecesSyncTimeout: 'pieces.sync.timeout',
|
||||||
|
piecesSyncTimeoutSafe: 'pieces.sync.timeout_safe',
|
||||||
|
protocolPex: 'protocol.pex',
|
||||||
|
sessionOnCompletion: 'session.on_completion',
|
||||||
|
sessionPath: 'session.path',
|
||||||
|
sessionUseLock: 'session.use_lock',
|
||||||
|
systemFileSplitSize: 'system.file.split_size',
|
||||||
|
systemFileSplitSuffix: 'system.file.split_suffix',
|
||||||
|
throttleDownMax: 'throttle.global_down.max_rate',
|
||||||
|
throttleGlobalUpMax: 'throttle.global_up.max_rate',
|
||||||
|
throttleMaxDownloadsDiv: 'throttle.max_downloads.div',
|
||||||
|
throttleMaxDownloadsGlobal: 'throttle.max_downloads.global',
|
||||||
|
throttleMaxPeersNormal: 'throttle.max_peers.normal',
|
||||||
|
throttleMaxPeersSeed: 'throttle.max_peers.seed',
|
||||||
|
throttleMaxDownloads: 'throttle.max_downloads',
|
||||||
|
throttleMaxDownloadsDiv: 'throttle.max_downloads.div',
|
||||||
|
throttleMaxDownloadsGlobal: 'throttle.max_downloads.global',
|
||||||
|
throttleMaxUploads: 'throttle.max_uploads',
|
||||||
|
throttleMaxUploadsDiv: 'throttle.max_uploads.div',
|
||||||
|
throttleMaxUploadsGlobal: 'throttle.max_uploads.global',
|
||||||
|
throttleMinPeersNormal: 'throttle.min_peers.normal',
|
||||||
|
throttleMinPeersSeed: 'throttle.min_peers.seed',
|
||||||
|
trackersNumWant: 'trackers.numwant',
|
||||||
|
trackersUseUdp: 'trackers.use_udp'
|
||||||
|
});
|
||||||
|
|
||||||
|
clientSettingsMap.defaults = [
|
||||||
|
'dhtPort',
|
||||||
|
'dhtStatus',
|
||||||
|
'directoryDefault',
|
||||||
|
'maxFileSize',
|
||||||
|
'networkBindAddress',
|
||||||
|
'networkHttpCert',
|
||||||
|
'networkHttpMaxOpen',
|
||||||
|
'networkHttpPath',
|
||||||
|
'networkHttpProxy',
|
||||||
|
'networkLocalAddress',
|
||||||
|
'networkMaxOpenFiles',
|
||||||
|
'networkMaxOpenSockets',
|
||||||
|
'networkPortOpen',
|
||||||
|
'networkPortRandom',
|
||||||
|
'networkPortRange',
|
||||||
|
'networkReceiveBufferSize',
|
||||||
|
'networkScgiDontRoute',
|
||||||
|
'networkSendBufferSize',
|
||||||
|
'piecesHashOnCompletion',
|
||||||
|
'piecesMemoryMax',
|
||||||
|
'piecesPreloadMinRate',
|
||||||
|
'piecesPreloadMinSize',
|
||||||
|
'piecesPreloadType',
|
||||||
|
'piecesSyncAlwaysSafe',
|
||||||
|
'piecesSyncTimeout',
|
||||||
|
'piecesSyncTimeoutSafe',
|
||||||
|
'protocolPex',
|
||||||
|
'sessionOnCompletion',
|
||||||
|
'sessionPath',
|
||||||
|
'sessionUseLock',
|
||||||
|
'systemFileSplitSize',
|
||||||
|
'systemFileSplitSuffix',
|
||||||
|
'throttleDownMax',
|
||||||
|
'throttleGlobalUpMax',
|
||||||
|
'throttleMaxDownloadsDiv',
|
||||||
|
'throttleMaxDownloadsGlobal',
|
||||||
|
'throttleMaxPeersNormal',
|
||||||
|
'throttleMaxPeersSeed',
|
||||||
|
'throttleMaxDownloads',
|
||||||
|
'throttleMaxUploads',
|
||||||
|
'throttleMaxUploadsDiv',
|
||||||
|
'throttleMaxUploadsGlobal',
|
||||||
|
'throttleMinPeersNormal',
|
||||||
|
'throttleMinPeersSeed',
|
||||||
|
'trackersNumWant',
|
||||||
|
'trackersUseUdp'
|
||||||
|
];
|
||||||
|
|
||||||
|
module.exports = clientSettingsMap;
|
||||||
13
shared/util/objectUtil.js
Normal file
13
shared/util/objectUtil.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
let objectUtil = {
|
||||||
|
reflect: (hash) => {
|
||||||
|
return Object.keys(hash).reduce((memo, key) => {
|
||||||
|
memo[key] = hash[key];
|
||||||
|
memo[hash[key]] = key;
|
||||||
|
return memo;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = objectUtil;
|
||||||
Reference in New Issue
Block a user