Add a button to increase peer timeouts

This commit is contained in:
Igor Katson 2023-11-30 16:05:48 +00:00
parent dc50de31dc
commit a0feee27a6
No known key found for this signature in database
GPG key ID: B4EC22B66D61A3F5
6 changed files with 61 additions and 28 deletions

View file

@ -12,12 +12,14 @@ use librqbit_core::torrent_metainfo::TorrentMetaV1Info;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::net::SocketAddr; use std::net::SocketAddr;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration;
use tokio::sync::mpsc::UnboundedSender; use tokio::sync::mpsc::UnboundedSender;
use tracing::{info, warn}; use tracing::{info, warn};
use axum::Router; use axum::Router;
use crate::http_api_error::{ApiError, ApiErrorExt}; use crate::http_api_error::{ApiError, ApiErrorExt};
use crate::peer_connection::PeerConnectionOptions;
use crate::session::{ use crate::session::{
AddTorrent, AddTorrentOptions, AddTorrentResponse, ListOnlyResponse, Session, TorrentId, AddTorrent, AddTorrentOptions, AddTorrentResponse, ListOnlyResponse, Session, TorrentId,
}; };
@ -322,13 +324,15 @@ impl<'de> Deserialize<'de> for OnlyFiles {
} }
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Default)]
pub struct TorrentAddQueryParams { pub struct TorrentAddQueryParams {
pub overwrite: Option<bool>, pub overwrite: Option<bool>,
pub output_folder: Option<String>, pub output_folder: Option<String>,
pub sub_folder: Option<String>, pub sub_folder: Option<String>,
pub only_files_regex: Option<String>, pub only_files_regex: Option<String>,
pub only_files: Option<OnlyFiles>, pub only_files: Option<OnlyFiles>,
pub peer_connect_timeout: Option<u64>,
pub peer_read_write_timeout: Option<u64>,
pub list_only: Option<bool>, pub list_only: Option<bool>,
} }
@ -341,6 +345,11 @@ impl TorrentAddQueryParams {
output_folder: self.output_folder, output_folder: self.output_folder,
sub_folder: self.sub_folder, sub_folder: self.sub_folder,
list_only: self.list_only.unwrap_or(false), list_only: self.list_only.unwrap_or(false),
peer_opts: Some(PeerConnectionOptions {
connect_timeout: self.peer_connect_timeout.map(Duration::from_secs),
read_write_timeout: self.peer_read_write_timeout.map(Duration::from_secs),
..Default::default()
}),
..Default::default() ..Default::default()
} }
} }

View file

@ -91,6 +91,7 @@ impl HttpApiClient {
output_folder: opts.output_folder, output_folder: opts.output_folder,
sub_folder: opts.sub_folder, sub_folder: opts.sub_folder,
list_only: Some(opts.list_only), list_only: Some(opts.list_only),
..Default::default()
}; };
let qs = serde_urlencoded::to_string(&params).unwrap(); let qs = serde_urlencoded::to_string(&params).unwrap();
let url = format!("{}torrents?{}", &self.base_url, qs); let url = format!("{}torrents?{}", &self.base_url, qs);

File diff suppressed because one or more lines are too long

View file

@ -4,7 +4,7 @@
"src": "assets/logo.svg" "src": "assets/logo.svg"
}, },
"index.html": { "index.html": {
"file": "assets/index-1c38bddb.js", "file": "assets/index-b3c336f4.js",
"isEntry": true, "isEntry": true,
"src": "index.html" "src": "index.html"
} }

View file

