use std::collections::{BTreeMap, BTreeSet};
use std::time::Duration;
use salvo::prelude::*;
use serde::{Deserialize, Serialize, de::Error as _};
use crate::events::{AnyStrippedStateEvent, AnySyncStateEvent, AnySyncTimelineEvent, StateEventType};
use crate::identifiers::*;
use crate::serde::{RawJson, deserialize_cow_str, duration::opt_ms};
use crate::state::TypeStateKey;
use crate::{OwnedMxcUri, Seqnum};
use super::UnreadNotificationsCount;
pub use super::v4::{
AccountData, AccountDataConfig, E2ee, E2eeConfig, Extensions, ExtensionsConfig, Receipts, ReceiptsConfig,
SyncRoomHero, ToDevice, ToDeviceConfig, Typing, TypingConfig,
};
use crate::directory::RoomTypeFilter;
pub type SyncInfo<'a> = (&'a UserId, &'a DeviceId, Seqnum, &'a SyncEventsReqBody);
pub type KnownRooms = BTreeMap<String, BTreeMap<OwnedRoomId, Seqnum>>;
pub type TodoRooms = BTreeMap<OwnedRoomId, (BTreeSet<TypeStateKey>, usize, Seqnum)>;
#[derive(ToParameters, Deserialize, Debug)]
pub struct SyncEventsReqArgs {
#[salvo(parameter(parameter_in = Query))]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub pos: Option<String>,
#[salvo(parameter(parameter_in = Query))]
#[serde(with = "opt_ms", default, skip_serializing_if = "Option::is_none")]
pub timeout: Option<Duration>,
}
#[derive(ToSchema, Deserialize, Debug)]
pub struct SyncEventsReqBody {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub conn_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub txn_id: Option<String>,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub lists: BTreeMap<String, ReqList>,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub room_subscriptions: BTreeMap<OwnedRoomId, RoomSubscription>,
#[serde(default, skip_serializing_if = "<[_]>::is_empty")]
pub unsubscribe_rooms: Vec<OwnedRoomId>,
#[serde(default, skip_serializing_if = "ExtensionsConfig::is_empty")]
pub extensions: ExtensionsConfig,
}
#[derive(ToSchema, Serialize, Default, Debug)]
pub struct SyncEventsResBody {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub txn_id: Option<String>,
pub pos: String,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub lists: BTreeMap<String, SyncList>,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub rooms: BTreeMap<OwnedRoomId, SyncRoom>,
#[serde(default, skip_serializing_if = "Extensions::is_empty")]
pub extensions: Extensions,
}
impl SyncEventsResBody {
pub fn new(pos: String) -> Self {
Self {
pos,
..Default::default()
}
}
}
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct SyncList {
pub count: usize,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct SyncRoom {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub avatar: Option<OwnedMxcUri>,
#[serde(skip_serializing_if = "Option::is_none")]
pub initial: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_dm: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub invite_state: Option<Vec<RawJson<AnyStrippedStateEvent>>>,
#[serde(flatten, default, skip_serializing_if = "UnreadNotificationsCount::is_empty")]
pub unread_notifications: UnreadNotificationsCount,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub timeline: Vec<RawJson<AnySyncTimelineEvent>>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub required_state: Vec<RawJson<AnySyncStateEvent>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub prev_batch: Option<String>,
#[serde(default, skip_serializing_if = "crate::serde::is_default")]
pub limited: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub joined_count: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub invited_count: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub num_live: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bump_stamp: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub heroes: Option<Vec<SyncRoomHero>>,
}
#[derive(ToSchema, Clone, Debug, Default, Serialize, Deserialize)]
pub struct ReqListFilters {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub is_invite: Option<bool>,
#[serde(default, skip_serializing_if = "<[_]>::is_empty")]
pub not_room_types: Vec<RoomTypeFilter>,
}
#[derive(ToSchema, Clone, Debug, Default, Serialize, Deserialize)]
pub struct ReqList {
pub ranges: Vec<(usize, usize)>,
#[serde(flatten)]
pub room_details: RoomDetailsConfig,
#[serde(skip_serializing_if = "Option::is_none")]
pub include_heroes: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub filters: Option<ReqListFilters>,
}
#[derive(ToSchema, Clone, Debug, Default, Serialize, Deserialize)]
pub struct RoomDetailsConfig {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub required_state: Vec<(StateEventType, String)>,
pub timeline_limit: usize,
}
#[derive(ToSchema, Clone, Debug, Default, Serialize, Deserialize)]
pub struct IncludeOldRooms {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub required_state: Vec<(StateEventType, String)>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub timeline_limit: Option<usize>,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct RoomSubscription {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub required_state: Vec<(StateEventType, String)>,
pub timeline_limit: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub include_heroes: Option<bool>,
}
#[derive(ToSchema, Deserialize, Serialize, Clone, Debug)]
#[serde(rename_all = "UPPERCASE")]
pub enum SlidingOp {
Sync,
Insert,
Delete,
Invalidate,
}
#[derive(ToSchema, Deserialize, Serialize, Clone, Debug)]
pub struct SyncOp {
pub op: SlidingOp,
pub range: Option<(u64, u64)>,
pub index: Option<u64>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub room_ids: Vec<OwnedRoomId>,
pub room_id: Option<OwnedRoomId>,
}
#[derive(Clone, Debug, PartialEq)]
pub enum ReceiptsRoom {
AllSubscribed,
Room(OwnedRoomId),
}
impl Serialize for ReceiptsRoom {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self {
Self::AllSubscribed => serializer.serialize_str("*"),
Self::Room(r) => r.serialize(serializer),
}
}
}
impl<'de> Deserialize<'de> for ReceiptsRoom {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'de>,
{
match deserialize_cow_str(deserializer)?.as_ref() {
"*" => Ok(Self::AllSubscribed),
other => Ok(Self::Room(RoomId::parse(other).map_err(D::Error::custom)?.to_owned())),
}
}
}