feat(torrents): add aggregate upload limit control

This commit is contained in:
NimBold
2026-08-02 23:36:48 +03:30
parent b2c86a2ec4
commit cba485ef44
16 changed files with 466 additions and 95 deletions
+50
View File
@@ -37,6 +37,7 @@ import { normalizeCustomProxy } from '../store/useDownloadStore';
import {
MAX_TORRENT_MAX_OPEN_FILES,
MIN_TORRENT_MAX_OPEN_FILES,
normalizeSpeedLimitForBackend,
normalizeTorrentMaxOpenFiles
} from '../utils/downloads';
import { useTranslation } from 'react-i18next';
@@ -326,7 +327,11 @@ const engineRunId = useRef(0);
const [torrentMaxOpenFilesInput, setTorrentMaxOpenFilesInput] = useState(
() => String(settings.torrentMaxOpenFiles)
);
const [torrentOverallUploadLimitInput, setTorrentOverallUploadLimitInput] = useState(
() => settings.torrentOverallUploadLimit
);
const torrentMaxOpenFilesCommitRef = useRef(0);
const torrentOverallUploadLimitCommitRef = useRef(0);
useEffect(() => {
setPerServerConnectionsInput(String(settings.perServerConnections));
@@ -344,6 +349,10 @@ const engineRunId = useRef(0);
setTorrentMaxOpenFilesInput(String(settings.torrentMaxOpenFiles));
}, [settings.torrentMaxOpenFiles]);
useEffect(() => {
setTorrentOverallUploadLimitInput(settings.torrentOverallUploadLimit);
}, [settings.torrentOverallUploadLimit]);
// Local state for adding site login
const [loginPattern, setLoginPattern] = useState('');
const [loginUser, setLoginUser] = useState('');
@@ -375,6 +384,32 @@ const engineRunId = useRef(0);
});
});
};
const commitTorrentOverallUploadLimit = (raw: string) => {
const trimmed = raw.trim();
const normalized = trimmed ? (normalizeSpeedLimitForBackend(trimmed) ?? '') : '';
if (trimmed && !normalized) {
setTorrentOverallUploadLimitInput(settings.torrentOverallUploadLimit);
addToast({
message: t($ => $.settings.network.torrentOverallUploadLimitInvalid),
variant: 'error',
isActionable: true
});
return;
}
const requestId = ++torrentOverallUploadLimitCommitRef.current;
setTorrentOverallUploadLimitInput(normalized);
void settings.setTorrentOverallUploadLimit(normalized).catch(error => {
if (requestId !== torrentOverallUploadLimitCommitRef.current) return;
setTorrentOverallUploadLimitInput(settings.torrentOverallUploadLimit);
addToast({
message: t($ => $.settings.network.torrentOverallUploadLimitUpdateFailed, {
detail: error instanceof Error ? error.message : String(error)
}),
variant: 'error',
isActionable: true
});
});
};
const [isCheckingForUpdates, setIsCheckingForUpdates] = useState(false);
const [manualUpdateStatus, setManualUpdateStatus] = useState<ManualUpdateStatus>({ type: 'idle' });
@@ -1395,6 +1430,21 @@ runEngineChecks(false);
aria-label={t($ => $.settings.network.torrentMaxOpenFiles)}
/>
</div>
<div className="mac-settings-row settings-network-row">
<div className="settings-row-label">
<span>{t($ => $.settings.network.torrentOverallUploadLimit)}</span>
<small>{t($ => $.settings.network.torrentOverallUploadLimitDescription)}</small>
</div>
<input
type="text"
value={torrentOverallUploadLimitInput}
onChange={(event) => setTorrentOverallUploadLimitInput(event.target.value)}
onBlur={(event) => commitTorrentOverallUploadLimit(event.target.value)}
placeholder="1M"
className="app-control settings-network-input text-center"
aria-label={t($ => $.settings.network.torrentOverallUploadLimit)}
/>
</div>
</div>
<h2 className="settings-section-title">{t($ => $.settings.network.identity)}</h2>