diff --git a/config.cli.js b/config.cli.js index 5d21a2a1..21fdcb3a 100644 --- a/config.cli.js +++ b/config.cli.js @@ -91,6 +91,12 @@ const {argv} = require('yargs') hidden: true, type: 'number', }) + .option('clientpollidle', { + default: 1000 * 60 * 15, + describe: 'ADVANCED: How often (in ms) Flood will request the torrent list when no user is present', + hidden: true, + type: 'number', + }) .option('rtorrent', { default: false, describe: 'ADVANCED: rTorrent daemon managed by Flood', @@ -174,6 +180,7 @@ const CONFIG = { floodServerProxy: argv.proxy, maxHistoryStates: argv.maxhistorystates, torrentClientPollInterval: argv.clientpoll, + torrentClientPollIntervalIdle: argv.clientpollidle, secret, ssl: argv.ssl, sslKey: argv.sslkey || path.resolve(path.join(argv.rundir, 'key.pem')), diff --git a/config.d.ts b/config.d.ts index 4eff7cad..cd35f3dc 100644 --- a/config.d.ts +++ b/config.d.ts @@ -12,6 +12,7 @@ declare const CONFIG: { floodServerProxy: string; maxHistoryStates: number; torrentClientPollInterval: number; + torrentClientPollIntervalIdle: number; secret: string; ssl: boolean; sslKey: string; diff --git a/config.template.js b/config.template.js index 07f35791..a986ecb0 100644 --- a/config.template.js +++ b/config.template.js @@ -1,5 +1,5 @@ // This is the configuration file for Flood, a React-based frontend for the -// rtorrent BitTorrent client. +// rTorrent BitTorrent client. // Copy this file to ./config.js and make changes below. // config.js must exist before running `npm run build`. @@ -12,19 +12,24 @@ const CONFIG = { // the `/flood` of Flood's web server. // See https://github.com/Flood-UI/flood/wiki/Using-Flood-behind-a-reverse-proxy baseURI: '/', + // Flood uses a local nedb database to keep track of users, torrents, // and activity. The database is regularly purged to remove outdated data. // This value dictates how old data is, in milliseconds, before being purged. dbCleanInterval: 1000 * 60 * 60, + // Where to store the local nedb database. dbPath: './run/db/', + // Where to store Flood's temporary files tempPath: './run/temp/', + // If this is true, there will be no users and no attempt to // authenticate or password-protect any page. In that case, // instead of per-user config, the following configUser settings // will be used. disableUsersAndAuth: false, + // Settings for the no-user configuration. configUser: { // {ClientConnectionSettings} @@ -33,30 +38,48 @@ const CONFIG = { version: 1, socket: '/data/rtorrent.sock', }, + // The host that Flood should listen for web connections on. // If you want to connect to Flood from hosts other that the one it is running // on, you should change this value. // To listen on all interfaces, change to `floodServerHost: '0.0.0.0'`.. floodServerHost: '127.0.0.1', + // The port that Flood should listen for web connections on. floodServerPort: 3000, + // Used for development. See the "Local Development" section of README.md // for detail. floodServerProxy: 'http://127.0.0.1:3000', + // Flood keeps a history of torrent download and upload speeds. // This value dictates the number of individual records per period to keep. maxHistoryStates: 30, - // How often (in milliseconds) Flood will request the torrent list from. + + // How often (in milliseconds) Flood will request the torrent list. + // This value affects how often values are updated when a user is present. + // {torrentClientPollIntervalIdle} will be used when no user is present. + // Note that poll intervals only affect activity stream. API requests + // like "GET /api/torrents" always trigger fresh torrent list fetch. torrentClientPollInterval: 1000 * 2, + + // How often (in milliseconds) Flood will request the torrent list when no user is present. + // {torrentClientPollInterval} will be used when at least one user is present. This value + // usually affects some automations such as notification of download completion. Automations + // that rely on torrent properties may be delayed within the interval. + torrentClientPollIntervalIdle: 1000 * 60 * 15, + // A unique secret for signing messages with JWT (see https://jwt.io). // Change this to something unique and hard to guess. // You can use 'uuidgen' or 'cat /proc/sys/kernel/random/uuid' or 'uuidgenerator.net'. // eslint-disable-next-line no-undef secret: process.env.FLOOD_SECRET || CHANGE_ME, + // Configuration for SSL, if using SSL with the Flood service directly. ssl: false, sslKey: '/absolute/path/to/key/', sslCert: '/absolute/path/to/certificate/', + // disk space service checks disk space of mounted partitions diskUsageService: { // assign desired mounts to include. Refer to "Mounted on" column of `df -P` @@ -64,6 +87,7 @@ const CONFIG = { // "/mnt/disk" // ] }, + // Allowed paths for file operations // allowedPaths: ['/mnt/download', '/data/download'], }; diff --git a/server/services/torrentService.ts b/server/services/torrentService.ts index 036d7c7b..7afb80d8 100644 --- a/server/services/torrentService.ts +++ b/server/services/torrentService.ts @@ -15,8 +15,7 @@ interface TorrentServiceEvents { } class TorrentService extends BaseService { - errorCount = 0; - pollEnabled = false; + pollInterval = config.torrentClientPollIntervalIdle; pollTimeout: NodeJS.Timeout | null = null; torrentListSummary: TorrentListSummary = {id: Date.now(), torrents: {}}; @@ -41,25 +40,22 @@ class TorrentService extends BaseService { // starts polling when the first streaming listener is added this.on('newListener', (event) => { - if (!this.pollEnabled && event === 'TORRENT_LIST_DIFF_CHANGE') { - this.pollEnabled = true; - this.deferFetchTorrentList(); + if (event === 'TORRENT_LIST_DIFF_CHANGE') { + this.pollInterval = config.torrentClientPollInterval; } }); // stops polling when the last streaming listener is removed this.on('removeListener', (event) => { if (event === 'TORRENT_LIST_DIFF_CHANGE' && this.listenerCount('TORRENT_LIST_DIFF_CHANGE') === 0) { - this.pollEnabled = false; + this.pollInterval = config.torrentClientPollIntervalIdle; } }); }; } - deferFetchTorrentList(interval = config.torrentClientPollInterval || 2000) { - if (this.pollEnabled) { - this.pollTimeout = setTimeout(this.fetchTorrentList, interval); - } + deferFetchTorrentList() { + this.pollTimeout = setTimeout(this.fetchTorrentList, this.pollInterval || 2000); } destroy() { @@ -94,15 +90,7 @@ class TorrentService extends BaseService { } handleFetchTorrentListError() { - let nextInterval = config.torrentClientPollInterval || 2000; - - // If more than 2 consecutive errors have occurred, then we delay the next request. - this.errorCount += 1; - if (this.errorCount > 2) { - nextInterval = Math.min(nextInterval + 2 ** this.errorCount, 1000 * 60); - } - - this.deferFetchTorrentList(nextInterval); + this.deferFetchTorrentList(); this.emit('FETCH_TORRENT_LIST_ERROR'); return null; @@ -118,7 +106,6 @@ class TorrentService extends BaseService { this.deferFetchTorrentList(); - this.errorCount = 0; this.emit('FETCH_TORRENT_LIST_SUCCESS'); return this.torrentListSummary; }