can now decode torrent as JSON in the HTTP API
This commit is contained in:
parent
52beec9296
commit
04cfe9fc6b
3 changed files with 61 additions and 3 deletions
|
|
@ -1,9 +1,9 @@
|
||||||
use std::{collections::HashMap, marker::PhantomData};
|
use std::{collections::HashMap, fmt::Display, marker::PhantomData};
|
||||||
|
|
||||||
use buffers::{ByteBuf, ByteBufOwned};
|
use buffers::{ByteBuf, ByteBufOwned};
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use clone_to_owned::CloneToOwned;
|
use clone_to_owned::CloneToOwned;
|
||||||
use serde::Deserializer;
|
use serde::{Deserialize, Deserializer, Serialize};
|
||||||
|
|
||||||
use crate::serde_bencode_de::from_bytes;
|
use crate::serde_bencode_de::from_bytes;
|
||||||
|
|
||||||
|
|
@ -136,6 +136,44 @@ where
|
||||||
pub type BencodeValueBorrowed<'a> = BencodeValue<ByteBuf<'a>>;
|
pub type BencodeValueBorrowed<'a> = BencodeValue<ByteBuf<'a>>;
|
||||||
pub type BencodeValueOwned = BencodeValue<ByteBufOwned>;
|
pub type BencodeValueOwned = BencodeValue<ByteBufOwned>;
|
||||||
|
|
||||||
|
// A wrapper to deserialize dyn values as strings.
|
||||||
|
#[derive(PartialEq, Eq, Hash)]
|
||||||
|
pub struct AsDisplay<T>(T);
|
||||||
|
|
||||||
|
impl<'de, T> From<&'de [u8]> for AsDisplay<T>
|
||||||
|
where
|
||||||
|
T: From<&'de [u8]>,
|
||||||
|
{
|
||||||
|
fn from(value: &'de [u8]) -> Self {
|
||||||
|
Self(T::from(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Serialize for AsDisplay<T>
|
||||||
|
where
|
||||||
|
T: Display,
|
||||||
|
{
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
serializer.serialize_str(&format!("{}", self.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de, T> Deserialize<'de> for AsDisplay<T>
|
||||||
|
where
|
||||||
|
T: Deserialize<'de>,
|
||||||
|
{
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let value = T::deserialize(deserializer)?;
|
||||||
|
Ok(AsDisplay(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::serde_bencode_ser::bencode_serialize_to_writer;
|
use crate::serde_bencode_ser::bencode_serialize_to_writer;
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,9 @@ impl<'a> std::fmt::Display for HexBytes<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn debug_bytes(b: &[u8], f: &mut std::fmt::Formatter<'_>, debug_strings: bool) -> std::fmt::Result {
|
fn debug_bytes(b: &[u8], f: &mut std::fmt::Formatter<'_>, debug_strings: bool) -> std::fmt::Result {
|
||||||
|
if b.is_empty() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
if b.iter().all(|b| *b == 0) {
|
if b.iter().all(|b| *b == 0) {
|
||||||
return write!(f, "<{} bytes, all zeroes>", b.len());
|
return write!(f, "<{} bytes, all zeroes>", b.len());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ use axum::body::Bytes;
|
||||||
use axum::extract::{Path, Query, State};
|
use axum::extract::{Path, Query, State};
|
||||||
use axum::response::IntoResponse;
|
use axum::response::IntoResponse;
|
||||||
use axum::routing::{get, post};
|
use axum::routing::{get, post};
|
||||||
|
use bencode::AsDisplay;
|
||||||
|
use buffers::ByteBuf;
|
||||||
use futures::future::BoxFuture;
|
use futures::future::BoxFuture;
|
||||||
use futures::{FutureExt, TryStreamExt};
|
use futures::{FutureExt, TryStreamExt};
|
||||||
use http::{HeaderMap, HeaderValue, StatusCode};
|
use http::{HeaderMap, HeaderValue, StatusCode};
|
||||||
|
|
@ -190,6 +192,7 @@ impl HttpApi {
|
||||||
|
|
||||||
async fn resolve_magnet(
|
async fn resolve_magnet(
|
||||||
State(state): State<ApiState>,
|
State(state): State<ApiState>,
|
||||||
|
inp_headers: HeaderMap,
|
||||||
url: String,
|
url: String,
|
||||||
) -> Result<impl IntoResponse> {
|
) -> Result<impl IntoResponse> {
|
||||||
let added = state
|
let added = state
|
||||||
|
|
@ -219,7 +222,21 @@ impl HttpApi {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut headers = HeaderMap::new();
|
let mut headers = HeaderMap::new();
|
||||||
|
|
||||||
|
if inp_headers
|
||||||
|
.get("Accept")
|
||||||
|
.and_then(|v| std::str::from_utf8(v.as_bytes()).ok())
|
||||||
|
== Some("application/json")
|
||||||
|
{
|
||||||
|
let data = bencode::dyn_from_bytes::<AsDisplay<ByteBuf>>(&content)
|
||||||
|
.context("error decoding .torrent file content")?;
|
||||||
|
let data = serde_json::to_string(&data).context("error serializing")?;
|
||||||
|
headers.insert("Content-Type", HeaderValue::from_static("application/json"));
|
||||||
|
return Ok((headers, data).into_response());
|
||||||
|
}
|
||||||
|
|
||||||
headers.insert(
|
headers.insert(
|
||||||
"Content-Type",
|
"Content-Type",
|
||||||
HeaderValue::from_static("application/x-bittorrent"),
|
HeaderValue::from_static("application/x-bittorrent"),
|
||||||
|
|
@ -234,7 +251,7 @@ impl HttpApi {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok((headers, content))
|
Ok((headers, content).into_response())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn torrent_playlist(
|
async fn torrent_playlist(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue