mirror of
https://git.asonix.dog/asonix/pict-rs
synced 2024-12-22 11:21:24 +00:00
Shorten pagination slugs
This commit is contained in:
parent
1271ff2cc7
commit
64950bfe0e
5 changed files with 71 additions and 53 deletions
|
@ -79,35 +79,35 @@ impl InternalFormat {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) const fn to_bytes(self) -> &'static [u8] {
|
||||
pub(crate) const fn to_byte(self) -> u8 {
|
||||
match self {
|
||||
Self::Animation(AnimationFormat::Apng) => b"a-apng",
|
||||
Self::Animation(AnimationFormat::Avif) => b"a-avif",
|
||||
Self::Animation(AnimationFormat::Gif) => b"a-gif",
|
||||
Self::Animation(AnimationFormat::Webp) => b"a-webp",
|
||||
Self::Image(ImageFormat::Avif) => b"i-avif",
|
||||
Self::Image(ImageFormat::Jpeg) => b"i-jpeg",
|
||||
Self::Image(ImageFormat::Jxl) => b"i-jxl",
|
||||
Self::Image(ImageFormat::Png) => b"i-png",
|
||||
Self::Image(ImageFormat::Webp) => b"i-webp",
|
||||
Self::Video(InternalVideoFormat::Mp4) => b"v-mp4",
|
||||
Self::Video(InternalVideoFormat::Webm) => b"v-webm",
|
||||
Self::Animation(AnimationFormat::Apng) => 0,
|
||||
Self::Animation(AnimationFormat::Avif) => 1,
|
||||
Self::Animation(AnimationFormat::Gif) => 2,
|
||||
Self::Animation(AnimationFormat::Webp) => 3,
|
||||
Self::Image(ImageFormat::Avif) => 4,
|
||||
Self::Image(ImageFormat::Jpeg) => 5,
|
||||
Self::Image(ImageFormat::Jxl) => 6,
|
||||
Self::Image(ImageFormat::Png) => 7,
|
||||
Self::Image(ImageFormat::Webp) => 8,
|
||||
Self::Video(InternalVideoFormat::Mp4) => 9,
|
||||
Self::Video(InternalVideoFormat::Webm) => 10,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const fn from_bytes(bytes: &[u8]) -> Option<Self> {
|
||||
match bytes {
|
||||
b"a-apng" => Some(Self::Animation(AnimationFormat::Apng)),
|
||||
b"a-avif" => Some(Self::Animation(AnimationFormat::Avif)),
|
||||
b"a-gif" => Some(Self::Animation(AnimationFormat::Gif)),
|
||||
b"a-webp" => Some(Self::Animation(AnimationFormat::Webp)),
|
||||
b"i-avif" => Some(Self::Image(ImageFormat::Avif)),
|
||||
b"i-jpeg" => Some(Self::Image(ImageFormat::Jpeg)),
|
||||
b"i-jxl" => Some(Self::Image(ImageFormat::Jxl)),
|
||||
b"i-png" => Some(Self::Image(ImageFormat::Png)),
|
||||
b"i-webp" => Some(Self::Image(ImageFormat::Webp)),
|
||||
b"v-mp4" => Some(Self::Video(InternalVideoFormat::Mp4)),
|
||||
b"v-webm" => Some(Self::Video(InternalVideoFormat::Webm)),
|
||||
pub(crate) const fn from_byte(byte: u8) -> Option<Self> {
|
||||
match byte {
|
||||
0 => Some(Self::Animation(AnimationFormat::Apng)),
|
||||
1 => Some(Self::Animation(AnimationFormat::Avif)),
|
||||
2 => Some(Self::Animation(AnimationFormat::Gif)),
|
||||
3 => Some(Self::Animation(AnimationFormat::Webp)),
|
||||
4 => Some(Self::Image(ImageFormat::Avif)),
|
||||
5 => Some(Self::Image(ImageFormat::Jpeg)),
|
||||
6 => Some(Self::Image(ImageFormat::Jxl)),
|
||||
7 => Some(Self::Image(ImageFormat::Png)),
|
||||
8 => Some(Self::Image(ImageFormat::Webp)),
|
||||
9 => Some(Self::Video(InternalVideoFormat::Mp4)),
|
||||
10 => Some(Self::Video(InternalVideoFormat::Webm)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -612,7 +612,7 @@ async fn page(
|
|||
) -> Result<HttpResponse, Error> {
|
||||
let limit = limit.unwrap_or(20);
|
||||
|
||||
let page = repo.hash_page(slug.clone(), limit).await?;
|
||||
let page = repo.hash_page(slug, limit).await?;
|
||||
|
||||
let mut hashes = Vec::with_capacity(page.hashes.len());
|
||||
|
||||
|
@ -641,7 +641,7 @@ async fn page(
|
|||
|
||||
let page = PageJson {
|
||||
limit: page.limit,
|
||||
current: slug,
|
||||
current: page.current(),
|
||||
prev: page.prev(),
|
||||
next: page.next(),
|
||||
hashes,
|
||||
|
|
41
src/repo.rs
41
src/repo.rs
|
@ -508,34 +508,33 @@ pub(crate) struct OrderedHash {
|
|||
|
||||
pub(crate) struct HashPage {
|
||||
pub(crate) limit: usize,
|
||||
prev: Option<OrderedHash>,
|
||||
next: Option<OrderedHash>,
|
||||
prev: Option<Hash>,
|
||||
next: Option<Hash>,
|
||||
pub(crate) hashes: Vec<Hash>,
|
||||
}
|
||||
|
||||
fn ordered_hash_to_string(OrderedHash { timestamp, hash }: &OrderedHash) -> String {
|
||||
let mut bytes: Vec<u8> = timestamp.unix_timestamp_nanos().to_be_bytes().into();
|
||||
bytes.extend(hash.to_bytes());
|
||||
base64::prelude::BASE64_URL_SAFE.encode(bytes)
|
||||
fn hash_to_slug(hash: &Hash) -> String {
|
||||
base64::prelude::BASE64_URL_SAFE.encode(hash.to_bytes())
|
||||
}
|
||||
|
||||
fn ordered_hash_from_string(s: &str) -> Option<OrderedHash> {
|
||||
fn hash_from_slug(s: &str) -> Option<Hash> {
|
||||
let bytes = base64::prelude::BASE64_URL_SAFE.decode(s).ok()?;
|
||||
let timestamp: [u8; 16] = bytes[0..16].try_into().ok()?;
|
||||
let timestamp = i128::from_be_bytes(timestamp);
|
||||
let timestamp = time::OffsetDateTime::from_unix_timestamp_nanos(timestamp).ok()?;
|
||||
let hash = Hash::from_bytes(&bytes[16..])?;
|
||||
let hash = Hash::from_bytes(&bytes)?;
|
||||
|
||||
Some(OrderedHash { timestamp, hash })
|
||||
Some(hash)
|
||||
}
|
||||
|
||||
impl HashPage {
|
||||
pub(crate) fn current(&self) -> Option<String> {
|
||||
self.hashes.first().map(hash_to_slug)
|
||||
}
|
||||
|
||||
pub(crate) fn next(&self) -> Option<String> {
|
||||
self.next.as_ref().map(ordered_hash_to_string)
|
||||
self.next.as_ref().map(hash_to_slug)
|
||||
}
|
||||
|
||||
pub(crate) fn prev(&self) -> Option<String> {
|
||||
self.prev.as_ref().map(ordered_hash_to_string)
|
||||
self.prev.as_ref().map(hash_to_slug)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -546,11 +545,19 @@ pub(crate) trait HashRepo: BaseRepo {
|
|||
async fn hashes(&self) -> LocalBoxStream<'static, Result<Hash, RepoError>>;
|
||||
|
||||
async fn hash_page(&self, slug: Option<String>, limit: usize) -> Result<HashPage, RepoError> {
|
||||
let bound = slug.as_deref().and_then(ordered_hash_from_string);
|
||||
let hash = slug.as_deref().and_then(hash_from_slug);
|
||||
|
||||
let bound = if let Some(hash) = hash {
|
||||
self.bound(hash).await?
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
self.hashes_ordered(bound, limit).await
|
||||
}
|
||||
|
||||
async fn bound(&self, hash: Hash) -> Result<Option<OrderedHash>, RepoError>;
|
||||
|
||||
async fn hashes_ordered(
|
||||
&self,
|
||||
bound: Option<OrderedHash>,
|
||||
|
@ -618,6 +625,10 @@ where
|
|||
T::hashes(self).await
|
||||
}
|
||||
|
||||
async fn bound(&self, hash: Hash) -> Result<Option<OrderedHash>, RepoError> {
|
||||
T::bound(self, hash).await
|
||||
}
|
||||
|
||||
async fn hashes_ordered(
|
||||
&self,
|
||||
bound: Option<OrderedHash>,
|
||||
|
|
|
@ -31,13 +31,13 @@ impl Hash {
|
|||
}
|
||||
|
||||
pub(super) fn to_bytes(&self) -> Vec<u8> {
|
||||
let format = self.format.to_bytes();
|
||||
let format_byte = self.format.to_byte();
|
||||
|
||||
let mut vec = Vec::with_capacity(32 + 8 + format.len());
|
||||
let mut vec = Vec::with_capacity(32 + 6 + 1);
|
||||
|
||||
vec.extend_from_slice(&self.hash[..]);
|
||||
vec.extend(self.size.to_be_bytes());
|
||||
vec.extend(format);
|
||||
vec.extend_from_slice(&self.size.to_be_bytes()[2..]);
|
||||
vec.push(format_byte);
|
||||
|
||||
vec
|
||||
}
|
||||
|
@ -51,17 +51,18 @@ impl Hash {
|
|||
}
|
||||
|
||||
pub(super) fn from_bytes(bytes: &[u8]) -> Option<Self> {
|
||||
if bytes.len() < 32 + 8 + 5 {
|
||||
if bytes.len() != 32 + 6 + 1 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let hash = &bytes[..32];
|
||||
let size = &bytes[32..40];
|
||||
let format = &bytes[40..];
|
||||
let size_bytes = &bytes[32..38];
|
||||
let format_byte = bytes[38];
|
||||
|
||||
let hash: [u8; 32] = hash.try_into().expect("Correct length");
|
||||
let size: [u8; 8] = size.try_into().expect("Correct length");
|
||||
let format = InternalFormat::from_bytes(format)?;
|
||||
let mut size = [0u8; 8];
|
||||
size[2..].copy_from_slice(size_bytes);
|
||||
let format = InternalFormat::from_byte(format_byte)?;
|
||||
|
||||
Some(Self {
|
||||
hash: Arc::new(hash),
|
||||
|
|
|
@ -1046,6 +1046,12 @@ impl HashRepo for SledRepo {
|
|||
Box::pin(from_iterator(iter, 8))
|
||||
}
|
||||
|
||||
async fn bound(&self, hash: Hash) -> Result<Option<OrderedHash>, RepoError> {
|
||||
let opt = b!(self.hashes, hashes.get(hash.to_ivec()));
|
||||
|
||||
Ok(opt.and_then(parse_ordered_hash))
|
||||
}
|
||||
|
||||
async fn hashes_ordered(
|
||||
&self,
|
||||
bound: Option<OrderedHash>,
|
||||
|
@ -1091,8 +1097,8 @@ impl HashRepo for SledRepo {
|
|||
|
||||
Ok(HashPage {
|
||||
limit,
|
||||
prev,
|
||||
next,
|
||||
prev: prev.map(|OrderedHash { hash, .. }| hash),
|
||||
next: next.map(|OrderedHash { hash, .. }| hash),
|
||||
hashes: hashes
|
||||
.into_iter()
|
||||
.map(|OrderedHash { hash, .. }| hash)
|
||||
|
|
Loading…
Reference in a new issue