Skip to content

Commit

Permalink
feat: improve sitemap
Browse files Browse the repository at this point in the history
  • Loading branch information
akarras committed Oct 18, 2023
1 parent f18f8ac commit e278a61
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 9 deletions.
2 changes: 1 addition & 1 deletion ultros/src/analyzer_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ impl From<&ultros_api_types::SaleHistory> for SaleSummary {
}
}

#[derive(Debug, Default)]
#[derive(Debug, Default, Clone)]
pub(crate) struct SaleHistory {
pub(crate) item_map: HashMap<ItemKey, SmallVec<[SaleSummary; SALE_HISTORY_SIZE]>>,
}
Expand Down
105 changes: 97 additions & 8 deletions ultros/src/web/sitemap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,27 @@ use crate::analyzer_service::AnalyzerService;
use anyhow::anyhow;
use axum::{
extract::{Path, State},
headers::CacheControl,
http::HeaderValue,
response::{IntoResponse, Response},
};
use chrono::{DateTime, Duration, NaiveDateTime, Utc};
use futures::future::{join_all, try_join_all};
use itertools::Itertools;
use mime_guess::mime;
use reqwest::header;
use sitemap_rs::{sitemap::Sitemap, sitemap_index::SitemapIndex, url::Url, url_set::UrlSet};
use std::{collections::HashSet, sync::Arc};
use sitemap_rs::{
image::Image,
sitemap::Sitemap,
sitemap_index::SitemapIndex,
url::{ChangeFrequency, Url},
url_set::UrlSet,
};
use std::{
collections::{HashMap, HashSet},
sync::Arc,
};
use ultros_api_types::world_helper::WorldHelper;
use ultros_db::world_cache::{AnySelector, WorldCache};

pub(crate) struct Xml(Vec<u8>);
Expand Down Expand Up @@ -128,7 +141,71 @@ pub(crate) async fn world_sitemap(
Ok(Xml(url_xml))
}

pub(crate) async fn item_sitemap() -> Result<Xml, WebError> {
pub(crate) async fn item_sitemap(
State(world_cache): State<Arc<WorldHelper>>,
State(analyzer_service): State<AnalyzerService>,
) -> Result<(CacheControl, Xml), WebError> {
let mut item_id_map: HashMap<_, Vec<_>> = HashMap::new();
let a = &analyzer_service;
let sales = try_join_all(
world_cache
.get_all()
.regions
.iter()
.flat_map(move |region| {
region.datacenters.iter().flat_map(move |datacenter| {
datacenter.worlds.iter().map(move |world| async move {
a.read_sale_history(&AnySelector::World(world.id), |w| w.clone())
.await
})
})
}),
)
.await?;
for (item, sales) in sales.into_iter().flat_map(|sale| sale.item_map.into_iter()) {
let entry = item_id_map.entry(item.item_id).or_default();
for sale in sales {
entry.push(sale);
}
}
let frequency_map: HashMap<_, _> = item_id_map
.into_iter()
.map(|(key, mut value)| {
value.sort_by_key(|f| f.sale_date);
let first = value.first().map(|f| f.sale_date);
let median = {
let len = value.len();
if len < 2 {
None
} else {
value.get(len / 2)
}
};
if let Some(median) = median {
(
key,
(
first,
match (Utc::now()
.naive_utc()
.signed_duration_since(median.sale_date))
.num_days()
.abs()
{
0 => ChangeFrequency::Always,
1 => ChangeFrequency::Daily,
2..=6 => ChangeFrequency::Weekly,
7..=30 => ChangeFrequency::Monthly,
31..=360 => ChangeFrequency::Yearly,
_ => ChangeFrequency::Never,
},
),
)
} else {
(key, (first, ChangeFrequency::Never))
}
})
.collect();
let items = UrlSet::new(
xiv_gen_db::data()
.items
Expand All @@ -137,15 +214,27 @@ pub(crate) async fn item_sitemap() -> Result<Xml, WebError> {
.map(|(key, _)| key.0)
.sorted()
.map(|id| {
Url::builder(format!("https://ultros.app/item/{id}"))
.build()
.unwrap()
let mut builder = Url::builder(format!("https://ultros.app/item/{id}"));
if let Some((last_modified, change)) = frequency_map.get(&id) {
if let Some(modified) = last_modified {
builder.last_modified(modified.and_utc().fixed_offset());
}
builder.change_frequency(*change);
}
builder.images(vec![Image::new(format!(
"https://ultros.app/static/itemicon/{id}?size=Large"
))]);
builder.build()
})
.collect(),
.collect::<Result<Vec<_>, _>>()
.map_err(|e| anyhow!("Error generating sitemap: {e}"))?,
)?;
let mut url_xml = Vec::new();
items
.write(&mut url_xml)
.map_err(|_| anyhow!("Error creating site map"))?;
Ok(Xml(url_xml))
Ok((
CacheControl::new().with_max_age(std::time::Duration::from_secs(60 * 10)),
Xml(url_xml),
))
}

0 comments on commit e278a61

Please sign in to comment.