aboutsummaryrefslogtreecommitdiffstats
path: root/src/copyparty/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/copyparty/mod.rs18
1 files changed, 12 insertions, 6 deletions
diff --git a/src/copyparty/mod.rs b/src/copyparty/mod.rs
index 00bfd53..164c9f8 100644
--- a/src/copyparty/mod.rs
+++ b/src/copyparty/mod.rs
@@ -1,3 +1,5 @@
1use std::time::Duration;
2
1use reqwest::Client; 3use reqwest::Client;
2use serde::Deserialize; 4use serde::Deserialize;
3use tracing::warn; 5use tracing::warn;
@@ -5,6 +7,10 @@ use tracing::warn;
5use crate::error::Result; 7use crate::error::Result;
6use crate::lang; 8use crate::lang;
7 9
10/// Timeout for copyparty search requests; autocomplete has a 3s Discord budget,
11/// so this must be comfortably lower.
12const SEARCH_HTTP_TIMEOUT: Duration = Duration::from_secs(4);
13
8#[derive(Clone)] 14#[derive(Clone)]
9pub struct CopypartyClient { 15pub struct CopypartyClient {
10 pub base_url: String, 16 pub base_url: String,
@@ -20,13 +26,12 @@ pub fn percent_decode(s: &str) -> String {
20 let mut i = 0; 26 let mut i = 0;
21 while i < bytes.len() { 27 while i < bytes.len() {
22 let b = bytes[i]; 28 let b = bytes[i];
23 if b == b'%' && i + 2 < bytes.len() { 29 if b == b'%' && i + 2 < bytes.len()
24 if let (Some(hi), Some(lo)) = (hex_nibble(bytes[i + 1]), hex_nibble(bytes[i + 2])) { 30 && let (Some(hi), Some(lo)) = (hex_nibble(bytes[i + 1]), hex_nibble(bytes[i + 2])) {
25 buf.push(hi << 4 | lo); 31 buf.push(hi << 4 | lo);
26 i += 3; 32 i += 3;
27 continue; 33 continue;
28 } 34 }
29 }
30 if b == b'+' { 35 if b == b'+' {
31 buf.push(b' '); 36 buf.push(b' ');
32 } else { 37 } else {
@@ -56,7 +61,7 @@ pub fn html_decode(s: &str) -> String {
56 "&quot;" => buf.extend_from_slice(b"\""), 61 "&quot;" => buf.extend_from_slice(b"\""),
57 "&apos;" => buf.extend_from_slice(b"'"), 62 "&apos;" => buf.extend_from_slice(b"'"),
58 "&nbsp;" => buf.extend_from_slice(b" "), 63 "&nbsp;" => buf.extend_from_slice(b" "),
59 _ if entity.as_bytes().len() > 3 && entity.as_bytes()[1] == b'#' => { 64 _ if entity.len() > 3 && entity.as_bytes()[1] == b'#' => {
60 let (num_str, radix) = 65 let (num_str, radix) =
61 if entity.as_bytes()[2] == b'x' || entity.as_bytes()[2] == b'X' { 66 if entity.as_bytes()[2] == b'x' || entity.as_bytes()[2] == b'X' {
62 (&entity[3..entity.len() - 1], 16u32) 67 (&entity[3..entity.len() - 1], 16u32)
@@ -130,7 +135,7 @@ impl SearchHit {
130 /// Best-effort URL path for building a full download URL. 135 /// Best-effort URL path for building a full download URL.
131 /// Tries `url`, then `rp`. 136 /// Tries `url`, then `rp`.
132 pub fn url_path(&self) -> Option<&str> { 137 pub fn url_path(&self) -> Option<&str> {
133 self.url.as_deref().or_else(|| self.rp.as_deref()) 138 self.url.as_deref().or(self.rp.as_deref())
134 } 139 }
135} 140}
136 141
@@ -203,7 +208,8 @@ impl CopypartyClient {
203 let mut req = self 208 let mut req = self
204 .client 209 .client
205 .post(format!("{}/?srch", self.base_url)) 210 .post(format!("{}/?srch", self.base_url))
206 .json(&payload); 211 .json(&payload)
212 .timeout(SEARCH_HTTP_TIMEOUT);
207 if let Some(pw) = &self.password { 213 if let Some(pw) = &self.password {
208 req = req.header("PW", pw); 214 req = req.header("PW", pw);
209 } 215 }