1use async_trait::async_trait;
2use chrono::NaiveDateTime;
3use serde::{Deserialize, Serialize};
4
5use crate::databases::mysql::Mysql;
6use crate::databases::sqlite::Sqlite;
7use crate::models::category::CategoryId;
8use crate::models::info_hash::InfoHash;
9use crate::models::response::TorrentsResponse;
10use crate::models::torrent::TorrentListing;
11use crate::models::torrent_file::{DbTorrentInfo, Torrent, TorrentFile};
12use crate::models::torrent_tag::{TagId, TorrentTag};
13use crate::models::tracker_key::TrackerKey;
14use crate::models::user::{User, UserAuthentication, UserCompact, UserId, UserProfile};
15
16pub const TABLES_TO_TRUNCATE: &[&str] = &[
19 "torrust_torrent_announce_urls",
20 "torrust_torrent_files",
21 "torrust_torrent_info",
22 "torrust_torrent_tag_links",
23 "torrust_torrent_tracker_stats",
24 "torrust_torrents",
25 "torrust_tracker_keys",
26 "torrust_user_authentication",
27 "torrust_user_bans",
28 "torrust_user_invitation_uses",
29 "torrust_user_invitations",
30 "torrust_user_profiles",
31 "torrust_user_public_keys",
32 "torrust_users",
33 "torrust_categories",
34 "torrust_torrent_tags",
35];
36
37#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)]
39pub enum Driver {
40 Sqlite3,
41 Mysql,
42}
43
44#[derive(Debug, Serialize, sqlx::FromRow)]
46pub struct TorrentCompact {
47 pub torrent_id: i64,
48 pub info_hash: String,
49}
50
51#[derive(Debug, Serialize, Deserialize, sqlx::FromRow)]
53pub struct Category {
54 pub category_id: i64,
55 pub name: String,
56 pub num_torrents: i64,
57}
58
59#[derive(Clone, Copy, Debug, Deserialize)]
61pub enum Sorting {
62 UploadedAsc,
63 UploadedDesc,
64 SeedersAsc,
65 SeedersDesc,
66 LeechersAsc,
67 LeechersDesc,
68 NameAsc,
69 NameDesc,
70 SizeAsc,
71 SizeDesc,
72}
73
74#[derive(Debug)]
76pub enum Error {
77 Error,
78 ErrorWithText(String),
79 UnrecognizedDatabaseDriver, UsernameTaken,
81 EmailTaken,
82 UserNotFound,
83 CategoryAlreadyExists,
84 CategoryNotFound,
85 TagAlreadyExists,
86 TagNotFound,
87 TorrentNotFound,
88 TorrentAlreadyExists, TorrentTitleAlreadyExists,
90}
91
92pub fn get_driver(db_path: &str) -> Result<Driver, Error> {
98 match &db_path.chars().collect::<Vec<char>>() as &[char] {
99 ['s', 'q', 'l', 'i', 't', 'e', ..] => Ok(Driver::Sqlite3),
100 ['m', 'y', 's', 'q', 'l', ..] => Ok(Driver::Mysql),
101 _ => Err(Error::UnrecognizedDatabaseDriver),
102 }
103}
104
105pub async fn connect(db_path: &str) -> Result<Box<dyn Database>, Error> {
111 let db_driver = self::get_driver(db_path)?;
112
113 Ok(match db_driver {
114 self::Driver::Sqlite3 => Box::new(Sqlite::new(db_path).await),
115 self::Driver::Mysql => Box::new(Mysql::new(db_path).await),
116 })
117}
118
119#[async_trait]
121pub trait Database: Sync + Send {
122 fn get_database_driver(&self) -> Driver;
124
125 async fn new(db_path: &str) -> Self
126 where
127 Self: Sized;
128
129 async fn insert_user_and_get_id(&self, username: &str, email: &str, password: &str) -> Result<UserId, Error>;
131
132 async fn get_user_from_id(&self, user_id: i64) -> Result<User, Error>;
134
135 async fn get_user_authentication_from_id(&self, user_id: UserId) -> Result<UserAuthentication, Error>;
137
138 async fn get_user_profile_from_username(&self, username: &str) -> Result<UserProfile, Error>;
140
141 async fn get_user_compact_from_id(&self, user_id: i64) -> Result<UserCompact, Error>;
143
144 async fn get_user_tracker_key(&self, user_id: i64) -> Option<TrackerKey>;
146
147 async fn count_users(&self) -> Result<i64, Error>;
149
150 async fn ban_user(&self, user_id: i64, reason: &str, date_expiry: NaiveDateTime) -> Result<(), Error>;
152
153 async fn grant_admin_role(&self, user_id: i64) -> Result<(), Error>;
155
156 async fn verify_email(&self, user_id: i64) -> Result<(), Error>;
158
159 async fn add_tracker_key(&self, user_id: i64, tracker_key: &TrackerKey) -> Result<(), Error>;
161
162 async fn delete_user(&self, user_id: i64) -> Result<(), Error>;
164
165 async fn insert_category_and_get_id(&self, category_name: &str) -> Result<i64, Error>;
167
168 async fn get_category_from_id(&self, category_id: i64) -> Result<Category, Error>;
170
171 async fn get_category_from_name(&self, category_name: &str) -> Result<Category, Error>;
173
174 async fn get_categories(&self) -> Result<Vec<Category>, Error>;
176
177 async fn delete_category(&self, category_name: &str) -> Result<(), Error>;
179
180 async fn get_torrents_search_sorted_paginated(
182 &self,
183 search: &Option<String>,
184 categories: &Option<Vec<String>>,
185 tags: &Option<Vec<String>>,
186 sort: &Sorting,
187 offset: u64,
188 page_size: u8,
189 ) -> Result<TorrentsResponse, Error>;
190
191 async fn insert_torrent_and_get_id(
193 &self,
194 torrent: &Torrent,
195 uploader_id: UserId,
196 category_id: i64,
197 title: &str,
198 description: &str,
199 ) -> Result<i64, Error>;
200
201 async fn get_torrent_from_info_hash(&self, info_hash: &InfoHash) -> Result<Torrent, Error> {
203 let torrent_info = self.get_torrent_info_from_info_hash(info_hash).await?;
204
205 let torrent_files = self.get_torrent_files_from_id(torrent_info.torrent_id).await?;
206
207 let torrent_announce_urls = self.get_torrent_announce_urls_from_id(torrent_info.torrent_id).await?;
208
209 Ok(Torrent::from_db_info_files_and_announce_urls(
210 torrent_info,
211 torrent_files,
212 torrent_announce_urls,
213 ))
214 }
215
216 async fn get_torrent_from_id(&self, torrent_id: i64) -> Result<Torrent, Error> {
218 let torrent_info = self.get_torrent_info_from_id(torrent_id).await?;
219
220 let torrent_files = self.get_torrent_files_from_id(torrent_id).await?;
221
222 let torrent_announce_urls = self.get_torrent_announce_urls_from_id(torrent_id).await?;
223
224 Ok(Torrent::from_db_info_files_and_announce_urls(
225 torrent_info,
226 torrent_files,
227 torrent_announce_urls,
228 ))
229 }
230
231 async fn get_torrent_info_from_id(&self, torrent_id: i64) -> Result<DbTorrentInfo, Error>;
233
234 async fn get_torrent_info_from_info_hash(&self, info_hash: &InfoHash) -> Result<DbTorrentInfo, Error>;
236
237 async fn get_torrent_files_from_id(&self, torrent_id: i64) -> Result<Vec<TorrentFile>, Error>;
239
240 async fn get_torrent_announce_urls_from_id(&self, torrent_id: i64) -> Result<Vec<Vec<String>>, Error>;
242
243 async fn get_torrent_listing_from_id(&self, torrent_id: i64) -> Result<TorrentListing, Error>;
245
246 async fn get_torrent_listing_from_info_hash(&self, info_hash: &InfoHash) -> Result<TorrentListing, Error>;
248
249 async fn get_all_torrents_compact(&self) -> Result<Vec<TorrentCompact>, Error>;
251
252 async fn update_torrent_title(&self, torrent_id: i64, title: &str) -> Result<(), Error>;
254
255 async fn update_torrent_description(&self, torrent_id: i64, description: &str) -> Result<(), Error>;
257
258 async fn update_torrent_category(&self, torrent_id: i64, category_id: CategoryId) -> Result<(), Error>;
260
261 async fn add_tag(&self, name: &str) -> Result<(), Error>;
263
264 async fn delete_tag(&self, tag_id: TagId) -> Result<(), Error>;
266
267 async fn add_torrent_tag_link(&self, torrent_id: i64, tag_id: TagId) -> Result<(), Error>;
269
270 async fn add_torrent_tag_links(&self, torrent_id: i64, tag_ids: &[TagId]) -> Result<(), Error>;
272
273 async fn delete_torrent_tag_link(&self, torrent_id: i64, tag_id: TagId) -> Result<(), Error>;
275
276 async fn delete_all_torrent_tag_links(&self, torrent_id: i64) -> Result<(), Error>;
278
279 async fn get_tag_from_name(&self, name: &str) -> Result<TorrentTag, Error>;
281
282 async fn get_tags(&self) -> Result<Vec<TorrentTag>, Error>;
284
285 async fn get_tags_for_torrent_id(&self, torrent_id: i64) -> Result<Vec<TorrentTag>, Error>;
287
288 async fn update_tracker_info(&self, torrent_id: i64, tracker_url: &str, seeders: i64, leechers: i64) -> Result<(), Error>;
290
291 async fn delete_torrent(&self, torrent_id: i64) -> Result<(), Error>;
293
294 async fn delete_all_database_rows(&self) -> Result<(), Error>;
296}