mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-05 17:58:55 +00:00
in-memory cache featured item list
This commit is contained in:
1 parent
a4023278bc
commit
8889299cc7
6 files changed
+90
-72
No files matched your search
+4
-4
@@ -7,11 +7,11 @@ use sieve_cache::SieveCache;
|
||||
use errors::AnyhowResult;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Sieve<K: Eq + Hash + Clone, V: Clone + ?Sized> {
|
||||
pub struct ArcSieve<K: Eq + Hash + Clone, V: Clone + ?Sized> {
|
||||
cache: Arc<Mutex<SieveCache<K, V>>>,
|
||||
}
|
||||
|
||||
impl <K: Eq + Hash + Clone, V: Clone + ?Sized> Sieve<K, V> {
|
||||
impl <K: Eq + Hash + Clone, V: Clone + ?Sized> ArcSieve<K, V> {
|
||||
|
||||
pub fn with_capacity(capacity: usize) -> AnyhowResult<Self> {
|
||||
let cache = SieveCache::new(capacity)
|
||||
@@ -54,11 +54,11 @@ impl <K: Eq + Hash + Clone, V: Clone + ?Sized> Sieve<K, V> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::sieve::Sieve;
|
||||
use crate::arc_sieve::ArcSieve;
|
||||
|
||||
#[test]
|
||||
fn test_get_copy() {
|
||||
let sieve : Sieve<String, String> = Sieve::with_capacity(1).unwrap();
|
||||
let sieve : ArcSieve<String, String> = ArcSieve::with_capacity(1).unwrap();
|
||||
let key = "key".to_string();
|
||||
let value = "value".to_string();
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#![allow(dead_code)]
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
pub mod arc_sieve;
|
||||
pub mod multi_item_ttl_cache;
|
||||
pub mod single_item_ttl_cache;
|
||||
pub mod ttl_key_counter;
|
||||
mod sieve;
|
||||
@@ -20,6 +20,8 @@ use tokens::tokens::users::UserToken;
|
||||
|
||||
use crate::payloads::prompt_args::prompt_inner_payload::PromptInnerPayload;
|
||||
|
||||
// NB: Clone is for caches.
|
||||
#[derive(Clone)]
|
||||
pub struct FeaturedMediaFileListPage {
|
||||
pub records: Vec<FeaturedMediaFileListItem>,
|
||||
|
||||
@@ -32,6 +34,7 @@ pub struct FeaturedMediaFileListPage {
|
||||
pub last_id: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FeaturedMediaFileListItem {
|
||||
pub token: MediaFileToken,
|
||||
|
||||
|
||||
+75
-67
@@ -20,21 +20,21 @@ use enums::by_table::media_files::media_file_type::MediaFileType;
|
||||
use enums::common::view_as::ViewAs;
|
||||
use enums::no_table::style_transfer::style_transfer_name::StyleTransferName;
|
||||
use mysql_queries::queries::media_files::get::batch_get_media_files_by_tokens::batch_get_media_files_by_tokens;
|
||||
use mysql_queries::queries::media_files::list::list_featured_media_files::{list_featured_media_files, ListFeaturedMediaFilesArgs};
|
||||
use mysql_queries::queries::media_files::list::list_featured_media_files::{FeaturedMediaFileListPage, list_featured_media_files, ListFeaturedMediaFilesArgs};
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
use crate::http_server::common_responses::user_details_lite::UserDetailsLight;
|
||||
|
||||
use crate::http_server::common_responses::media_file_cover_image_details::{MediaFileCoverImageDetails, MediaFileDefaultCover};
|
||||
use crate::http_server::common_responses::media_file_origin_details::MediaFileOriginDetails;
|
||||
use crate::http_server::common_responses::pagination_cursors::PaginationCursors;
|
||||
use crate::http_server::common_responses::simple_entity_stats::SimpleEntityStats;
|
||||
use crate::http_server::common_responses::user_details_lite::UserDetailsLight;
|
||||
use crate::http_server::endpoints::media_files::helpers::get_scoped_engine_categories::get_scoped_engine_categories;
|
||||
use crate::http_server::endpoints::media_files::helpers::get_scoped_media_classes::get_scoped_media_classes;
|
||||
use crate::http_server::endpoints::media_files::helpers::get_scoped_media_types::get_scoped_media_types;
|
||||
use crate::state::server_state::ServerState;
|
||||
use crate::util::allowed_explore_media_access::allowed_explore_media_access;
|
||||
|
||||
#[derive(Deserialize, ToSchema, IntoParams)]
|
||||
#[derive(Deserialize, ToSchema, IntoParams, Hash, Clone, PartialEq, Eq)]
|
||||
pub struct ListFeaturedMediaFilesQueryParams {
|
||||
pub sort_ascending: Option<bool>,
|
||||
pub page_size: Option<usize>,
|
||||
@@ -181,72 +181,19 @@ pub async fn list_featured_media_files_handler(
|
||||
http_request: HttpRequest,
|
||||
query: Query<ListFeaturedMediaFilesQueryParams>,
|
||||
server_state: web::Data<Arc<ServerState>>
|
||||
) -> Result<HttpResponse, impl ResponseError> {
|
||||
) -> Result<HttpResponse, ListFeaturedMediaFilesError> {
|
||||
|
||||
let maybe_user_session = server_state
|
||||
.session_checker
|
||||
.maybe_get_user_session(&http_request, &server_state.mysql_pool)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
warn!("Session checker error: {:?}", e);
|
||||
ListFeaturedMediaFilesError::ServerError
|
||||
})?;
|
||||
let maybe_cached_results = server_state
|
||||
.caches
|
||||
.ephemeral
|
||||
.featured_media_files_sieve
|
||||
.get_copy(&query)
|
||||
.ok()
|
||||
.flatten();
|
||||
|
||||
let mut is_mod = false;
|
||||
|
||||
match maybe_user_session {
|
||||
None => {},
|
||||
Some(session) => {
|
||||
is_mod = session.can_ban_users;
|
||||
},
|
||||
};
|
||||
|
||||
// TODO(bt,2023-12-04): Enforce real maximums and defaults
|
||||
let limit = query.page_size.unwrap_or(25);
|
||||
|
||||
let sort_ascending = query.sort_ascending.unwrap_or(false);
|
||||
let cursor_is_reversed = query.cursor_is_reversed.unwrap_or(false);
|
||||
|
||||
let cursor = if let Some(cursor) = query.cursor.as_deref() {
|
||||
let cursor = server_state.sort_key_crypto.decrypt_id(cursor)
|
||||
.map_err(|e| {
|
||||
warn!("crypto error: {:?}", e);
|
||||
ListFeaturedMediaFilesError::ServerError
|
||||
})?;
|
||||
Some(cursor as usize)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let view_as = if is_mod {
|
||||
ViewAs::Moderator
|
||||
} else {
|
||||
ViewAs::AnotherUser
|
||||
};
|
||||
|
||||
let mut maybe_filter_media_types = get_scoped_media_types(query.filter_media_type.as_deref());
|
||||
let mut maybe_filter_media_classes = get_scoped_media_classes(query.filter_media_classes.as_deref());
|
||||
let mut maybe_filter_engine_categories = get_scoped_engine_categories(query.filter_engine_categories.as_deref());
|
||||
|
||||
let query_results =
|
||||
list_featured_media_files(ListFeaturedMediaFilesArgs {
|
||||
limit,
|
||||
maybe_offset: cursor,
|
||||
cursor_is_reversed,
|
||||
sort_ascending,
|
||||
view_as,
|
||||
maybe_filter_media_types: maybe_filter_media_types.as_ref(),
|
||||
maybe_filter_media_classes: maybe_filter_media_classes.as_ref(),
|
||||
maybe_filter_engine_categories: maybe_filter_engine_categories.as_ref(),
|
||||
mysql_pool: &server_state.mysql_pool,
|
||||
}).await;
|
||||
|
||||
let results_page = match query_results {
|
||||
Ok(results) => results,
|
||||
Err(e) => {
|
||||
warn!("Query error: {:?}", e);
|
||||
return Err(ListFeaturedMediaFilesError::ServerError);
|
||||
}
|
||||
let results_page = match maybe_cached_results {
|
||||
Some(cached_results) => cached_results,
|
||||
None => database_lookup(&query, &server_state).await?,
|
||||
};
|
||||
|
||||
let cursor_next = if let Some(id) = results_page.last_id {
|
||||
@@ -271,6 +218,12 @@ pub async fn list_featured_media_files_handler(
|
||||
None
|
||||
};
|
||||
|
||||
// TODO(bt,2023-12-04): Enforce real maximums and defaults
|
||||
let limit = query.page_size.unwrap_or(25);
|
||||
|
||||
let sort_ascending = query.sort_ascending.unwrap_or(false);
|
||||
let cursor_is_reversed = query.cursor_is_reversed.unwrap_or(false);
|
||||
|
||||
let results = results_page.records.into_iter()
|
||||
.map(|m| {
|
||||
let public_bucket_path = MediaFileBucketPath::from_object_hash(
|
||||
@@ -342,3 +295,58 @@ pub async fn list_featured_media_files_handler(
|
||||
.content_type("application/json")
|
||||
.body(body))
|
||||
}
|
||||
|
||||
async fn database_lookup(
|
||||
query: &ListFeaturedMediaFilesQueryParams,
|
||||
server_state: &ServerState,
|
||||
) -> Result<FeaturedMediaFileListPage, ListFeaturedMediaFilesError> {
|
||||
|
||||
// TODO(bt,2023-12-04): Enforce real maximums and defaults
|
||||
let limit = query.page_size.unwrap_or(25);
|
||||
|
||||
let sort_ascending = query.sort_ascending.unwrap_or(false);
|
||||
let cursor_is_reversed = query.cursor_is_reversed.unwrap_or(false);
|
||||
|
||||
let cursor = if let Some(cursor) = query.cursor.as_deref() {
|
||||
let cursor = server_state.sort_key_crypto.decrypt_id(cursor)
|
||||
.map_err(|e| {
|
||||
warn!("crypto error: {:?}", e);
|
||||
ListFeaturedMediaFilesError::ServerError
|
||||
})?;
|
||||
Some(cursor as usize)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut maybe_filter_media_types = get_scoped_media_types(query.filter_media_type.as_deref());
|
||||
let mut maybe_filter_media_classes = get_scoped_media_classes(query.filter_media_classes.as_deref());
|
||||
let mut maybe_filter_engine_categories = get_scoped_engine_categories(query.filter_engine_categories.as_deref());
|
||||
|
||||
// NB: No reason to show deleted or non-public featured items to mods or authors.
|
||||
// That's just confusing and wastes an extra query.
|
||||
const VIEW_AS: ViewAs = ViewAs::AnotherUser;
|
||||
|
||||
let results = list_featured_media_files(ListFeaturedMediaFilesArgs {
|
||||
limit,
|
||||
maybe_offset: cursor,
|
||||
cursor_is_reversed,
|
||||
sort_ascending,
|
||||
view_as: VIEW_AS,
|
||||
maybe_filter_media_types: maybe_filter_media_types.as_ref(),
|
||||
maybe_filter_media_classes: maybe_filter_media_classes.as_ref(),
|
||||
maybe_filter_engine_categories: maybe_filter_engine_categories.as_ref(),
|
||||
mysql_pool: &server_state.mysql_pool,
|
||||
}).await.map_err(|err| {
|
||||
error!("DB error: {:?}", err);
|
||||
ListFeaturedMediaFilesError::ServerError
|
||||
})?;
|
||||
|
||||
// NB: Fail open.
|
||||
let _result = server_state
|
||||
.caches
|
||||
.ephemeral
|
||||
.featured_media_files_sieve
|
||||
.store_copy(&query, &results);
|
||||
|
||||
Ok(results)
|
||||
}
|
||||
@@ -58,6 +58,7 @@ use config::shared_constants::DEFAULT_MYSQL_CONNECTION_STRING;
|
||||
use config::shared_constants::DEFAULT_RUST_LOG;
|
||||
use email_sender::smtp_email_sender::SmtpEmailSender;
|
||||
use errors::AnyhowResult;
|
||||
use memory_caching::arc_sieve::ArcSieve;
|
||||
use memory_caching::single_item_ttl_cache::SingleItemTtlCache;
|
||||
use mysql_queries::mediators::badge_granter::BadgeGranter;
|
||||
use mysql_queries::mediators::firehose_publisher::FirehosePublisher;
|
||||
@@ -428,6 +429,7 @@ async fn main() -> AnyhowResult<()> {
|
||||
easyenv::get_env_duration_seconds_or_default(
|
||||
"QUEUE_STATS_CACHE_TTL_SECONDS",
|
||||
Duration::from_secs(60))),
|
||||
featured_media_files_sieve: ArcSieve::with_capacity(100)?,
|
||||
}
|
||||
},
|
||||
ip_ban_list,
|
||||
|
||||
@@ -7,10 +7,12 @@ use actix_helpers::middleware::banned_ip_filter::ip_ban_list::ip_ban_list::IpBan
|
||||
use billing_component::stripe::stripe_config::StripeConfig;
|
||||
use cloud_storage::bucket_client::BucketClient;
|
||||
use email_sender::smtp_email_sender::SmtpEmailSender;
|
||||
use memory_caching::arc_sieve::ArcSieve;
|
||||
use memory_caching::single_item_ttl_cache::SingleItemTtlCache;
|
||||
use mysql_queries::mediators::badge_granter::BadgeGranter;
|
||||
use mysql_queries::mediators::firehose_publisher::FirehosePublisher;
|
||||
use mysql_queries::queries::generic_inference::web::get_pending_inference_job_count::InferenceQueueLengthResult;
|
||||
use mysql_queries::queries::media_files::list::list_featured_media_files::FeaturedMediaFileListPage;
|
||||
use mysql_queries::queries::model_categories::list_categories_query_builder::CategoryList;
|
||||
use mysql_queries::queries::tts::tts_inference_jobs::get_pending_tts_inference_job_count::TtsQueueLengthResult;
|
||||
use mysql_queries::queries::w2l::w2l_templates::list_w2l_templates::W2lTemplateRecordForList;
|
||||
@@ -23,6 +25,7 @@ use crate::configs::static_api_tokens::StaticApiTokenSet;
|
||||
use crate::http_server::cookies::anonymous_visitor_tracking::avt_cookie_manager::AvtCookieManager;
|
||||
use crate::http_server::endpoints::categories::tts::list_fully_computed_assigned_tts_categories::list_fully_computed_assigned_tts_categories::ModelTokensByCategoryToken;
|
||||
use crate::http_server::endpoints::leaderboard::get_leaderboard::LeaderboardInfo;
|
||||
use crate::http_server::endpoints::media_files::list::list_featured_media_files_handler::ListFeaturedMediaFilesQueryParams;
|
||||
use crate::http_server::endpoints::stats::result_transformer::CacheableQueueStats;
|
||||
use crate::http_server::endpoints::tts::list_tts_models::TtsModelRecordForResponse;
|
||||
use crate::http_server::endpoints::voice_conversion::models::list_voice_conversion_models::VoiceConversionModel;
|
||||
@@ -191,6 +194,8 @@ pub struct EphemeralInMemoryCaches {
|
||||
pub tts_queue_length: SingleItemTtlCache<TtsQueueLengthResult>,
|
||||
|
||||
pub leaderboard: SingleItemTtlCache<LeaderboardInfo>,
|
||||
|
||||
pub featured_media_files_sieve: ArcSieve<ListFeaturedMediaFilesQueryParams, FeaturedMediaFileListPage>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
||||
Reference in new issue
Block a user