fix: Fix pagination tokens being corrupted for backfilled PDUs

This commit is contained in:
Ginger 2025-09-04 10:33:43 -04:00 committed by nex
commit 16f4efa708
6 changed files with 18 additions and 36 deletions

View file

@ -35,7 +35,7 @@ use ruma::{
}; };
use tracing::warn; use tracing::warn;
use super::utils::{count_to_token, parse_pagination_token as parse_token}; use super::utils::{count_to_pagination_token, pagination_token_to_count as parse_token};
use crate::Ruma; use crate::Ruma;
/// list of safe and common non-state events to ignore if the user is ignored /// list of safe and common non-state events to ignore if the user is ignored
@ -181,8 +181,8 @@ pub(crate) async fn get_message_events_route(
.collect(); .collect();
Ok(get_message_events::v3::Response { Ok(get_message_events::v3::Response {
start: count_to_token(from), start: count_to_pagination_token(from),
end: next_token.map(count_to_token), end: next_token.map(count_to_pagination_token),
chunk, chunk,
state, state,
}) })

View file

@ -18,7 +18,7 @@ use ruma::{
events::{TimelineEventType, relation::RelationType}, events::{TimelineEventType, relation::RelationType},
}; };
use super::utils::{count_to_token, parse_pagination_token as parse_token}; use super::utils::{count_to_pagination_token, pagination_token_to_count as parse_token};
use crate::Ruma; use crate::Ruma;
/// # `GET /_matrix/client/r0/rooms/{roomId}/relations/{eventId}/{relType}/{eventType}` /// # `GET /_matrix/client/r0/rooms/{roomId}/relations/{eventId}/{relType}/{eventType}`
@ -193,7 +193,7 @@ async fn paginate_relations_with_filter(
| Direction::Forward => events.last(), | Direction::Forward => events.last(),
| Direction::Backward => events.first(), | Direction::Backward => events.first(),
} }
.map(|(count, _)| count_to_token(*count)) .map(|(count, _)| count_to_pagination_token(*count))
} else { } else {
None None
}; };

View file

@ -9,7 +9,7 @@ use conduwuit::{
use futures::StreamExt; use futures::StreamExt;
use ruma::{api::client::threads::get_threads, uint}; use ruma::{api::client::threads::get_threads, uint};
use crate::Ruma; use crate::{Ruma, client::utils::pagination_token_to_count};
/// # `GET /_matrix/client/r0/rooms/{roomId}/threads` /// # `GET /_matrix/client/r0/rooms/{roomId}/threads`
pub(crate) async fn get_threads_route( pub(crate) async fn get_threads_route(
@ -27,7 +27,7 @@ pub(crate) async fn get_threads_route(
let from: PduCount = body let from: PduCount = body
.from .from
.as_deref() .as_deref()
.map(str::parse) .map(pagination_token_to_count)
.transpose()? .transpose()?
.unwrap_or_else(PduCount::max); .unwrap_or_else(PduCount::max);

View file

@ -1,28 +1,7 @@
use conduwuit::{ use conduwuit::{Result, matrix::pdu::PduCount};
Result, err,
matrix::pdu::{PduCount, ShortEventId},
};
/// Parse a pagination token, trying ShortEventId first, then falling back to /// Parse a pagination token
/// PduCount pub(crate) fn pagination_token_to_count(token: &str) -> Result<PduCount> { token.parse() }
pub(crate) fn parse_pagination_token(token: &str) -> Result<PduCount> {
// Try parsing as ShortEventId first
if let Ok(shorteventid) = token.parse::<ShortEventId>() {
// ShortEventId maps directly to a PduCount in our database
Ok(PduCount::Normal(shorteventid))
} else if let Ok(count) = token.parse::<u64>() {
// Fallback to PduCount for backwards compatibility
Ok(PduCount::Normal(count))
} else if let Ok(count) = token.parse::<i64>() {
// Also handle negative counts for backfilled events
Ok(PduCount::from_signed(count))
} else {
Err(err!(Request(InvalidParam("Invalid pagination token"))))
}
}
/// Convert a PduCount to a token string (using the underlying ShortEventId) /// Convert a PduCount to a token string
pub(crate) fn count_to_token(count: PduCount) -> String { pub(crate) fn count_to_pagination_token(count: PduCount) -> String { count.to_string() }
// The PduCount's unsigned value IS the ShortEventId
count.into_unsigned().to_string()
}

View file

@ -1,6 +1,10 @@
#![allow(clippy::cast_possible_wrap, clippy::cast_sign_loss, clippy::as_conversions)] #![allow(clippy::cast_possible_wrap, clippy::cast_sign_loss, clippy::as_conversions)]
use std::{cmp::Ordering, fmt, fmt::Display, str::FromStr}; use std::{
cmp::Ordering,
fmt::{self, Display},
str::FromStr,
};
use ruma::api::Direction; use ruma::api::Direction;

View file

@ -3,8 +3,7 @@ use std::{borrow::Borrow, sync::Arc};
use conduwuit::{ use conduwuit::{
Err, PduCount, PduEvent, Result, at, err, Err, PduCount, PduEvent, Result, at, err,
result::{LogErr, NotFound}, result::{LogErr, NotFound},
utils, utils::{self, stream::TryReadyExt},
utils::stream::TryReadyExt,
}; };
use database::{Database, Deserialized, Json, KeyVal, Map}; use database::{Database, Deserialized, Json, KeyVal, Map};
use futures::{FutureExt, Stream, TryFutureExt, TryStreamExt, future::select_ok, pin_mut}; use futures::{FutureExt, Stream, TryFutureExt, TryStreamExt, future::select_ok, pin_mut};