Skip to content

Commit

Permalink
feat: new endpoint to generate random torrents
Browse files Browse the repository at this point in the history
For now, it will be used only for testing purposes.

We need to generate random torrent in Cypress in the Index Frontend app.
  • Loading branch information
josecelano committed Jul 31, 2023
1 parent dd1dc0c commit 30bf79e
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 6 deletions.
64 changes: 63 additions & 1 deletion src/web/api/v1/contexts/torrent/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@ use axum::extract::{self, Multipart, Path, Query, State};
use axum::response::{IntoResponse, Response};
use axum::Json;
use serde::Deserialize;
use sha1::{Digest, Sha1};
use uuid::Uuid;

use super::forms::UpdateTorrentInfoForm;
use super::responses::{new_torrent_response, torrent_file_response};
use crate::common::AppData;
use crate::errors::ServiceError;
use crate::models::info_hash::InfoHash;
use crate::models::torrent::{AddTorrentRequest, Metadata};
use crate::models::torrent_file::{DbTorrentInfo, Torrent, TorrentFile};
use crate::models::torrent_tag::TagId;
use crate::services::torrent::ListingRequest;
use crate::utils::parse_torrent;
Expand Down Expand Up @@ -92,7 +95,7 @@ pub async fn download_torrent_handler(
return ServiceError::InternalServerError.into_response();
};

torrent_file_response(bytes)
torrent_file_response(bytes, &format!("{}.torrent", torrent.info.name))
}

/// It returns a list of torrents matching the search criteria.
Expand Down Expand Up @@ -214,6 +217,65 @@ pub async fn delete_torrent_handler(
}
}

/// Returns a random torrent as a byte stream `application/x-bittorrent`.
///
/// This is useful for testing purposes.
///
/// # Errors
///
/// Returns `ServiceError::BadRequest` if the torrent info-hash is invalid.
#[allow(clippy::unused_async)]
pub async fn create_random_torrent_handler(State(_app_data): State<Arc<AppData>>) -> Response {
let torrent = generate_random_torrent();

let Ok(bytes) = parse_torrent::encode_torrent(&torrent) else {
return ServiceError::InternalServerError.into_response();
};

torrent_file_response(bytes, &format!("{}.torrent", torrent.info.name))
}

/// It generates a random single-file torrent for testing purposes.
fn generate_random_torrent() -> Torrent {
let id = Uuid::new_v4();

let file_contents = format!("{id}\n");

let torrent_info = DbTorrentInfo {
torrent_id: 1,
info_hash: String::new(),
name: format!("file-{id}.txt"),
pieces: sha1(&file_contents),
piece_length: 16384,
private: None,
root_hash: 0,
};

let torrent_files: Vec<TorrentFile> = vec![TorrentFile {
path: vec![String::new()],
length: 37, // Number of bytes for the UUID plus one char for line break (`0a`).
md5sum: None,
}];

let torrent_announce_urls: Vec<Vec<String>> = vec![];

Torrent::from_db_info_files_and_announce_urls(torrent_info, torrent_files, torrent_announce_urls)
}

fn sha1(data: &str) -> String {
// Create a Sha1 object
let mut hasher = Sha1::new();

// Write input message
hasher.update(data.as_bytes());

// Read hash digest and consume hasher
let result = hasher.finalize();

// Convert the hash (a byte array) to a string of hex characters
hex::encode(result)
}

/// Extracts the [`TorrentRequest`] from the multipart form payload.
///
/// # Errors
Expand Down
12 changes: 10 additions & 2 deletions src/web/api/v1/contexts/torrent/responses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ pub fn new_torrent_response(torrent_id: TorrentId, info_hash: &str) -> Json<OkRe
}

#[must_use]
pub fn torrent_file_response(bytes: Vec<u8>) -> Response {
(StatusCode::OK, [(header::CONTENT_TYPE, "application/x-bittorrent")], bytes).into_response()
pub fn torrent_file_response(bytes: Vec<u8>, filename: &str) -> Response {
(
StatusCode::OK,
[
(header::CONTENT_TYPE, "application/x-bittorrent"),
(header::CONTENT_DISPOSITION, &format!("attachment; filename={filename}")),
],
bytes,
)
.into_response()
}
8 changes: 5 additions & 3 deletions src/web/api/v1/contexts/torrent/routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use axum::routing::{delete, get, post, put};
use axum::Router;

use super::handlers::{
delete_torrent_handler, download_torrent_handler, get_torrent_info_handler, get_torrents_handler,
update_torrent_info_handler, upload_torrent_handler,
create_random_torrent_handler, delete_torrent_handler, download_torrent_handler, get_torrent_info_handler,
get_torrents_handler, update_torrent_info_handler, upload_torrent_handler,
};
use crate::common::AppData;

Expand All @@ -27,5 +27,7 @@ pub fn router_for_single_resources(app_data: Arc<AppData>) -> Router {

/// Routes for the [`torrent`](crate::web::api::v1::contexts::torrent) API context for multiple resources.
pub fn router_for_multiple_resources(app_data: Arc<AppData>) -> Router {
Router::new().route("/", get(get_torrents_handler).with_state(app_data))
Router::new()
.route("/", get(get_torrents_handler).with_state(app_data.clone()))
.route("/random", get(create_random_torrent_handler).with_state(app_data))
}

0 comments on commit 30bf79e

Please sign in to comment.