Skip to content

Commit

Permalink
refactor: improve source representation (#148)
Browse files Browse the repository at this point in the history
Previously dynamic source is represented as `Option<Source>`. Upon
reflection, the case for dynamic source is not semantically the case for
the lack of source despite a null source is how dynamic source is
represented in config. Therefore, it is better to represent dynamic
source as a variant of `Source`.
  • Loading branch information
shouya authored Sep 18, 2024
1 parent d178443 commit ef30e22
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 71 deletions.
2 changes: 1 addition & 1 deletion scripts/watch-dev.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT

cargo watch -x build -s 'touch /tmp/.trigger' &
cargo watch -w /tmp/.trigger -d0 -s 'target/debug/rss-funnel -c ~/.config/rss-funnel-dev/funnel.yaml server' &
cargo watch -w /tmp/.trigger -d0 -s 'target/debug/rss-funnel -c ~/.config/rss-funnel-dev/funnel.yaml server -w' &

wait

10 changes: 10 additions & 0 deletions src/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ pub struct FilterContext {
/// from a relative path.
base: Option<Url>,

/// User supplied source (`?source=` query parameter)
source: Option<Url>,

/// The maximum number of filters to run on this pipeline
filter_skip: Option<FilterSkip>,

Expand All @@ -63,6 +66,7 @@ impl FilterContext {
Self {
base: None,
filter_skip: None,
source: None,
extra_queries: HashMap::new(),
}
}
Expand All @@ -79,6 +83,10 @@ impl FilterContext {
&self.extra_queries
}

pub fn source(&self) -> Option<&Url> {
self.source.as_ref()
}

pub fn set_filter_skip(&mut self, filter_skip: FilterSkip) {
self.filter_skip = Some(filter_skip);
}
Expand All @@ -90,6 +98,7 @@ impl FilterContext {
pub fn subcontext(&self) -> Self {
Self {
base: self.base.clone(),
source: None,
filter_skip: None,
extra_queries: self.extra_queries.clone(),
}
Expand All @@ -98,6 +107,7 @@ impl FilterContext {
pub fn from_param(param: &crate::server::EndpointParam) -> Self {
Self {
base: param.base().cloned(),
source: param.source().cloned(),
filter_skip: param.filter_skip().cloned(),
extra_queries: param.extra_queries().clone(),
}
Expand Down
32 changes: 10 additions & 22 deletions src/server/endpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ impl EndpointConfig {
path: path.to_string(),
note: Some("Default On-the-fly filter endpoint".to_string()),
config: EndpointServiceConfig {
source: None,
source: SourceConfig::Dynamic,
filters: FilterPipelineConfig::default(),
on_the_fly_filters: true,
client: None,
Expand All @@ -66,8 +66,8 @@ impl EndpointConfig {
EndpointService::from_config(self.config).await
}

pub(crate) fn source(&self) -> Option<&SourceConfig> {
self.config.source.as_ref()
pub(crate) fn source(&self) -> &SourceConfig {
&self.config.source
}
}

Expand All @@ -76,7 +76,7 @@ impl EndpointConfig {
)]
pub struct EndpointServiceConfig {
#[serde(default)]
pub source: Option<SourceConfig>,
pub source: SourceConfig,
#[serde(default)]
pub filters: FilterPipelineConfig,
#[serde(default)]
Expand All @@ -97,7 +97,7 @@ pub struct EndpointServiceConfig {
pub struct EndpointService {
// used for detecting changes in the config for partial update
config: EndpointServiceConfig,
source: Option<Source>,
source: Source,
on_the_fly_filter: Option<Arc<Mutex<OnTheFlyFilter>>>,
filters: Arc<FilterPipeline>,
client: Arc<Client>,
Expand Down Expand Up @@ -235,7 +235,7 @@ impl EndpointService {
self
}

pub fn source(&self) -> &Option<Source> {
pub fn source(&self) -> &Source {
&self.source
}

Expand All @@ -262,7 +262,7 @@ impl EndpointService {

let default_cache_ttl = Duration::from_secs(15 * 60);
let client = config.client.unwrap_or_default().build(default_cache_ttl)?;
let source = config.source.map(|s| s.try_into()).transpose()?;
let source = config.source.try_into()?;
let on_the_fly_filter = if config.on_the_fly_filters {
Some(Default::default())
} else {
Expand All @@ -279,9 +279,9 @@ impl EndpointService {
}

pub async fn run(self, param: EndpointParam) -> Result<Feed> {
let source = self.find_source(&param.source)?;
let mut context = FilterContext::from_param(&param);
let feed = source
let feed = self
.source
.fetch_feed(&context, Some(&self.client))
.await
.map_err(|e| Error::FetchSource(Box::new(e)))?;
Expand Down Expand Up @@ -311,18 +311,6 @@ impl EndpointService {
Ok(feed)
}

fn find_source(&self, param: &Option<Url>) -> Result<Source> {
match &self.source {
// ignore the source from param if it's already specified in config
Some(source) => Ok(source.clone()),
None => param
.as_ref()
.ok_or(Error::Message("missing source".into()))
.cloned()
.map(Source::from),
}
}

pub fn config_changed(&self, config: &EndpointServiceConfig) -> bool {
self.config != *config
}
Expand All @@ -340,7 +328,7 @@ impl EndpointService {
}

if self.config.source != config.source {
let source = config.source.map(|s| s.try_into()).transpose()?;
let source = config.source.try_into()?;
self.source = source;
}

Expand Down
30 changes: 12 additions & 18 deletions src/server/web/endpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,9 @@ pub async fn render_endpoint_page(
}

section .source-and-config {
@if let Some(source) = source {
section .source-control {
(source);
div.loading { (sprite("loader")) }
}
section .source-control {
(source);
div.loading { (sprite("loader")) }
}

details {
Expand All @@ -92,11 +90,11 @@ pub async fn render_endpoint_page(

fn source_control_fragment(
path: &str,
source: &Option<Source>,
source: &Source,
param: &Result<EndpointParam, String>,
) -> Option<Markup> {
) -> Markup {
match source {
None => Some(html! {
Source::Dynamic => html! {
input
.hx-included.grow
type="text"
Expand All @@ -111,20 +109,16 @@ fn source_control_fragment(
hx-target="main"
hx-select="main"
{}
}),
Some(Source::AbsoluteUrl(url)) => Some(html! {
div title="Source" .source { (url) }
}),
Some(Source::RelativeUrl(url)) => Some(html! {
div title="Source" .source { (url) }
}),
Some(Source::Templated(templated)) => Some(html! {
},
Source::AbsoluteUrl(url) => html! {div title="Source" .source { (url) }},
Source::RelativeUrl(url) => html! {div title="Source" .source { (url) }},
Source::Templated(templated) => html! {
div .source-template-container {
@let queries = param.as_ref().ok().map(|p| p.extra_queries());
(source_template_fragment(templated, path, queries));
}
}),
Some(Source::FromScratch(scratch)) => Some(from_scratch_fragment(scratch)),
},
Source::FromScratch(scratch) => from_scratch_fragment(scratch),
}
}

Expand Down
14 changes: 7 additions & 7 deletions src/server/web/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pub fn render_endpoint_list_page(root_config: &RootConfig) -> Markup {

fn endpoint_list_entry_fragment(endpoint: &EndpointConfig) -> Markup {
html! {
li ."my-.5" {
li {
p {
a href={"/_/endpoint/" (endpoint.path.trim_start_matches('/'))} {
(endpoint.path)
Expand Down Expand Up @@ -74,12 +74,12 @@ fn url_path(url: impl TryInto<Url>) -> Option<String> {
Some(url.path().to_owned())
}

fn short_source_repr(source: Option<&SourceConfig>) -> Markup {
fn short_source_repr(source: &SourceConfig) -> Markup {
match source {
None => html! {
SourceConfig::Dynamic => html! {
span .tag.dynamic { "dynamic" }
},
Some(SourceConfig::Simple(url)) if url.starts_with("/") => {
SourceConfig::Simple(url) if url.starts_with("/") => {
let path = url_path(url.as_str());
let path = path.map(|p| format!("/_/{p}"));
html! {
Expand All @@ -94,20 +94,20 @@ fn short_source_repr(source: Option<&SourceConfig>) -> Markup {
}
}
}
Some(SourceConfig::Simple(url)) => {
SourceConfig::Simple(url) => {
let host = url_host(url.as_str()).unwrap_or_else(|| "...".into());
html! {
span .tag.simple {
a href=(url) { (host) }
}
}
}
Some(SourceConfig::FromScratch(_)) => {
SourceConfig::FromScratch(_) => {
html! {
span .tag.scratch title="Made from scratch" { "scratch" }
}
}
Some(SourceConfig::Templated(_source)) => {
SourceConfig::Templated(_source) => {
html! {
span .tag.templated title="Templated source" { "templated" }
}
Expand Down
Loading

0 comments on commit ef30e22

Please sign in to comment.