loading by offset on profile

This commit is contained in:
Tyler Murphy 2023-02-02 11:29:37 -05:00
parent afc4ba3d4d
commit 18a27f62be
7 changed files with 65 additions and 41 deletions

View file

@ -59,8 +59,8 @@ const loadpostspage = async (page) => {
return await request('/posts/page', {page}) return await request('/posts/page', {page})
} }
const loadusersposts = async (user_id) => { const loadusersposts = async (user_id, page) => {
return await request('/posts/user', {user_id}) return await request('/posts/user', {user_id, page})
} }
const loadusers = async (ids) => { const loadusers = async (ids) => {

View file

@ -88,8 +88,12 @@ function render() {
<div id="posts" class="${posts ? '' : 'hidden'}"> <div id="posts" class="${posts ? '' : 'hidden'}">
${data.posts.map(p => parsePost(p)).join('')} ${data.posts.map(p => parsePost(p)).join('')}
</div> </div>
<div id="load">
<a class="bold gtext" onclick="loadMore()">Load more posts</a>
</div>
` `
append(postsh) append(postsh)
const about = ` const about = `
@ -129,42 +133,29 @@ async function logout_button() {
location.href = '/login' location.href = '/login'
} }
async function loadMore() {
const posts = await load()
data.posts.push(... posts)
const posts_block = document.getElementById("posts")
for (p of posts) {
append(parsePost(p), posts_block)
}
}
var posts = true var posts = true
var isself = false var isself = false
var page = 0
var id
async function load() { async function load() {
const posts = (await loadusersposts(id, page)).json
var params = {}; if (posts.length === 0) {
for (const [key, value] of new URLSearchParams(location.search)) { page = -1
params[key] = value remove('load')
}
let request = await loadself()
if (request.status === 429) {
header(false, false)
throw new Error("Rate limited");
}
data.self = request.json;
data.users[data.self.user_id] = data.self
let id;
header(false, false, data.self.user_id)
if (params.id !== undefined && !isNaN(params.id)) {
id = parseInt(params.id);
} else { } else {
id = data.self.user_id page++
} }
let batch = []
isself = id === data.self.user_id
const posts = (await loadusersposts(id)).json
data.posts.push(... posts)
const batch = []
if (!isself) { if (!isself) {
batch.push(id) batch.push(id)
} }
@ -182,8 +173,39 @@ async function load() {
for (const user of users) { for (const user of users) {
data.users[user.user_id] = user data.users[user.user_id] = user
} }
return posts
}
async function init() {
let request = await loadself()
if (request.status === 429) {
header(false, false)
throw new Error("Rate limited");
}
data.self = request.json;
data.users[data.self.user_id] = data.self
header(false, false, data.self.user_id)
var params = {};
for (const [key, value] of new URLSearchParams(location.search)) {
params[key] = value
}
if (params.id !== undefined && !isNaN(params.id)) {
id = parseInt(params.id);
} else {
id = data.self.user_id
}
isself = id === data.self.user_id
const posts = await load()
data.posts.push(... posts)
data.user = data.users[id] data.user = data.users[id]
render() render()
} }
load() init()

View file

@ -16,7 +16,7 @@ pub use auth::RegistrationRequet;
pub fn router() -> Router { pub fn router() -> Router {
let governor_conf = Box::new( let governor_conf = Box::new(
GovernorConfigBuilder::default() GovernorConfigBuilder::default()
.burst_size(10) .burst_size(1000)
.per_second(1) .per_second(1)
.key_extractor(SmartIpKeyExtractor) .key_extractor(SmartIpKeyExtractor)
.finish() .finish()

View file

@ -72,6 +72,7 @@ async fn page(
#[derive(Deserialize)] #[derive(Deserialize)]
struct UsersPostsRequest { struct UsersPostsRequest {
user_id: u64, user_id: u64,
page: u64
} }
impl Check for UsersPostsRequest { impl Check for UsersPostsRequest {
@ -84,7 +85,7 @@ async fn user(
AuthorizedUser(_user): AuthorizedUser, AuthorizedUser(_user): AuthorizedUser,
Json(body): Json<UsersPostsRequest>, Json(body): Json<UsersPostsRequest>,
) -> Response { ) -> Response {
let Ok(posts) = Post::from_user_id(body.user_id) else { let Ok(posts) = Post::from_user_post_page(body.user_id, body.page) else {
return ResponseCode::InternalServerError.text("Failed to fetch posts") return ResponseCode::InternalServerError.text("Failed to fetch posts")
}; };

View file

@ -90,11 +90,12 @@ pub fn get_all_posts() -> Result<Vec<Post>, rusqlite::Error> {
} }
#[instrument()] #[instrument()]
pub fn get_users_posts(user_id: u64) -> Result<Vec<Post>, rusqlite::Error> { pub fn get_users_post_page(user_id: u64, page: u64) -> Result<Vec<Post>, rusqlite::Error> {
tracing::trace!("Retrieving users posts"); tracing::trace!("Retrieving users posts");
let page_size = 10;
let conn = database::connect()?; let conn = database::connect()?;
let mut stmt = conn.prepare("SELECT * FROM posts WHERE user_id = ? ORDER BY post_id DESC")?; let mut stmt = conn.prepare("SELECT * FROM posts WHERE user_id = ? ORDER BY post_id DESC LIMIT ? OFFSET ?")?;
let row = stmt.query_map([user_id], |row| { let row = stmt.query_map([user_id, page_size, page_size * page], |row| {
let row = post_from_row(row)?; let row = post_from_row(row)?;
Ok(row) Ok(row)
})?; })?;

View file

@ -24,7 +24,7 @@ pub mod pages;
pub fn router() -> Router { pub fn router() -> Router {
let governor_conf = Box::new( let governor_conf = Box::new(
GovernorConfigBuilder::default() GovernorConfigBuilder::default()
.burst_size(20) .burst_size(20000)
.per_second(1) .per_second(1)
.key_extractor(SmartIpKeyExtractor) .key_extractor(SmartIpKeyExtractor)
.finish() .finish()

View file

@ -43,8 +43,8 @@ impl Post {
} }
#[instrument()] #[instrument()]
pub fn from_user_id(user_id: u64) -> Result<Vec<Self>> { pub fn from_user_post_page(user_id: u64, page: u64) -> Result<Vec<Self>> {
let Ok(posts) = database::posts::get_users_posts(user_id) else { let Ok(posts) = database::posts::get_users_post_page(user_id, page) else {
return Err(ResponseCode::BadRequest.text("Failed to fetch posts")) return Err(ResponseCode::BadRequest.text("Failed to fetch posts"))
}; };
Ok(posts) Ok(posts)