Introduce enum and enum dispatching for backends
This way handlers don't need to do case matching on backend ID strings anymore. * Rename `backend` to `backend_id` where we have a backend ID * Add `get` function and `Backends` enum to the `backend` module * Add a depend on the `enum_dispatch` crate
This commit is contained in:
parent
cb40f6b192
commit
49e0e47ba2
|
@ -538,6 +538,18 @@ dependencies = [
|
|||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enum_dispatch"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eb359f1476bf611266ac1f5355bc14aeca37b299d0ebccc038ee7058891c9cb"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.8.0"
|
||||
|
@ -1521,6 +1533,7 @@ dependencies = [
|
|||
"async-trait",
|
||||
"cached",
|
||||
"chrono",
|
||||
"enum_dispatch",
|
||||
"reqwest",
|
||||
"rocket",
|
||||
"rocket_dyn_templates",
|
||||
|
|
|
@ -11,6 +11,7 @@ license = "MIT"
|
|||
async-trait = "0.1.57"
|
||||
cached = { version = "0.38.0", features = ["async"] }
|
||||
chrono = { version = "0.4.19", features = ["serde"] }
|
||||
enum_dispatch = "0.3.8"
|
||||
reqwest = { version = "0.11.10", features = ["json"] }
|
||||
rocket = { version = "0.5.0-rc.2", features = ["json"] }
|
||||
rocket_dyn_templates = { version = "0.1.0-rc.2", features = ["tera"] }
|
||||
|
|
|
@ -9,14 +9,30 @@ use std::path::{Path, PathBuf};
|
|||
|
||||
use async_trait::async_trait;
|
||||
use chrono::{DateTime, Utc};
|
||||
use enum_dispatch::enum_dispatch;
|
||||
use reqwest::Url;
|
||||
|
||||
use crate::Result;
|
||||
use crate::{Error, Result};
|
||||
|
||||
pub(crate) mod mixcloud;
|
||||
|
||||
/// Retrieves the back-end for the provided ID (if supported).
|
||||
pub(crate) fn get(backend: &str) -> Result<Backends> {
|
||||
match backend {
|
||||
"mixcloud" => Ok(Backends::Mixcloud(mixcloud::backend())),
|
||||
_ => Err(Error::UnsupportedBackend(backend.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
/// The support back-ends.
|
||||
#[enum_dispatch(Backend)]
|
||||
pub(crate) enum Backends {
|
||||
Mixcloud(mixcloud::Backend),
|
||||
}
|
||||
|
||||
/// Functionality of a content back-end.
|
||||
#[async_trait]
|
||||
#[enum_dispatch]
|
||||
pub(crate) trait Backend {
|
||||
/// Returns the name of the backend.
|
||||
fn name(&self) -> &'static str;
|
||||
|
|
|
@ -18,7 +18,7 @@ use crate::Config;
|
|||
/// Constructs a feed as string from a back-end channel using the `rss` crate.
|
||||
///
|
||||
/// It requires the backend and configuration to be able to construct download URLs.
|
||||
pub(crate) fn construct(backend: &str, config: &Config, channel: Channel) -> rss::Channel {
|
||||
pub(crate) fn construct(backend_id: &str, config: &Config, channel: Channel) -> rss::Channel {
|
||||
let category = CategoryBuilder::default()
|
||||
.name(
|
||||
channel
|
||||
|
@ -41,7 +41,7 @@ pub(crate) fn construct(backend: &str, config: &Config, channel: Channel) -> rss
|
|||
let items = channel
|
||||
.items
|
||||
.into_iter()
|
||||
.map(|item| construct_item(backend, config, item, &mut last_build))
|
||||
.map(|item| construct_item(backend_id, config, item, &mut last_build))
|
||||
.collect::<Vec<_>>();
|
||||
let itunes_ext = ITunesChannelExtensionBuilder::default()
|
||||
.author(channel.author)
|
||||
|
@ -76,7 +76,7 @@ pub(crate) fn construct(backend: &str, config: &Config, channel: Channel) -> rss
|
|||
/// It also bumps the last build timestamp if the last updated timestamp is later than the current
|
||||
/// value.
|
||||
fn construct_item(
|
||||
backend: &str,
|
||||
backend_id: &str,
|
||||
config: &Config,
|
||||
item: Item,
|
||||
last_build: &mut DateTime<Utc>,
|
||||
|
@ -93,7 +93,7 @@ fn construct_item(
|
|||
.collect::<Vec<_>>();
|
||||
let url = uri!(
|
||||
Absolute::parse(&config.url).expect("valid URL"),
|
||||
crate::get_download(backend = backend, file = item.enclosure.file)
|
||||
crate::get_download(backend_id = backend_id, file = item.enclosure.file)
|
||||
);
|
||||
let enclosure = EnclosureBuilder::default()
|
||||
.url(url.to_string())
|
||||
|
|
28
src/lib.rs
28
src/lib.rs
|
@ -18,7 +18,7 @@ use rocket::serde::{Deserialize, Serialize};
|
|||
use rocket::{get, routes, Build, Request, Responder, Rocket, State};
|
||||
use rocket_dyn_templates::{context, Template};
|
||||
|
||||
use crate::backends::{mixcloud, Backend};
|
||||
use crate::backends::Backend;
|
||||
|
||||
pub(crate) mod backends;
|
||||
pub(crate) mod feed;
|
||||
|
@ -80,32 +80,26 @@ pub(crate) struct Config {
|
|||
struct RssFeed(String);
|
||||
|
||||
/// Retrieves a download by redirecting to the URL resolved by the selected back-end.
|
||||
#[get("/download/<backend>/<file..>")]
|
||||
pub(crate) async fn get_download(file: PathBuf, backend: &str) -> Result<Redirect> {
|
||||
match backend {
|
||||
"mixcloud" => mixcloud::backend()
|
||||
.redirect_url(&file)
|
||||
.await
|
||||
.map(Redirect::to),
|
||||
_ => Err(Error::UnsupportedBackend(backend.to_string())),
|
||||
}
|
||||
#[get("/download/<backend_id>/<file..>")]
|
||||
pub(crate) async fn get_download(file: PathBuf, backend_id: &str) -> Result<Redirect> {
|
||||
let backend = backends::get(backend_id)?;
|
||||
|
||||
backend.redirect_url(&file).await.map(Redirect::to)
|
||||
}
|
||||
|
||||
/// Handler for retrieving the RSS feed of a channel on a certain back-end.
|
||||
///
|
||||
/// The limit parameter determines the maximum of items that can be in the feed.
|
||||
#[get("/feed/<backend>/<channel_id>?<limit>")]
|
||||
#[get("/feed/<backend_id>/<channel_id>?<limit>")]
|
||||
async fn get_feed(
|
||||
backend: &str,
|
||||
backend_id: &str,
|
||||
channel_id: &str,
|
||||
limit: Option<usize>,
|
||||
config: &State<Config>,
|
||||
) -> Result<RssFeed> {
|
||||
let channel = match backend {
|
||||
"mixcloud" => mixcloud::backend().channel(channel_id, limit).await?,
|
||||
_ => return Err(Error::UnsupportedBackend(backend.to_string())),
|
||||
};
|
||||
let feed = feed::construct(backend, config, channel);
|
||||
let backend = backends::get(backend_id)?;
|
||||
let channel = backend.channel(channel_id, limit).await?;
|
||||
let feed = feed::construct(backend_id, config, channel);
|
||||
|
||||
Ok(RssFeed(feed.to_string()))
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue