diff --git a/src/bin/supercell.rs b/src/bin/supercell.rs index 27124ff..88aa434 100644 --- a/src/bin/supercell.rs +++ b/src/bin/supercell.rs @@ -62,9 +62,14 @@ async fn main() -> Result<()> { .flat_map(|(_, (_, allow))| allow.iter().cloned()) .collect::>(); - let cache = Cache::default(); - - let web_context = WebContext::new(pool.clone(), config.external_base.as_str(), feeds, cache.clone()); + let cache = Cache::new(20); + + let web_context = WebContext::new( + pool.clone(), + config.external_base.as_str(), + feeds, + cache.clone(), + ); let app = build_router(web_context.clone()); diff --git a/src/cache.rs b/src/cache.rs index cf26ec3..3fa7f23 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -43,7 +43,7 @@ impl InnerCache { } impl Cache { - pub(crate) fn new(page_size: u8) -> Self { + pub fn new(page_size: u8) -> Self { Self { inner_cache: Arc::new(RwLock::new(InnerCache::new(page_size))), } @@ -54,13 +54,14 @@ impl Cache { let feed_chunks = inner.cached_feeds.get(feed_id)?; - if page as usize > feed_chunks.len() { + if page > feed_chunks.len() { return None; } feed_chunks.get(page).cloned() } + #[allow(clippy::ptr_arg)] pub(crate) async fn update_feed(&self, feed_id: &str, posts: &Vec) { let mut inner = self.inner_cache.write().await; @@ -136,7 +137,6 @@ impl CacheTask { .generate_popular(&feed.uri, gravity, *limit.as_ref()) .await { - tracing::error!(error = ?err, feed_uri = ?feed.uri, "failed to generate simple feed"); } } diff --git a/src/http/handle_get_feed_skeleton.rs b/src/http/handle_get_feed_skeleton.rs index d5ca07d..5418cd1 100644 --- a/src/http/handle_get_feed_skeleton.rs +++ b/src/http/handle_get_feed_skeleton.rs @@ -103,7 +103,9 @@ pub async fn handle_get_feed_skeleton( } } - let parsed_cursor = parse_cursor(feed_params.cursor).map(|value| value.clamp(0, 10000)).unwrap_or(0) as usize; + let parsed_cursor = parse_cursor(feed_params.cursor) + .map(|value| value.clamp(0, 10000)) + .unwrap_or(0) as usize; let posts = web_context.cache.get_posts(&feed_uri, parsed_cursor).await; @@ -119,10 +121,10 @@ pub async fn handle_get_feed_skeleton( } let posts = posts.unwrap(); - let cursor = if posts.len() != 0 { - Some((parsed_cursor + 1).to_string()) - } else { + let cursor = if posts.is_empty() { Some(parsed_cursor.to_string()) + } else { + Some((parsed_cursor + 1).to_string()) }; let feed_item_views = posts diff --git a/src/matcher.rs b/src/matcher.rs index 080fa32..d85a1e2 100644 --- a/src/matcher.rs +++ b/src/matcher.rs @@ -2,7 +2,9 @@ use anyhow::{anyhow, Context, Result}; use serde_json_path::JsonPath; -use rhai::{serde::to_dynamic, CustomType, Dynamic, Engine, Scope, TypeBuilder, AST}; +use rhai::{ + serde::to_dynamic, Array, CustomType, Dynamic, Engine, ImmutableString, Scope, TypeBuilder, AST, +}; use std::{collections::HashMap, path::PathBuf, str::FromStr}; use crate::config; @@ -276,6 +278,35 @@ impl Matcher for SequenceMatcher { } } +pub fn matcher_sequence_matches(sequence: Array, text: ImmutableString) -> bool { + let sequence = sequence + .iter() + .filter_map(|value| value.clone().try_cast::()) + .collect::>(); + sequence_matches(sequence.as_ref(), &text) +} + +fn sequence_matches(sequence: &[String], text: &str) -> bool { + let mut last_found: i32 = -1; + + let mut found_index = 0; + for (index, expected) in sequence.iter().enumerate() { + if let Some(current_found) = text.find(expected) { + if (current_found as i32) > last_found { + last_found = current_found as i32; + found_index = index; + } else { + last_found = -1; + break; + } + } else { + last_found = -1; + break; + } + } + last_found != -1 && found_index == sequence.len() - 1 +} + fn extract_aturi(aturi: Option<&JsonPath>, event_value: &serde_json::Value) -> Option { if let Some(aturi_path) = aturi { let nodes = aturi_path.query(event_value).all(); @@ -358,6 +389,7 @@ impl RhaiMatcher { engine .build_type::() .register_fn("build_aturi", build_aturi) + .register_fn("sequence_matches", matcher_sequence_matches) .register_fn("update_match", Match::update) .register_fn("upsert_match", Match::upsert); let ast = engine @@ -680,6 +712,11 @@ mod tests { "at://did:plc:cbkjy5n7bk3ax2wplmtjofq2/app.bsky.feed.post/3laadb7behk25", ), ("rhai_match_reply_root.rhai", false, ""), + ( + "rhai_match_sequence.rhai", + true, + "at://did:plc:cbkjy5n7bk3ax2wplmtjofq2/app.bsky.feed.post/3laadb7behk25", + ), ], ), ( diff --git a/testdata/rhai_match_sequence.rhai b/testdata/rhai_match_sequence.rhai new file mode 100644 index 0000000..797895e --- /dev/null +++ b/testdata/rhai_match_sequence.rhai @@ -0,0 +1,15 @@ +let rtype = event?.commit?.record["$type"]; + +switch rtype { + "app.bsky.feed.post" => { + let text = event?.commit?.record?.text ?? ""; + let found = sequence_matches(["feed", "generator"], text.to_lower()); + if found { + return build_aturi(event); + } + } + // noop + _ => { } +} + +false