Update desktop app to support new persistence config

This commit is contained in:
Igor Katson 2024-08-15 11:39:12 +01:00
parent d77d96bd48
commit 275b3b0185
No known key found for this signature in database
GPG key ID: B4EC22B66D61A3F5
6 changed files with 68 additions and 22 deletions

View file

@ -334,6 +334,13 @@ pub enum SessionPersistenceConfig {
Json { folder: Option<PathBuf> }, Json { folder: Option<PathBuf> },
} }
impl SessionPersistenceConfig {
pub fn default_json_persistence_folder() -> anyhow::Result<PathBuf> {
let dir = get_configuration_directory("session")?;
Ok(dir.data_dir().to_owned())
}
}
#[derive(Default)] #[derive(Default)]
pub struct SessionOptions { pub struct SessionOptions {
/// Turn on to disable DHT. /// Turn on to disable DHT.
@ -475,16 +482,11 @@ impl Session {
async fn persistence_factory( async fn persistence_factory(
opts: &SessionOptions, opts: &SessionOptions,
) -> anyhow::Result<Option<BoxSessionPersistenceStore>> { ) -> anyhow::Result<Option<BoxSessionPersistenceStore>> {
pub fn default_persistence_folder() -> anyhow::Result<PathBuf> {
let dir = get_configuration_directory("session")?;
Ok(dir.data_dir().to_owned())
}
match &opts.persistence { match &opts.persistence {
Some(SessionPersistenceConfig::Json { folder }) => { Some(SessionPersistenceConfig::Json { folder }) => {
let folder = match folder.as_ref() { let folder = match folder.as_ref() {
Some(f) => f.clone(), Some(f) => f.clone(),
None => default_persistence_folder()?, None => SessionPersistenceConfig::default_json_persistence_folder()?,
}; };
Ok(Some(Box::new( Ok(Some(Box::new(

View file

@ -1847,6 +1847,7 @@ version = "6.0.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-stream", "async-stream",
"async-trait",
"axum", "axum",
"backoff", "backoff",
"base64 0.21.7", "base64 0.21.7",
@ -1897,6 +1898,7 @@ name = "librqbit-bencode"
version = "2.2.3" version = "2.2.3"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes",
"librqbit-buffers", "librqbit-buffers",
"librqbit-clone-to-owned", "librqbit-clone-to-owned",
"librqbit-sha1-wrapper", "librqbit-sha1-wrapper",
@ -1907,6 +1909,7 @@ dependencies = [
name = "librqbit-buffers" name = "librqbit-buffers"
version = "3.0.1" version = "3.0.1"
dependencies = [ dependencies = [
"bytes",
"librqbit-clone-to-owned", "librqbit-clone-to-owned",
"serde", "serde",
] ]
@ -1914,12 +1917,16 @@ dependencies = [
[[package]] [[package]]
name = "librqbit-clone-to-owned" name = "librqbit-clone-to-owned"
version = "2.2.1" version = "2.2.1"
dependencies = [
"bytes",
]
[[package]] [[package]]
name = "librqbit-core" name = "librqbit-core"
version = "3.9.0" version = "3.9.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes",
"data-encoding", "data-encoding",
"directories", "directories",
"hex 0.4.3", "hex 0.4.3",
@ -1942,6 +1949,7 @@ version = "5.0.4"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"backoff", "backoff",
"bytes",
"chrono", "chrono",
"dashmap", "dashmap",
"futures", "futures",
@ -1969,6 +1977,7 @@ dependencies = [
"bincode", "bincode",
"bitvec", "bitvec",
"byteorder", "byteorder",
"bytes",
"librqbit-bencode", "librqbit-bencode",
"librqbit-buffers", "librqbit-buffers",
"librqbit-clone-to-owned", "librqbit-clone-to-owned",

View file

@ -1,10 +1,10 @@
use std::{ use std::{
net::{Ipv4Addr, SocketAddr, SocketAddrV4}, net::{Ipv4Addr, SocketAddr, SocketAddrV4},
path::PathBuf, path::{Path, PathBuf},
time::Duration, time::Duration,
}; };
use librqbit::{dht::PersistentDht, Session}; use librqbit::dht::PersistentDht;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_with::serde_as; use serde_with::serde_as;
@ -49,14 +49,35 @@ impl Default for RqbitDesktopConfigTcpListen {
#[serde(default)] #[serde(default)]
pub struct RqbitDesktopConfigPersistence { pub struct RqbitDesktopConfigPersistence {
pub disable: bool, pub disable: bool,
#[serde(default)]
pub folder: PathBuf,
/// Deprecated, but keeping for backwards compat for serialized / deserialized config.
#[serde(default)]
pub filename: PathBuf, pub filename: PathBuf,
} }
impl RqbitDesktopConfigPersistence {
pub(crate) fn fix_backwards_compat(&mut self) {
if self.folder != Path::new("") {
return;
}
if self.filename != Path::new("") {
if let Some(parent) = self.filename.parent() {
self.folder = parent.to_owned();
}
}
}
}
impl Default for RqbitDesktopConfigPersistence { impl Default for RqbitDesktopConfigPersistence {
fn default() -> Self { fn default() -> Self {
let folder = librqbit::SessionPersistenceConfig::default_json_persistence_folder().unwrap();
Self { Self {
disable: false, disable: false,
filename: Session::default_persistence_filename().unwrap(), folder,
filename: PathBuf::new(),
} }
} }
} }

View file

@ -21,6 +21,7 @@ use librqbit::{
dht::PersistentDhtConfig, dht::PersistentDhtConfig,
tracing_subscriber_config_utils::{init_logging, InitLoggingOptions, InitLoggingResult}, tracing_subscriber_config_utils::{init_logging, InitLoggingOptions, InitLoggingResult},
AddTorrent, AddTorrentOptions, Api, ApiError, PeerConnectionOptions, Session, SessionOptions, AddTorrent, AddTorrentOptions, Api, ApiError, PeerConnectionOptions, Session, SessionOptions,
SessionPersistenceConfig,
}; };
use parking_lot::RwLock; use parking_lot::RwLock;
use serde::Serialize; use serde::Serialize;
@ -42,7 +43,9 @@ struct State {
fn read_config(path: &str) -> anyhow::Result<RqbitDesktopConfig> { fn read_config(path: &str) -> anyhow::Result<RqbitDesktopConfig> {
let rdr = BufReader::new(File::open(path)?); let rdr = BufReader::new(File::open(path)?);
Ok(serde_json::from_reader(rdr)?) let mut config: RqbitDesktopConfig = serde_json::from_reader(rdr)?;
config.persistence.fix_backwards_compat();
Ok(config)
} }
fn write_config(path: &str, config: &RqbitDesktopConfig) -> anyhow::Result<()> { fn write_config(path: &str, config: &RqbitDesktopConfig) -> anyhow::Result<()> {
@ -65,6 +68,17 @@ async fn api_from_config(
init_logging: &InitLoggingResult, init_logging: &InitLoggingResult,
config: &RqbitDesktopConfig, config: &RqbitDesktopConfig,
) -> anyhow::Result<Api> { ) -> anyhow::Result<Api> {
let persistence = if config.persistence.disable {
None
} else {
Some(SessionPersistenceConfig::Json {
folder: if config.persistence.folder == Path::new("") {
None
} else {
Some(config.persistence.folder.clone())
},
})
};
let session = Session::new_with_opts( let session = Session::new_with_opts(
config.default_download_location.clone(), config.default_download_location.clone(),
SessionOptions { SessionOptions {
@ -74,8 +88,7 @@ async fn api_from_config(
config_filename: Some(config.dht.persistence_filename.clone()), config_filename: Some(config.dht.persistence_filename.clone()),
..Default::default() ..Default::default()
}), }),
persistence: !config.persistence.disable, persistence,
persistence_filename: Some(config.persistence.filename.clone()),
peer_opts: Some(PeerConnectionOptions { peer_opts: Some(PeerConnectionOptions {
connect_timeout: Some(config.peer_opts.connect_timeout), connect_timeout: Some(config.peer_opts.connect_timeout),
read_write_timeout: Some(config.peer_opts.read_write_timeout), read_write_timeout: Some(config.peer_opts.read_write_timeout),
@ -266,7 +279,7 @@ async fn torrent_action_delete(
state: tauri::State<'_, State>, state: tauri::State<'_, State>,
id: usize, id: usize,
) -> Result<EmptyJsonResponse, ApiError> { ) -> Result<EmptyJsonResponse, ApiError> {
state.api()?.api_torrent_action_delete(id) state.api()?.api_torrent_action_delete(id).await
} }
#[tauri::command] #[tauri::command]
@ -274,7 +287,7 @@ async fn torrent_action_pause(
state: tauri::State<'_, State>, state: tauri::State<'_, State>,
id: usize, id: usize,
) -> Result<EmptyJsonResponse, ApiError> { ) -> Result<EmptyJsonResponse, ApiError> {
state.api()?.api_torrent_action_pause(id) state.api()?.api_torrent_action_pause(id).await
} }
#[tauri::command] #[tauri::command]
@ -282,7 +295,7 @@ async fn torrent_action_forget(
state: tauri::State<'_, State>, state: tauri::State<'_, State>,
id: usize, id: usize,
) -> Result<EmptyJsonResponse, ApiError> { ) -> Result<EmptyJsonResponse, ApiError> {
state.api()?.api_torrent_action_forget(id) state.api()?.api_torrent_action_forget(id).await
} }
#[tauri::command] #[tauri::command]
@ -290,7 +303,7 @@ async fn torrent_action_start(
state: tauri::State<'_, State>, state: tauri::State<'_, State>,
id: usize, id: usize,
) -> Result<EmptyJsonResponse, ApiError> { ) -> Result<EmptyJsonResponse, ApiError> {
state.api()?.api_torrent_action_start(id) state.api()?.api_torrent_action_start(id).await
} }
#[tauri::command] #[tauri::command]
@ -302,6 +315,7 @@ async fn torrent_action_configure(
state state
.api()? .api()?
.api_torrent_action_update_only_files(id, &only_files.into_iter().collect()) .api_torrent_action_update_only_files(id, &only_files.into_iter().collect())
.await
} }
#[tauri::command] #[tauri::command]

View file

@ -16,7 +16,7 @@ interface RqbitDesktopConfigTcpListen {
interface RqbitDesktopConfigPersistence { interface RqbitDesktopConfigPersistence {
disable: boolean; disable: boolean;
filename: PathLike; folder: PathLike;
} }
interface RqbitDesktopConfigPeerOpts { interface RqbitDesktopConfigPeerOpts {

View file

@ -130,7 +130,7 @@ export const ConfigModal: React.FC<{
}; };
const handleToggleChange: React.ChangeEventHandler<HTMLInputElement> = ( const handleToggleChange: React.ChangeEventHandler<HTMLInputElement> = (
e, e
) => { ) => {
const name: string = e.target.name; const name: string = e.target.name;
const [mainField, subField] = name.split(".", 2); const [mainField, subField] = name.split(".", 2);
@ -166,7 +166,7 @@ export const ConfigModal: React.FC<{
text: "Error saving configuration", text: "Error saving configuration",
details: e, details: e,
}); });
}, }
); );
}; };
@ -292,10 +292,10 @@ export const ConfigModal: React.FC<{
/> />
<FormInput <FormInput
label="Persistence filename" label="Persistence folder"
name="persistence.filename" name="persistence.folder"
inputType="text" inputType="text"
value={config.persistence.filename} value={config.persistence.folder}
onChange={handleInputChange} onChange={handleInputChange}
disabled={config.persistence.disable} disabled={config.persistence.disable}
/> />