refactor(webapi)!: avoid u64/i64 usage in types except timestamp

We do not need that many big numbers yet. This should simplify client
implementation without native u64 (eg. JavaScript).

Also put a hard limit on `unseen_cnt` query.
This commit is contained in:
oxalica 2024-09-21 15:12:17 -04:00
parent ad3e422902
commit a7f31e5fad
3 changed files with 19 additions and 18 deletions

View file

@ -405,7 +405,7 @@ pub struct RoomMetadata {
/// `last_msg.cid`. /// `last_msg.cid`.
/// This may or may not be a precise number. /// This may or may not be a precise number.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub unseen_cnt: Option<u64>, pub unseen_cnt: Option<u32>,
/// The member permission of current user in the room, or `None` if it is not a member. /// The member permission of current user in the room, or `None` if it is not a member.
/// Only available with authentication. /// Only available with authentication.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
@ -508,7 +508,7 @@ pub enum RoomAdminOp {
bitflags::bitflags! { bitflags::bitflags! {
/// TODO: Is this a really all about permission, or is a generic `UserFlags`? /// TODO: Is this a really all about permission, or is a generic `UserFlags`?
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ServerPermission: u64 { pub struct ServerPermission: i32 {
const CREATE_ROOM = 1 << 0; const CREATE_ROOM = 1 << 0;
const ACCEPT_PEER_CHAT = 1 << 16; const ACCEPT_PEER_CHAT = 1 << 16;
@ -517,7 +517,7 @@ bitflags::bitflags! {
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MemberPermission: u64 { pub struct MemberPermission: i32 {
const POST_CHAT = 1 << 0; const POST_CHAT = 1 << 0;
const ADD_MEMBER = 1 << 1; const ADD_MEMBER = 1 << 1;
const DELETE_ROOM = 1 << 2; const DELETE_ROOM = 1 << 2;
@ -529,7 +529,7 @@ bitflags::bitflags! {
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct RoomAttrs: u64 { pub struct RoomAttrs: i32 {
// NB. Used by schema. // NB. Used by schema.
const PUBLIC_READABLE = 1 << 0; const PUBLIC_READABLE = 1 << 0;
const PUBLIC_JOINABLE = 1 << 1; const PUBLIC_JOINABLE = 1 << 1;
@ -597,27 +597,25 @@ mod sql_impl {
} }
} }
macro_rules! impl_u64_flag { macro_rules! impl_flag_to_from_sql {
($($name:ident),*) => { ($($name:ident),*) => {
$( $(
impl ToSql for $name { impl ToSql for $name {
fn to_sql(&self) -> Result<ToSqlOutput<'_>> { fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
// Cast out the sign. Ok(self.bits().into())
Ok((self.bits() as i64).into())
} }
} }
impl FromSql for $name { impl FromSql for $name {
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
// Cast out the sign. i32::column_result(value).map($name::from_bits_retain)
i64::column_result(value).map(|v| $name::from_bits_retain(v as u64))
} }
} }
)* )*
}; };
} }
impl_u64_flag!(ServerPermission, MemberPermission, RoomAttrs); impl_flag_to_from_sql!(ServerPermission, MemberPermission, RoomAttrs);
} }
#[cfg(test)] #[cfg(test)]

View file

@ -19,6 +19,7 @@ mod tests;
const DEFAULT_DATABASE_PATH: &str = "/var/lib/blahd/db.sqlite"; const DEFAULT_DATABASE_PATH: &str = "/var/lib/blahd/db.sqlite";
const STMT_CACHE_CAPACITY: usize = 24; const STMT_CACHE_CAPACITY: usize = 24;
const UNSEEN_CNT_LIMIT: u32 = 999;
static INIT_SQL: &str = include_str!("../schema.sql"); static INIT_SQL: &str = include_str!("../schema.sql");
@ -345,7 +346,6 @@ pub trait TransactionOps {
start_rid: Id, start_rid: Id,
page_len: usize, page_len: usize,
) -> Result<Vec<RoomMetadata>> { ) -> Result<Vec<RoomMetadata>> {
// FIXME: Limit `unseen_cnt` counting.
prepare_cached_and_bind!( prepare_cached_and_bind!(
self.conn(), self.conn(),
r" r"
@ -354,10 +354,13 @@ pub trait TransactionOps {
`cid`, `timestamp`, `nonce`, `sig`, `rich_text`, `cid`, `timestamp`, `nonce`, `sig`, `rich_text`,
`last_author`.`id_key`, `msg`.`act_key`, `last_author`.`id_key`, `msg`.`act_key`,
`peer_user`.`id_key` AS `peer_id_key`, `peer_user`.`id_key` AS `peer_id_key`,
(SELECT COUNT(*) (SELECT COUNT(*) FROM (
SELECT 1
FROM `msg` AS `unseen_msg` FROM `msg` AS `unseen_msg`
WHERE `unseen_msg`.`rid` = `room`.`rid` AND WHERE `unseen_msg`.`rid` = `room`.`rid` AND
`last_seen_cid` < `unseen_msg`.`cid`) AS `unseen_cnt` `last_seen_cid` < `unseen_msg`.`cid`
LIMIT :UNSEEN_CNT_LIMIT
)) AS `unseen_cnt`
FROM `room_member` INDEXED BY `ix_member_room` FROM `room_member` INDEXED BY `ix_member_room`
JOIN `room` USING (`rid`) JOIN `room` USING (`rid`)
LEFT JOIN `msg` USING (`rid`) LEFT JOIN `msg` USING (`rid`)

View file

@ -506,7 +506,7 @@ components:
attrs: attrs:
description: Room attributes bitset, see `RoomAttrs`. description: Room attributes bitset, see `RoomAttrs`.
type: integer type: integer
format: int64 format: int32
last_msg: last_msg:
$ref: '#/components/schemas/WithMsgId-Signed-Chat' $ref: '#/components/schemas/WithMsgId-Signed-Chat'
last_seen_cid: last_seen_cid:
@ -517,10 +517,10 @@ components:
The number of unseen messages. Only available for The number of unseen messages. Only available for
GET `/room?filter=unseen`. GET `/room?filter=unseen`.
type: integer type: integer
format: uint64 format: uint32
member_permission: member_permission:
type: integer type: integer
format: int64 format: int32
peer_user: peer_user:
type: string type: string
description: | description: |
@ -536,7 +536,7 @@ components:
type: string type: string
attrs: attrs:
type: integer type: integer
format: int64 format: int32
RoomMsgs: RoomMsgs:
type: object type: object
@ -644,7 +644,7 @@ components:
type: string type: string
permission: permission:
type: integer type: integer
format: uint64 format: int32
user: user:
type: string type: string