diff options
| author | metamuffin <metamuffin@disroot.org> | 2026-02-26 03:02:24 +0100 |
|---|---|---|
| committer | metamuffin <metamuffin@disroot.org> | 2026-02-26 03:02:24 +0100 |
| commit | eb6648770e7de66ccafe44d114ecbb2c1eaf444d (patch) | |
| tree | 2bce9f579b3ea7313f84df94b27fad813c66e9e1 /server/src | |
| parent | 7f7deec27e69ed110c52caddaa3a0c04430e71d9 (diff) | |
| download | jellything-eb6648770e7de66ccafe44d114ecbb2c1eaf444d.tar jellything-eb6648770e7de66ccafe44d114ecbb2c1eaf444d.tar.bz2 jellything-eb6648770e7de66ccafe44d114ecbb2c1eaf444d.tar.zst | |
implement application-side continuation tokens
Diffstat (limited to 'server/src')
| -rw-r--r-- | server/src/auth.rs | 4 | ||||
| -rw-r--r-- | server/src/compat/youtube.rs | 4 | ||||
| -rw-r--r-- | server/src/logic/stream.rs | 4 | ||||
| -rw-r--r-- | server/src/main.rs | 4 | ||||
| -rw-r--r-- | server/src/routes.rs | 2 | ||||
| -rw-r--r-- | server/src/ui/account/mod.rs | 4 | ||||
| -rw-r--r-- | server/src/ui/account/settings.rs | 4 | ||||
| -rw-r--r-- | server/src/ui/admin/users.rs | 6 | ||||
| -rw-r--r-- | server/src/ui/items.rs | 69 | ||||
| -rw-r--r-- | server/src/ui/mod.rs | 1 | ||||
| -rw-r--r-- | server/src/ui/node.rs | 4 | ||||
| -rw-r--r-- | server/src/ui/player.rs | 4 |
12 files changed, 70 insertions, 40 deletions
diff --git a/server/src/auth.rs b/server/src/auth.rs index 26da82b..d973dfc 100644 --- a/server/src/auth.rs +++ b/server/src/auth.rs @@ -11,7 +11,7 @@ use jellycommon::{ jellyobject::{ObjectBuffer, Path}, *, }; -use jellydb::{Filter, Query, Sort}; +use jellydb::{Filter, Query}; pub fn token_to_user(state: &State, token: &str) -> Result<ObjectBuffer> { let user_row = token::validate(&state.session_key, token)?; @@ -38,7 +38,7 @@ pub fn login( state.database.transaction(&mut |txn| { user_row = txn.query_single(Query { filter: Filter::Match(Path(vec![USER_LOGIN.0]), username.into()), - sort: Sort::None, + ..Default::default() })?; if let Some(ur) = user_row { user = txn.get(ur)?; diff --git a/server/src/compat/youtube.rs b/server/src/compat/youtube.rs index a5f540b..4ba3dc8 100644 --- a/server/src/compat/youtube.rs +++ b/server/src/compat/youtube.rs @@ -8,7 +8,7 @@ use anyhow::anyhow; use jellycommon::{ IDENT_YOUTUBE_VIDEO, NO_IDENTIFIERS, NO_SLUG, jellyobject::Path, routes::u_node_id, }; -use jellydb::{Filter, Query, Sort}; +use jellydb::{Filter, Query}; use rocket::{get, response::Redirect}; #[get("/watch?<v>")] @@ -23,7 +23,7 @@ pub fn r_youtube_watch(ri: RequestInfo<'_>, v: &str) -> MyResult<Redirect> { Path(vec![NO_IDENTIFIERS.0, IDENT_YOUTUBE_VIDEO.0]), v.into(), ), - sort: Sort::None, + ..Default::default() })? { res = txn.get(row)?; } diff --git a/server/src/logic/stream.rs b/server/src/logic/stream.rs index 6f0fdc4..e332811 100644 --- a/server/src/logic/stream.rs +++ b/server/src/logic/stream.rs @@ -9,7 +9,7 @@ use jellycommon::{ NO_SLUG, NO_TITLE, NO_TRACK, TR_SOURCE, TRSOURCE_LOCAL_PATH, jellyobject::Path, stream::StreamSpec, }; -use jellydb::{Filter, Query, Sort}; +use jellydb::{Filter, Query}; use jellystream::SMediaInfo; use log::{info, warn}; use rocket::{ @@ -58,7 +58,7 @@ pub async fn r_stream( ri.state.database.transaction(&mut |txn| { if let Some(row) = txn.query_single(Query { filter: Filter::Match(Path(vec![NO_SLUG.0]), slug.into()), - sort: Sort::None, + ..Default::default() })? { node = txn.get(row)?; } diff --git a/server/src/main.rs b/server/src/main.rs index cbad704..f3eabcf 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -17,7 +17,7 @@ use jellycommon::{ USER_ADMIN, USER_LOGIN, USER_PASSWORD, jellyobject::{ObjectBuffer, Path}, }; -use jellydb::{Database, Filter, Query, Sort}; +use jellydb::{Database, Filter, Query}; use log::{error, info}; use routes::build_rocket; use serde::Deserialize; @@ -102,7 +102,7 @@ fn create_admin_user(state: &State) -> Result<()> { state.database.transaction(&mut |txn| { let admin_row = txn.query_single(Query { filter: Filter::Match(Path(vec![USER_LOGIN.0]), "admin".into()), - sort: Sort::None, + ..Default::default() })?; if admin_row.is_none() { info!("Creating new admin user"); diff --git a/server/src/routes.rs b/server/src/routes.rs index f17952a..fc1d5e6 100644 --- a/server/src/routes.rs +++ b/server/src/routes.rs @@ -25,6 +25,7 @@ use crate::{ assets::{r_image, r_image_fallback_person}, error::{r_api_catch, r_catch}, home::r_home, + items::r_items, node::r_node, player::r_player, r_favicon, r_index, @@ -101,6 +102,7 @@ pub(super) fn build_rocket(state: Arc<State>) -> Rocket<Build> { r_image_fallback_person, r_image, r_index, + r_items, r_node, r_player, r_playersync, diff --git a/server/src/ui/account/mod.rs b/server/src/ui/account/mod.rs index 837d49a..ab5093d 100644 --- a/server/src/ui/account/mod.rs +++ b/server/src/ui/account/mod.rs @@ -20,7 +20,7 @@ use jellycommon::{ routes::{u_account_login, u_home}, *, }; -use jellydb::{Filter, Query, Sort}; +use jellydb::{Filter, Query}; use rocket::{ Either, FromForm, form::{Contextual, Form}, @@ -74,7 +74,7 @@ pub fn r_account_login_post( ri.state.database.transaction(&mut |txn| { let user_row = txn.query_single(Query { filter: Filter::Match(Path(vec![USER_LOGIN.0]), form.username.clone().into()), - sort: Sort::None, + ..Default::default() })?; if let Some(ur) = user_row { let mut user = txn.get(ur)?.unwrap(); diff --git a/server/src/ui/account/settings.rs b/server/src/ui/account/settings.rs index bb4b323..c1068f6 100644 --- a/server/src/ui/account/settings.rs +++ b/server/src/ui/account/settings.rs @@ -13,7 +13,7 @@ use jellycommon::{ routes::u_account_settings, *, }; -use jellydb::{Filter, Query, Sort}; +use jellydb::{Filter, Query}; use jellyui::tr; use rocket::{ FromForm, @@ -112,7 +112,7 @@ fn update_user(ri: &RequestInfo, update: impl Fn(Object) -> ObjectBuffer) -> MyR let user_row = txn .query_single(Query { filter: Filter::Match(Path(vec![USER_LOGIN.0]), login.into()), - sort: Sort::None, + ..Default::default() })? .ok_or(anyhow!("user vanished"))?; diff --git a/server/src/ui/admin/users.rs b/server/src/ui/admin/users.rs index 654a6b9..172facc 100644 --- a/server/src/ui/admin/users.rs +++ b/server/src/ui/admin/users.rs @@ -12,7 +12,7 @@ use jellycommon::{ routes::u_admin_users, *, }; -use jellydb::{Filter, Query, Sort}; +use jellydb::{Filter, Query}; use jellyui::tr; use rand::random; use rocket::{ @@ -88,8 +88,8 @@ pub fn r_admin_user(ri: RequestInfo<'_>, name: &str) -> MyResult<UiResponse> { let mut page = OBB::new(); ri.state.database.transaction(&mut |txn| { if let Some(row) = txn.query_single(Query { - sort: Sort::None, filter: Filter::Match(Path(vec![USER_LOGIN.0]), name.into()), + ..Default::default() })? { let user = txn.get(row)?.unwrap(); page = OBB::new(); @@ -106,8 +106,8 @@ pub fn r_admin_user_remove(ri: RequestInfo<'_>, name: &str) -> MyResult<Flash<Re ri.require_admin()?; ri.state.database.transaction(&mut |txn| { if let Some(row) = txn.query_single(Query { - sort: Sort::None, filter: Filter::Match(Path(vec![USER_LOGIN.0]), name.into()), + ..Default::default() })? { txn.remove(row)?; } diff --git a/server/src/ui/items.rs b/server/src/ui/items.rs index cc8c18f..6383830 100644 --- a/server/src/ui/items.rs +++ b/server/src/ui/items.rs @@ -3,27 +3,52 @@ which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2026 metamuffin <metamuffin.org> */ -use super::error::MyError; -use rocket::{Either, get, response::content::RawHtml, serde::json::Json}; -#[get("/items?<page>&<filter..>")] -pub fn r_items( - ri: RequestInfo, - page: Option<usize>, - filter: ANodeFilterSort, -) -> Result<Either<RawHtml<String>, Json<ApiItemsResponse>>, MyError> { - let r = all_items(&ri.session, page, filter.clone().into())?; - Ok(if matches!(ri.accept, Accept::Json) { - Either::Right(Json(r)) - } else { - Either::Left(RawHtml(render_page( - &ItemsPage { - lang: &ri.lang, - r, - filter: &filter.clone().into(), - page: page.unwrap_or(0), - }, - ri.render_info(), - ))) - }) +use crate::{request_info::RequestInfo, ui::error::MyResult, ui_responder::UiResponse}; +use anyhow::anyhow; +use base64::{Engine, prelude::BASE64_URL_SAFE}; +use jellycommon::{ + jellyobject::{OBB, Path}, + *, +}; +use jellydb::{Filter, Query}; +use rocket::get; + +#[get("/items?<cont>")] +pub fn r_items(ri: RequestInfo, cont: Option<&str>) -> MyResult<UiResponse> { + let cont = cont + .map(|s| BASE64_URL_SAFE.decode(s)) + .transpose() + .map_err(|_| anyhow!("invalid contination token"))?; + + let mut page = OBB::new(); + ri.state.database.transaction(&mut |txn| { + let rows = txn + .query(Query { + filter: Filter::Has(Path(vec![NO_SLUG.0])), + continuation: cont.clone(), + ..Default::default() + })? + .take(64) + .collect::<Result<Vec<_>, _>>()?; + + let mut list = OBB::new() + .with(NODELIST_DISPLAYSTYLE, NLSTYLE_GRID) + .with(NODELIST_TITLE, "items"); + + let mut iterstate = Vec::new(); + for (r, is) in rows { + let node = txn.get(r)?.unwrap(); + let nku = OBB::new().with(NKU_NODE, node.as_object()).finish(); + list.push(NODELIST_ITEM, nku.as_object()); + iterstate = is; + } + list.push(NODELIST_CONTINUATION, &BASE64_URL_SAFE.encode(iterstate)); + + page = OBB::new(); + page.push(VIEW_NODE_LIST, list.finish().as_object()); + + Ok(()) + })?; + Ok(ri.respond_ui(page)) } diff --git a/server/src/ui/mod.rs b/server/src/ui/mod.rs index 27535fa..6cb3cd2 100644 --- a/server/src/ui/mod.rs +++ b/server/src/ui/mod.rs @@ -18,6 +18,7 @@ pub mod home; pub mod node; pub mod player; pub mod style; +pub mod items; #[get("/")] pub async fn r_index(ri: RequestInfo<'_>) -> MyResult<Redirect> { diff --git a/server/src/ui/node.rs b/server/src/ui/node.rs index 509e9ae..55a1d09 100644 --- a/server/src/ui/node.rs +++ b/server/src/ui/node.rs @@ -23,7 +23,7 @@ pub fn r_node(ri: RequestInfo<'_>, slug: &str) -> MyResult<UiResponse> { ri.state.database.transaction(&mut |txn| { if let Some(row) = txn.query_single(Query { filter: Filter::Match(Path(vec![NO_SLUG.0]), slug.into()), - sort: Sort::None, + ..Default::default() })? { let n = txn.get(row)?.unwrap(); let nku = Object::EMPTY.insert(NKU_NODE, n.as_object()); @@ -78,6 +78,7 @@ fn c_children( Filter::Match(Path(vec![NO_VISIBILITY.0]), VISI_VISIBLE.into()), Filter::Match(Path(vec![NO_PARENT.0]), row.into()), ]), + ..Default::default() })? .collect::<Result<Vec<_>>>()?; @@ -163,6 +164,7 @@ fn c_credited(page: &mut ObjectBufferBuilder, txn: &mut dyn Transaction, row: u6 Filter::Match(Path(vec![NO_VISIBILITY.0]), VISI_VISIBLE.into()), Filter::Match(Path(vec![NO_CREDIT.0, CR_NODE.0]), row.into()), ]), + ..Default::default() })? .collect::<Result<Vec<_>>>()?; diff --git a/server/src/ui/player.rs b/server/src/ui/player.rs index 4c592e4..f0d6dea 100644 --- a/server/src/ui/player.rs +++ b/server/src/ui/player.rs @@ -9,7 +9,7 @@ use jellycommon::{ jellyobject::{OBB, Object, Path}, *, }; -use jellydb::{Filter, Query, Sort}; +use jellydb::{Filter, Query}; use rocket::get; // fn jellynative_url(action: &str, seek: f64, secret: &str, node: &str, session: &str) -> String { @@ -34,7 +34,7 @@ pub fn r_player(ri: RequestInfo<'_>, t: Option<f64>, slug: &str) -> MyResult<UiR ri.state.database.transaction(&mut |txn| { if let Some(row) = txn.query_single(Query { filter: Filter::Match(Path(vec![NO_SLUG.0]), slug.into()), - sort: Sort::None, + ..Default::default() })? { let n = txn.get(row)?.unwrap(); let nku = Object::EMPTY.insert(NKU_NODE, n.as_object()); |