Allow the network timeout to be customized

https://forums.ankiweb.net/t/local-sync-server-collection-exceeds-size-limit/27183/7
This commit is contained in:
Damien Elmes 2023-02-08 14:32:37 +10:00
parent ed54cf71ec
commit f616bea580
9 changed files with 67 additions and 2 deletions

View file

@ -67,6 +67,7 @@ preferences-note = Note
preferences-scheduler = Scheduler preferences-scheduler = Scheduler
preferences-user-interface = User Interface preferences-user-interface = User Interface
preferences-import-export = Import/Export preferences-import-export = Import/Export
preferences-network-timeout = Network timeout
## NO NEED TO TRANSLATE. This text is no longer used by Anki, and will be removed in the future. ## NO NEED TO TRANSLATE. This text is no longer used by Anki, and will be removed in the future.

View file

@ -24,6 +24,7 @@ service SyncService {
message SyncAuth { message SyncAuth {
string hkey = 1; string hkey = 1;
optional string endpoint = 2; optional string endpoint = 2;
optional uint32 io_timeout_secs = 3;
} }
message SyncLoginRequest { message SyncLoginRequest {

View file

@ -712,6 +712,47 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>preferences_network_timeout</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="network_timeout">
<property name="minimum">
<number>30</number>
</property>
<property name="maximum">
<number>99999</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_8">
<property name="text">
<string>scheduling_seconds</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_3"> <layout class="QHBoxLayout" name="horizontalLayout_3">
<item> <item>
@ -1087,6 +1128,7 @@
<tabstop>syncOnProgramOpen</tabstop> <tabstop>syncOnProgramOpen</tabstop>
<tabstop>autoSyncMedia</tabstop> <tabstop>autoSyncMedia</tabstop>
<tabstop>fullSync</tabstop> <tabstop>fullSync</tabstop>
<tabstop>network_timeout</tabstop>
<tabstop>media_log</tabstop> <tabstop>media_log</tabstop>
<tabstop>syncDeauth</tabstop> <tabstop>syncDeauth</tabstop>
<tabstop>custom_sync_url</tabstop> <tabstop>custom_sync_url</tabstop>

View file

@ -183,6 +183,7 @@ class Preferences(QDialog):
qconnect(self.form.syncDeauth.clicked, self.sync_logout) qconnect(self.form.syncDeauth.clicked, self.sync_logout)
self.form.syncDeauth.setText(tr.sync_log_out_button()) self.form.syncDeauth.setText(tr.sync_log_out_button())
self.form.custom_sync_url.setText(self.mw.pm.custom_sync_url()) self.form.custom_sync_url.setText(self.mw.pm.custom_sync_url())
self.form.network_timeout.setValue(self.mw.pm.network_timeout())
def on_media_log(self) -> None: def on_media_log(self) -> None:
self.mw.media_syncer.show_sync_log() self.mw.media_syncer.show_sync_log()
@ -211,6 +212,7 @@ class Preferences(QDialog):
if self.form.fullSync.isChecked(): if self.form.fullSync.isChecked():
self.mw.col.mod_schema(check=False) self.mw.col.mod_schema(check=False)
self.mw.pm.set_custom_sync_url(self.form.custom_sync_url.text()) self.mw.pm.set_custom_sync_url(self.form.custom_sync_url.text())
self.mw.pm.set_network_timeout(self.form.network_timeout.value())
# Global preferences # Global preferences
###################################################################### ######################################################################

View file

@ -642,7 +642,11 @@ create table if not exists profiles
def sync_auth(self) -> SyncAuth | None: def sync_auth(self) -> SyncAuth | None:
if not (hkey := self.profile.get("syncKey")): if not (hkey := self.profile.get("syncKey")):
return None return None
return SyncAuth(hkey=hkey, endpoint=self.sync_endpoint()) return SyncAuth(
hkey=hkey,
endpoint=self.sync_endpoint(),
io_timeout_secs=self.network_timeout(),
)
def clear_sync_auth(self) -> None: def clear_sync_auth(self) -> None:
self.set_sync_key(None) self.set_sync_key(None)
@ -680,3 +684,9 @@ create table if not exists profiles
def set_show_browser_table_tooltips(self, val: bool) -> None: def set_show_browser_table_tooltips(self, val: bool) -> None:
self.profile["browserTableTooltips"] = val self.profile["browserTableTooltips"] = val
def set_network_timeout(self, timeout_secs: int) -> None:
self.profile["networkTimeout"] = timeout_secs
def network_timeout(self) -> int:
return self.profile.get("networkTimeout") or 30

View file

@ -89,6 +89,7 @@ impl TryFrom<pb::sync::SyncAuth> for SyncAuth {
.or_invalid("Invalid sync server specified. Please check the preferences.") .or_invalid("Invalid sync server specified. Please check the preferences.")
}) })
.transpose()?, .transpose()?,
io_timeout_secs: value.io_timeout_secs,
}) })
} }
} }
@ -236,6 +237,7 @@ impl Backend {
ret.map(|a| pb::sync::SyncAuth { ret.map(|a| pb::sync::SyncAuth {
hkey: a.hkey, hkey: a.hkey,
endpoint: None, endpoint: None,
io_timeout_secs: None,
}) })
} }

