Made changes for Desktop app to work
This commit is contained in:
parent
fe04e17d63
commit
28c2db2a37
15 changed files with 74 additions and 38 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -1313,6 +1313,7 @@ name = "librqbit-core"
|
|||
version = "3.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"directories",
|
||||
"hex 0.4.3",
|
||||
"itertools 0.12.0",
|
||||
"librqbit-bencode",
|
||||
|
|
@ -1335,7 +1336,6 @@ dependencies = [
|
|||
"backoff",
|
||||
"chrono",
|
||||
"dashmap",
|
||||
"directories",
|
||||
"futures",
|
||||
"hex 0.4.3",
|
||||
"indexmap 2.1.0",
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ backoff = "0.4.0"
|
|||
futures = "0.3"
|
||||
rand = "0.8"
|
||||
indexmap = "2"
|
||||
directories = "5"
|
||||
dashmap = {version = "5.5.3", features = ["serde"]}
|
||||
|
||||
clone_to_owned = {path="../clone_to_owned", package="librqbit-clone-to-owned", version = "2.2.1"}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
// TODO: this now stores only the routing table, but we also need AT LEAST the same socket address...
|
||||
|
||||
use librqbit_core::directories::get_configuration_directory;
|
||||
use librqbit_core::spawn_utils::spawn;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fs::OpenOptions;
|
||||
|
|
@ -72,8 +73,7 @@ impl PersistentDht {
|
|||
let config_filename = match config.config_filename.take() {
|
||||
Some(config_filename) => config_filename,
|
||||
None => {
|
||||
let dirs = directories::ProjectDirs::from("com", "rqbit", "dht")
|
||||
.context("cannot determine project directory for com.rqbit.dht")?;
|
||||
let dirs = get_configuration_directory("dht")?;
|
||||
let path = dirs.cache_dir().join("dht.json");
|
||||
info!("will store DHT routing table to {:?} periodically", &path);
|
||||
path
|
||||
|
|
|
|||
|
|
@ -143,8 +143,10 @@ impl Api {
|
|||
info,
|
||||
only_files,
|
||||
seen_peers,
|
||||
output_folder,
|
||||
}) => ApiAddTorrentResponse {
|
||||
id: None,
|
||||
output_folder: output_folder.to_string_lossy().into_owned(),
|
||||
seen_peers: Some(seen_peers),
|
||||
details: make_torrent_details(&info_hash, &info, only_files.as_deref())
|
||||
.context("error making torrent details")?,
|
||||
|
|
@ -159,6 +161,7 @@ impl Api {
|
|||
ApiAddTorrentResponse {
|
||||
id: Some(id),
|
||||
details,
|
||||
output_folder: handle.info().out_dir.to_string_lossy().into_owned(),
|
||||
seen_peers: None,
|
||||
}
|
||||
}
|
||||
|
|
@ -227,6 +230,7 @@ pub struct TorrentDetailsResponse {
|
|||
pub struct ApiAddTorrentResponse {
|
||||
pub id: Option<usize>,
|
||||
pub details: TorrentDetailsResponse,
|
||||
pub output_folder: String,
|
||||
pub seen_peers: Option<Vec<SocketAddr>>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ use bencode::{bencode_serialize_to_writer, BencodeDeserializer};
|
|||
use buffers::ByteString;
|
||||
use dht::{Dht, DhtBuilder, Id20, PersistentDht, PersistentDhtConfig, RequestPeersStream};
|
||||
use librqbit_core::{
|
||||
directories::get_configuration_directory,
|
||||
magnet::Magnet,
|
||||
peer_id::generate_peer_id,
|
||||
torrent_metainfo::{torrent_from_bytes, TorrentMetaV1Info, TorrentMetaV1Owned},
|
||||
|
|
@ -66,7 +67,7 @@ impl SessionDatabase {
|
|||
|
||||
fn serialize(&self) -> SerializedSessionDatabase {
|
||||
SerializedSessionDatabase {
|
||||
torrents_v2: self
|
||||
torrents: self
|
||||
.torrents
|
||||
.iter()
|
||||
.map(|(id, torrent)| {
|
||||
|
|
@ -135,7 +136,7 @@ where
|
|||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct SerializedSessionDatabase {
|
||||
torrents_v2: HashMap<usize, SerializedTorrent>,
|
||||
torrents: HashMap<usize, SerializedTorrent>,
|
||||
}
|
||||
|
||||
pub struct Session {
|
||||
|
|
@ -208,9 +209,11 @@ pub struct ListOnlyResponse {
|
|||
pub info_hash: Id20,
|
||||
pub info: TorrentMetaV1Info<ByteString>,
|
||||
pub only_files: Option<Vec<usize>>,
|
||||
pub output_folder: PathBuf,
|
||||
pub seen_peers: Vec<SocketAddr>,
|
||||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum AddTorrentResponse {
|
||||
AlreadyManaged(TorrentId, ManagedTorrentHandle),
|
||||
ListOnly(ListOnlyResponse),
|
||||
|
|
@ -276,7 +279,6 @@ pub struct SessionOptions {
|
|||
pub disable_dht: bool,
|
||||
pub disable_dht_persistence: bool,
|
||||
pub persistence: bool,
|
||||
// Will default to output_folder/.rqbit-session.json
|
||||
pub persistence_filename: Option<PathBuf>,
|
||||
pub dht_config: Option<PersistentDhtConfig>,
|
||||
pub peer_id: Option<Id20>,
|
||||
|
|
@ -308,9 +310,12 @@ impl Session {
|
|||
Some(dht)
|
||||
};
|
||||
let peer_opts = opts.peer_opts.unwrap_or_default();
|
||||
let persistence_filename = opts
|
||||
.persistence_filename
|
||||
.unwrap_or_else(|| output_folder.join(".rqbit-session.json"));
|
||||
let persistence_filename = match opts.persistence_filename {
|
||||
Some(filename) => filename,
|
||||
None => get_configuration_directory("session")?
|
||||
.data_dir()
|
||||
.join("session.json"),
|
||||
};
|
||||
let session = Arc::new(Self {
|
||||
persistence_filename,
|
||||
peer_id,
|
||||
|
|
@ -322,6 +327,10 @@ impl Session {
|
|||
});
|
||||
|
||||
if opts.persistence {
|
||||
info!(
|
||||
"will use {:?} for session persistence",
|
||||
session.persistence_filename
|
||||
);
|
||||
if let Some(parent) = session.persistence_filename.parent() {
|
||||
std::fs::create_dir_all(parent).with_context(|| {
|
||||
format!("couldn't create directory {:?} for session storage", parent)
|
||||
|
|
@ -391,7 +400,7 @@ impl Session {
|
|||
let db: SerializedSessionDatabase =
|
||||
serde_json::from_reader(&mut rdr).context("error deserializing session database")?;
|
||||
let mut futures = Vec::new();
|
||||
for (id, storrent) in db.torrents_v2.into_iter() {
|
||||
for (id, storrent) in db.torrents.into_iter() {
|
||||
let trackers: Vec<ByteString> = storrent
|
||||
.trackers
|
||||
.into_iter()
|
||||
|
|
@ -646,15 +655,6 @@ impl Session {
|
|||
|
||||
let only_files = get_only_files(opts.only_files, opts.only_files_regex, opts.list_only)?;
|
||||
|
||||
if opts.list_only {
|
||||
return Ok(AddTorrentResponse::ListOnly(ListOnlyResponse {
|
||||
info_hash,
|
||||
info,
|
||||
only_files,
|
||||
seen_peers: initial_peers,
|
||||
}));
|
||||
}
|
||||
|
||||
let sub_folder = opts.sub_folder.map(PathBuf::from).unwrap_or_default();
|
||||
let output_folder = opts
|
||||
.output_folder
|
||||
|
|
@ -662,6 +662,16 @@ impl Session {
|
|||
.unwrap_or_else(|| self.output_folder.clone())
|
||||
.join(sub_folder);
|
||||
|
||||
if opts.list_only {
|
||||
return Ok(AddTorrentResponse::ListOnly(ListOnlyResponse {
|
||||
info_hash,
|
||||
info,
|
||||
only_files,
|
||||
output_folder,
|
||||
seen_peers: initial_peers,
|
||||
}));
|
||||
}
|
||||
|
||||
let mut builder = ManagedTorrentBuilder::new(info, info_hash, output_folder.clone());
|
||||
builder
|
||||
.overwrite(opts.overwrite)
|
||||
|
|
|
|||
BIN
crates/librqbit/webui/assets/logo.png
Normal file
BIN
crates/librqbit/webui/assets/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 154 KiB |
16
crates/librqbit/webui/dist/assets/index.js
vendored
16
crates/librqbit/webui/dist/assets/index.js
vendored
File diff suppressed because one or more lines are too long
2
crates/librqbit/webui/dist/manifest.json
vendored
2
crates/librqbit/webui/dist/manifest.json
vendored
|
|
@ -4,7 +4,7 @@
|
|||
"src": "assets/logo.svg"
|
||||
},
|
||||
"index.html": {
|
||||
"file": "assets/index-386e9e08.js",
|
||||
"file": "assets/index-3e661b92.js",
|
||||
"isEntry": true,
|
||||
"src": "index.html"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ export interface TorrentDetails {
|
|||
export interface AddTorrentResponse {
|
||||
id: number | null;
|
||||
details: TorrentDetails;
|
||||
output_folder: string,
|
||||
seen_peers?: Array<string>;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,6 +72,9 @@ export const API: RqbitAPI = {
|
|||
if (opts?.initial_peers) {
|
||||
url += `&initial_peers=${opts.initial_peers.join(',')}`;
|
||||
}
|
||||
if (opts?.output_folder) {
|
||||
url += `&output_folder=${opts.output_folder}`;
|
||||
}
|
||||
if (typeof data === 'string') {
|
||||
url += '&is_url=true';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { API } from "./http-api";
|
|||
ReactDOM.createRoot(document.getElementById('app') as HTMLInputElement).render(
|
||||
<StrictMode>
|
||||
<APIContext.Provider value={API}>
|
||||
<RqbitWebUI />
|
||||
<RqbitWebUI title="rqbit web UI - version 4.0.0-beta.3" />
|
||||
</APIContext.Provider>
|
||||
</StrictMode>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -349,7 +349,7 @@ const TorrentsList = (props: { torrents: Array<TorrentId> | null, loading: boole
|
|||
</>;
|
||||
};
|
||||
|
||||
export const RqbitWebUI = () => {
|
||||
export const RqbitWebUI = (props: { title: string }) => {
|
||||
const [closeableError, setCloseableError] = useState<Error | null>(null);
|
||||
const [otherError, setOtherError] = useState<Error | null>(null);
|
||||
|
||||
|
|
@ -382,7 +382,7 @@ export const RqbitWebUI = () => {
|
|||
|
||||
return <AppContext.Provider value={context}>
|
||||
<div className='text-center'>
|
||||
<h1 className="mt-3 mb-4">rqbit web 4.0.0-beta.0</h1>
|
||||
<h1 className="mt-3 mb-4">{props.title}</h1>
|
||||
<RootContent
|
||||
closeableError={closeableError}
|
||||
otherError={otherError}
|
||||
|
|
@ -591,11 +591,14 @@ const FileSelectionModal = (props: {
|
|||
const [uploading, setUploading] = useState(false);
|
||||
const [uploadError, setUploadError] = useState<Error | null>(null);
|
||||
const [unpopularTorrent, setUnpopularTorrent] = useState(false);
|
||||
const [outputFolder, setOutputFolder] = useState<string>('');
|
||||
const ctx = useContext(AppContext);
|
||||
const API = useContext(APIContext);
|
||||
|
||||
useEffect(() => {
|
||||
console.log(listTorrentResponse);
|
||||
setSelectedFiles(listTorrentResponse ? listTorrentResponse.details.files.map((_, id) => id) : []);
|
||||
setOutputFolder(listTorrentResponse?.output_folder || '');
|
||||
}, [listTorrentResponse]);
|
||||
|
||||
const clear = () => {
|
||||
|
|
@ -623,6 +626,7 @@ const FileSelectionModal = (props: {
|
|||
overwrite: true,
|
||||
only_files: selectedFiles,
|
||||
initial_peers: initialPeers,
|
||||
output_folder: outputFolder,
|
||||
};
|
||||
if (unpopularTorrent) {
|
||||
opts.peer_opts = {
|
||||
|
|
@ -647,7 +651,7 @@ const FileSelectionModal = (props: {
|
|||
return <ErrorComponent error={listTorrentError}></ErrorComponent>;
|
||||
} else if (listTorrentResponse) {
|
||||
return <Form>
|
||||
<fieldset className='mb-5'>
|
||||
<fieldset className='mb-4'>
|
||||
<legend>Pick the files to download</legend>
|
||||
{listTorrentResponse.details.files.map((file, index) => (
|
||||
<Form.Group key={index} controlId={`check-${index}`}>
|
||||
|
|
@ -661,9 +665,16 @@ const FileSelectionModal = (props: {
|
|||
))}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Other options</legend>
|
||||
|
||||
<Form.Group controlId='unpopular-torrent'>
|
||||
<legend>Options</legend>
|
||||
<Form.Group controlId='output-folder' className="mb-3">
|
||||
<Form.Label>Output folder</Form.Label>
|
||||
<Form.Control
|
||||
type="text"
|
||||
value={outputFolder}
|
||||
onChange={(e) => setOutputFolder(e.target.value)}
|
||||
/>
|
||||
</Form.Group>
|
||||
<Form.Group controlId='unpopular-torrent' className="mb-3">
|
||||
<Form.Check
|
||||
type="checkbox"
|
||||
label="Increase timeouts"
|
||||
|
|
@ -673,7 +684,7 @@ const FileSelectionModal = (props: {
|
|||
<small id="emailHelp" className="form-text text-muted">This might be useful for unpopular torrents with few peers. It will slow down fast torrents though.</small>
|
||||
</Form.Group>
|
||||
</fieldset>
|
||||
</Form >
|
||||
</Form>
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ buffers = {path="../buffers", package="librqbit-buffers", version = "2.2.1"}
|
|||
bencode = {path = "../bencode", default-features=false, package="librqbit-bencode", version="2.2.1"}
|
||||
clone_to_owned = {path="../clone_to_owned", package="librqbit-clone-to-owned", version = "2.2.1"}
|
||||
itertools = "0.12"
|
||||
directories = "5"
|
||||
|
||||
[dev-dependencies]
|
||||
serde_json = "1"
|
||||
serde_json = "1"
|
||||
|
|
|
|||
6
crates/librqbit_core/src/directories.rs
Normal file
6
crates/librqbit_core/src/directories.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
use anyhow::Context;
|
||||
|
||||
pub fn get_configuration_directory(application: &str) -> anyhow::Result<directories::ProjectDirs> {
|
||||
directories::ProjectDirs::from("com", "rqbit", application)
|
||||
.with_context(|| format!("cannot determine project directory for com.rqbit.{application}"))
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
pub mod constants;
|
||||
pub mod directories;
|
||||
pub mod id20;
|
||||
pub mod lengths;
|
||||
pub mod magnet;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue