Skip to content

Commit 6beec3a

Browse files
committed
refactor: [#1264] add a database method to increase the number of downloads for a torrent
1 parent 8a4dba3 commit 6beec3a

File tree

5 files changed

+100
-32
lines changed

5 files changed

+100
-32
lines changed

packages/tracker-core/src/databases/driver/mod.rs

+15
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ pub(crate) mod tests {
9999

100100
handling_torrent_persistence::it_should_save_and_load_persistent_torrents(driver);
101101
handling_torrent_persistence::it_should_load_all_persistent_torrents(driver);
102+
handling_torrent_persistence::it_should_increase_the_number_of_downloads_for_a_given_torrent(driver);
102103

103104
// Authentication keys (for private trackers)
104105

@@ -177,6 +178,20 @@ pub(crate) mod tests {
177178
assert_eq!(torrents.len(), 1);
178179
assert_eq!(torrents.get(&infohash), Some(number_of_downloads).as_ref());
179180
}
181+
182+
pub fn it_should_increase_the_number_of_downloads_for_a_given_torrent(driver: &Arc<Box<dyn Database>>) {
183+
let infohash = sample_info_hash();
184+
185+
let number_of_downloads = 1;
186+
187+
driver.save_persistent_torrent(&infohash, number_of_downloads).unwrap();
188+
189+
driver.increase_number_of_downloads(&infohash).unwrap();
190+
191+
let number_of_downloads = driver.load_persistent_torrent(&infohash).unwrap().unwrap();
192+
193+
assert_eq!(number_of_downloads, 2);
194+
}
180195
}
181196

182197
mod handling_authentication_keys {

packages/tracker-core/src/databases/driver/mysql.rs

+25-13
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,31 @@ impl Database for Mysql {
143143
Ok(persistent_torrent)
144144
}
145145

146+
/// Refer to [`databases::Database::save_persistent_torrent`](crate::core::databases::Database::save_persistent_torrent).
147+
fn save_persistent_torrent(&self, info_hash: &InfoHash, completed: u32) -> Result<(), Error> {
148+
const COMMAND : &str = "INSERT INTO torrents (info_hash, completed) VALUES (:info_hash_str, :completed) ON DUPLICATE KEY UPDATE completed = VALUES(completed)";
149+
150+
let mut conn = self.pool.get().map_err(|e| (e, DRIVER))?;
151+
152+
let info_hash_str = info_hash.to_string();
153+
154+
Ok(conn.exec_drop(COMMAND, params! { info_hash_str, completed })?)
155+
}
156+
157+
/// Refer to [`databases::Database::increase_number_of_downloads`](crate::core::databases::Database::increase_number_of_downloads).
158+
fn increase_number_of_downloads(&self, info_hash: &InfoHash) -> Result<(), Error> {
159+
let mut conn = self.pool.get().map_err(|e| (e, DRIVER))?;
160+
161+
let info_hash_str = info_hash.to_string();
162+
163+
conn.exec_drop(
164+
"UPDATE torrents SET completed = completed + 1 WHERE info_hash = :info_hash_str",
165+
params! { info_hash_str },
166+
)?;
167+
168+
Ok(())
169+
}
170+
146171
/// Refer to [`databases::Database::load_keys`](crate::core::databases::Database::load_keys).
147172
fn load_keys(&self) -> Result<Vec<authentication::PeerKey>, Error> {
148173
let mut conn = self.pool.get().map_err(|e| (e, DRIVER))?;
@@ -175,19 +200,6 @@ impl Database for Mysql {
175200
Ok(info_hashes)
176201
}
177202

178-
/// Refer to [`databases::Database::save_persistent_torrent`](crate::core::databases::Database::save_persistent_torrent).
179-
fn save_persistent_torrent(&self, info_hash: &InfoHash, completed: u32) -> Result<(), Error> {
180-
const COMMAND : &str = "INSERT INTO torrents (info_hash, completed) VALUES (:info_hash_str, :completed) ON DUPLICATE KEY UPDATE completed = VALUES(completed)";
181-
182-
let mut conn = self.pool.get().map_err(|e| (e, DRIVER))?;
183-
184-
let info_hash_str = info_hash.to_string();
185-
186-
tracing::debug!("{}", info_hash_str);
187-
188-
Ok(conn.exec_drop(COMMAND, params! { info_hash_str, completed })?)
189-
}
190-
191203
/// Refer to [`databases::Database::get_info_hash_from_whitelist`](crate::core::databases::Database::get_info_hash_from_whitelist).
192204
fn get_info_hash_from_whitelist(&self, info_hash: InfoHash) -> Result<Option<InfoHash>, Error> {
193205
let mut conn = self.pool.get().map_err(|e| (e, DRIVER))?;

packages/tracker-core/src/databases/driver/sqlite.rs

+38-19
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,44 @@ impl Database for Sqlite {
141141
}))
142142
}
143143

144+
/// Refer to [`databases::Database::save_persistent_torrent`](crate::core::databases::Database::save_persistent_torrent).
145+
fn save_persistent_torrent(&self, info_hash: &InfoHash, completed: u32) -> Result<(), Error> {
146+
let conn = self.pool.get().map_err(|e| (e, DRIVER))?;
147+
148+
let insert = conn.execute(
149+
"INSERT INTO torrents (info_hash, completed) VALUES (?1, ?2) ON CONFLICT(info_hash) DO UPDATE SET completed = ?2",
150+
[info_hash.to_string(), completed.to_string()],
151+
)?;
152+
153+
if insert == 0 {
154+
Err(Error::InsertFailed {
155+
location: Location::caller(),
156+
driver: DRIVER,
157+
})
158+
} else {
159+
Ok(())
160+
}
161+
}
162+
163+
/// Refer to [`databases::Database::increase_number_of_downloads`](crate::core::databases::Database::increase_number_of_downloads).
164+
fn increase_number_of_downloads(&self, info_hash: &InfoHash) -> Result<(), Error> {
165+
let conn = self.pool.get().map_err(|e| (e, DRIVER))?;
166+
167+
let update = conn.execute(
168+
"UPDATE torrents SET completed = completed + 1 WHERE info_hash = ?",
169+
[info_hash.to_string()],
170+
)?;
171+
172+
if update == 0 {
173+
Err(Error::UpdateFailed {
174+
location: Location::caller(),
175+
driver: DRIVER,
176+
})
177+
} else {
178+
Ok(())
179+
}
180+
}
181+
144182
/// Refer to [`databases::Database::load_keys`](crate::core::databases::Database::load_keys).
145183
fn load_keys(&self) -> Result<Vec<authentication::PeerKey>, Error> {
146184
let conn = self.pool.get().map_err(|e| (e, DRIVER))?;
@@ -185,25 +223,6 @@ impl Database for Sqlite {
185223
Ok(info_hashes)
186224
}
187225

188-
/// Refer to [`databases::Database::save_persistent_torrent`](crate::core::databases::Database::save_persistent_torrent).
189-
fn save_persistent_torrent(&self, info_hash: &InfoHash, completed: u32) -> Result<(), Error> {
190-
let conn = self.pool.get().map_err(|e| (e, DRIVER))?;
191-
192-
let insert = conn.execute(
193-
"INSERT INTO torrents (info_hash, completed) VALUES (?1, ?2) ON CONFLICT(info_hash) DO UPDATE SET completed = ?2",
194-
[info_hash.to_string(), completed.to_string()],
195-
)?;
196-
197-
if insert == 0 {
198-
Err(Error::InsertFailed {
199-
location: Location::caller(),
200-
driver: DRIVER,
201-
})
202-
} else {
203-
Ok(())
204-
}
205-
}
206-
207226
/// Refer to [`databases::Database::get_info_hash_from_whitelist`](crate::core::databases::Database::get_info_hash_from_whitelist).
208227
fn get_info_hash_from_whitelist(&self, info_hash: InfoHash) -> Result<Option<InfoHash>, Error> {
209228
let conn = self.pool.get().map_err(|e| (e, DRIVER))?;

packages/tracker-core/src/databases/error.rs

+9
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@ pub enum Error {
4949
driver: Driver,
5050
},
5151

52+
/// Indicates a failure to update a record into the database.
53+
///
54+
/// This error is raised when an insertion operation fails.
55+
#[error("Unable to update record into {driver} database, {location}")]
56+
UpdateFailed {
57+
location: &'static Location<'static>,
58+
driver: Driver,
59+
},
60+
5261
/// Indicates a failure to delete a record from the database.
5362
///
5463
/// This error includes an error code that may be returned by the database

packages/tracker-core/src/databases/mod.rs

+13
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,19 @@ pub trait Database: Sync + Send {
126126
/// Returns an [`Error`] if the metrics cannot be saved.
127127
fn save_persistent_torrent(&self, info_hash: &InfoHash, downloaded: u32) -> Result<(), Error>;
128128

129+
/// Increases the number of downloads for a given torrent.
130+
///
131+
/// # Arguments
132+
///
133+
/// * `info_hash` - A reference to the torrent's info hash.
134+
///
135+
/// # Context: Torrent Metrics
136+
///
137+
/// # Errors
138+
///
139+
/// Returns an [`Error`] if the query failed.
140+
fn increase_number_of_downloads(&self, info_hash: &InfoHash) -> Result<(), Error>;
141+
129142
// Whitelist
130143

131144
/// Loads the whitelisted torrents from the database.

0 commit comments

Comments
 (0)