@ -147,7 +147,7 @@ export const API = {
}, },
uploadTorrent: (data: string | File, opts?: { uploadTorrent: (data: string | File, opts?: {
listOnly?: boolean, selectedFiles?: Array<number> listOnly?: boolean, selectedFiles?: Array<number>, unpopularTorrent?: boolean,
}): Promise<AddTorrentResponse> => { }): Promise<AddTorrentResponse> => {
opts = opts || {}; opts = opts || {};
let url = '/torrents?&overwrite=true'; let url = '/torrents?&overwrite=true';
@ -157,6 +157,9 @@ export const API = {
if (opts.selectedFiles != null) { if (opts.selectedFiles != null) {
url += `&only_files=${opts.selectedFiles.join(',')}`; url += `&only_files=${opts.selectedFiles.join(',')}`;
} }
if (opts.unpopularTorrent) {
url += '&peer_connect_timeout=20&peer_read_write_timeout=60';
}
return makeRequest('POST', url, data) return makeRequest('POST', url, data)
}, },

View file

@ -438,7 +438,7 @@ const MagnetInput = () => {
}; };
return ( return (
<UploadButton variant='primary' buttonText="Add Torrent from Magnet Link" onClick={onClick} data={magnet} resetData={() => setMagnet(null)} /> <UploadButton variant='primary' buttonText="Add Torrent from Magnet / URL" onClick={onClick} data={magnet} resetData={() => setMagnet(null)} />
); );
}; };
@ -481,6 +481,7 @@ const FileSelectionModal = (props: {
const [selectedFiles, setSelectedFiles] = useState([]); const [selectedFiles, setSelectedFiles] = useState([]);
const [uploading, setUploading] = useState(false); const [uploading, setUploading] = useState(false);
const [uploadError, setUploadError] = useState<Error>(null); const [uploadError, setUploadError] = useState<Error>(null);
const [unpopularTorrent, setUnpopularTorrent] = useState(false);
const ctx = useContext(AppContext); const ctx = useContext(AppContext);
useEffect(() => { useEffect(() => {
@ -504,7 +505,7 @@ const FileSelectionModal = (props: {
const handleUpload = async () => { const handleUpload = async () => {
setUploading(true); setUploading(true);
API.uploadTorrent(data, { selectedFiles }).then( API.uploadTorrent(data, { selectedFiles, unpopularTorrent }).then(
() => { () => {
onHide(); onHide();
ctx.refreshTorrents(); ctx.refreshTorrents();
@ -518,24 +519,43 @@ const FileSelectionModal = (props: {
return ( return (
<Modal show={show} onHide={clear} size='lg'> <Modal show={show} onHide={clear} size='lg'>
<Modal.Header closeButton> <Modal.Header closeButton>
{!!fileListError || <Modal.Title>Select Files</Modal.Title>} {!!fileListError || <Modal.Title>Add torrent</Modal.Title>}
</Modal.Header> </Modal.Header>
<Modal.Body> <Modal.Body>
{fileListLoading ? <Spinner /> <Form>
: fileListError ? <ErrorComponent error={fileListError}></ErrorComponent> : <fieldset className='mb-5'>
<Form> <legend>Pick the files to download</legend>
{fileList.map((file, index) => ( {fileListLoading ? <Spinner />
<Form.Group key={index} controlId={`check-${index}`}> : fileListError ? <ErrorComponent error={fileListError}></ErrorComponent> :
<Form.Check <>
type="checkbox" {fileList.map((file, index) => (
label={`${file.name} (${formatBytes(file.length)})`} <Form.Group key={index} controlId={`check-${index}`}>
checked={selectedFiles.includes(index)} <Form.Check
onChange={() => handleToggleFile(index)}> type="checkbox"
</Form.Check> label={`${file.name} (${formatBytes(file.length)})`}
</Form.Group> checked={selectedFiles.includes(index)}
))} onChange={() => handleToggleFile(index)}>
</Form> </Form.Check>
} </Form.Group>
))}
</>
}
</fieldset>
<fieldset>
<legend>Other options</legend>
<Form.Group controlId='unpopular-torrent'>
<Form.Check
type="checkbox"
label="Increase timeouts"
checked={unpopularTorrent}
onChange={() => setUnpopularTorrent(!unpopularTorrent)}>
</Form.Check>
<small id="emailHelp" className="form-text text-muted">This might be useful for unpopular torrents with few peers.</small>
</Form.Group>
</fieldset>
</Form>
<ErrorComponent error={uploadError} /> <ErrorComponent error={uploadError} />
</Modal.Body> </Modal.Body>
<Modal.Footer> <Modal.Footer>