View file

@ -98,6 +98,7 @@ where
let auth = SyncAuth { let auth = SyncAuth {
hkey: AUTH.host_key.clone(), hkey: AUTH.host_key.clone(),
endpoint: Some(endpoint), endpoint: Some(endpoint),
io_timeout_secs: None,
}; };
let client = HttpSyncClient::new(auth); let client = HttpSyncClient::new(auth);
op(client).await op(client).await

View file

@ -32,11 +32,13 @@ pub struct HttpSyncClient {
session_key: String, session_key: String,
client: Client, client: Client,
pub endpoint: Url, pub endpoint: Url,
pub io_timeout: Duration,
full_sync_progress_fn: Mutex<Option<FullSyncProgressFn>>, full_sync_progress_fn: Mutex<Option<FullSyncProgressFn>>,
} }
impl HttpSyncClient { impl HttpSyncClient {
pub fn new(auth: SyncAuth) -> HttpSyncClient { pub fn new(auth: SyncAuth) -> HttpSyncClient {
let io_timeout = Duration::from_secs(auth.io_timeout_secs.unwrap_or(30) as u64);
HttpSyncClient { HttpSyncClient {
sync_key: auth.hkey, sync_key: auth.hkey,
session_key: simple_session_id(), session_key: simple_session_id(),
@ -44,6 +46,7 @@ impl HttpSyncClient {
endpoint: auth endpoint: auth
.endpoint .endpoint
.unwrap_or_else(|| Url::try_from("https://sync.ankiweb.net/").unwrap()), .unwrap_or_else(|| Url::try_from("https://sync.ankiweb.net/").unwrap()),
io_timeout,
full_sync_progress_fn: Mutex::new(None), full_sync_progress_fn: Mutex::new(None),
} }
} }
@ -56,6 +59,7 @@ impl HttpSyncClient {
client: self.client.clone(), client: self.client.clone(),
endpoint: self.endpoint.clone(), endpoint: self.endpoint.clone(),
full_sync_progress_fn: Mutex::new(None), full_sync_progress_fn: Mutex::new(None),
io_timeout: self.io_timeout,
} }
} }
@ -86,7 +90,7 @@ impl HttpSyncClient {
.post(url) .post(url)
.header(&SYNC_HEADER_NAME, serde_json::to_string(&header).unwrap()); .header(&SYNC_HEADER_NAME, serde_json::to_string(&header).unwrap());
io_monitor io_monitor
.zstd_request_with_timeout(request, data, Duration::from_secs(30)) .zstd_request_with_timeout(request, data, self.io_timeout)
.await .await
.map(SyncResponse::from_vec) .map(SyncResponse::from_vec)
} }

View file

@ -14,6 +14,7 @@ use crate::sync::request::IntoSyncRequest;
pub struct SyncAuth { pub struct SyncAuth {
pub hkey: String, pub hkey: String,
pub endpoint: Option<Url>, pub endpoint: Option<Url>,
pub io_timeout_secs: Option<u32>,
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@ -53,5 +54,6 @@ pub async fn sync_login<S: Into<String>>(
Ok(SyncAuth { Ok(SyncAuth {
hkey: resp.key, hkey: resp.key,
endpoint: None, endpoint: None,
io_timeout_secs: None,
}) })
} }