use std::{collections::BTreeMap, fmt, ops::Deref};
use as_variant::as_variant;
use ruma::{
MilliSecondsSinceUnixEpoch, OwnedDeviceId, OwnedEventId, OwnedTransactionId, OwnedUserId,
TransactionId, UInt,
events::{
AnyMessageLikeEventContent, MessageLikeEventContent as _, RawExt as _,
room::{MediaSource, message::RoomMessageEventContent},
},
serde::Raw,
};
use serde::{Deserialize, Serialize};
use crate::media::MediaRequestParameters;
#[derive(Clone, Serialize, Deserialize)]
pub struct SerializableEventContent {
event: Raw<AnyMessageLikeEventContent>,
event_type: String,
}
#[cfg(not(tarpaulin_include))]
impl fmt::Debug for SerializableEventContent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SerializedEventContent")
.field("event_type", &self.event_type)
.finish_non_exhaustive()
}
}
impl SerializableEventContent {
pub fn from_raw(event: Raw<AnyMessageLikeEventContent>, event_type: String) -> Self {
Self { event_type, event }
}
pub fn new(event: &AnyMessageLikeEventContent) -> Result<Self, serde_json::Error> {
Ok(Self::from_raw(Raw::new(event)?, event.event_type().to_string()))
}
pub fn deserialize(&self) -> Result<AnyMessageLikeEventContent, serde_json::Error> {
self.event.deserialize_with_type(&self.event_type)
}
pub fn raw(&self) -> (&Raw<AnyMessageLikeEventContent>, &str) {
(&self.event, &self.event_type)
}
pub fn into_raw(self) -> (Raw<AnyMessageLikeEventContent>, String) {
(self.event, self.event_type)
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum QueuedRequestKind {
Event {
content: SerializableEventContent,
},
MediaUpload {
content_type: String,
cache_key: MediaRequestParameters,
thumbnail_source: Option<MediaSource>,
related_to: OwnedTransactionId,
#[cfg(feature = "unstable-msc4274")]
#[serde(default)]
accumulated: Vec<AccumulatedSentMediaInfo>,
},
}
impl From<SerializableEventContent> for QueuedRequestKind {
fn from(content: SerializableEventContent) -> Self {
Self::Event { content }
}
}
#[derive(Clone)]
pub struct QueuedRequest {
pub kind: QueuedRequestKind,
pub transaction_id: OwnedTransactionId,
pub error: Option<QueueWedgeError>,
pub priority: usize,
pub created_at: MilliSecondsSinceUnixEpoch,
}
impl QueuedRequest {
pub fn as_event(&self) -> Option<&SerializableEventContent> {
as_variant!(&self.kind, QueuedRequestKind::Event { content } => content)
}
pub fn is_wedged(&self) -> bool {
self.error.is_some()
}
}
#[derive(Clone, Debug, Serialize, Deserialize, thiserror::Error)]
pub enum QueueWedgeError {
#[error("There are insecure devices in the room")]
InsecureDevices {
user_device_map: BTreeMap<OwnedUserId, Vec<OwnedDeviceId>>,
},
#[error("Some users that were previously verified are not anymore")]
IdentityViolations {
users: Vec<OwnedUserId>,
},
#[error("Own verification is required")]
CrossVerificationRequired,
#[error("Media content disappeared")]
MissingMediaContent,
#[error("Invalid mime type '{mime_type}' for media")]
InvalidMimeType {
mime_type: String,
},
#[error("Other unrecoverable error: {msg}")]
GenericApiError {
msg: String,
},
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum DependentQueuedRequestKind {
EditEvent {
new_content: SerializableEventContent,
},
RedactEvent,
ReactEvent {
key: String,
},
#[serde(alias = "UploadFileWithThumbnail")]
UploadFileOrThumbnail {
content_type: String,
cache_key: MediaRequestParameters,
related_to: OwnedTransactionId,
#[serde(default = "default_parent_is_thumbnail_upload")]
parent_is_thumbnail_upload: bool,
},
FinishUpload {
local_echo: Box<RoomMessageEventContent>,
file_upload: OwnedTransactionId,
thumbnail_info: Option<FinishUploadThumbnailInfo>,
},
#[cfg(feature = "unstable-msc4274")]
FinishGallery {
local_echo: Box<RoomMessageEventContent>,
item_infos: Vec<FinishGalleryItemInfo>,
},
}
fn default_parent_is_thumbnail_upload() -> bool {
true
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct FinishUploadThumbnailInfo {
pub txn: OwnedTransactionId,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub width: Option<UInt>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub height: Option<UInt>,
}
#[cfg(feature = "unstable-msc4274")]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct FinishGalleryItemInfo {
pub file_upload: OwnedTransactionId,
pub thumbnail_info: Option<FinishUploadThumbnailInfo>,
}
#[repr(transparent)]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(transparent)]
pub struct ChildTransactionId(OwnedTransactionId);
impl ChildTransactionId {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self(TransactionId::new())
}
}
impl Deref for ChildTransactionId {
type Target = TransactionId;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<String> for ChildTransactionId {
fn from(val: String) -> Self {
Self(val.into())
}
}
impl From<ChildTransactionId> for OwnedTransactionId {
fn from(val: ChildTransactionId) -> Self {
val.0
}
}
impl From<OwnedTransactionId> for ChildTransactionId {
fn from(val: OwnedTransactionId) -> Self {
Self(val)
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SentMediaInfo {
pub file: MediaSource,
pub thumbnail: Option<MediaSource>,
#[cfg(feature = "unstable-msc4274")]
#[serde(default)]
pub accumulated: Vec<AccumulatedSentMediaInfo>,
}
#[cfg(feature = "unstable-msc4274")]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AccumulatedSentMediaInfo {
pub file: MediaSource,
pub thumbnail: Option<MediaSource>,
}
#[cfg(feature = "unstable-msc4274")]
impl From<AccumulatedSentMediaInfo> for SentMediaInfo {
fn from(value: AccumulatedSentMediaInfo) -> Self {
Self { file: value.file, thumbnail: value.thumbnail, accumulated: vec![] }
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum SentRequestKey {
Event {
event_id: OwnedEventId,
event: Raw<AnyMessageLikeEventContent>,
event_type: String,
},
Media(SentMediaInfo),
}
impl SentRequestKey {
pub fn into_event_id(self) -> Option<OwnedEventId> {
as_variant!(self, Self::Event { event_id, .. } => event_id)
}
pub fn into_media(self) -> Option<SentMediaInfo> {
as_variant!(self, Self::Media)
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct DependentQueuedRequest {
pub own_transaction_id: ChildTransactionId,
pub kind: DependentQueuedRequestKind,
pub parent_transaction_id: OwnedTransactionId,
pub parent_key: Option<SentRequestKey>,
pub created_at: MilliSecondsSinceUnixEpoch,
}
impl DependentQueuedRequest {
pub fn is_own_event(&self) -> bool {
match self.kind {
DependentQueuedRequestKind::EditEvent { .. }
| DependentQueuedRequestKind::RedactEvent
| DependentQueuedRequestKind::ReactEvent { .. }
| DependentQueuedRequestKind::UploadFileOrThumbnail { .. } => {
false
}
DependentQueuedRequestKind::FinishUpload { .. } => {
true
}
#[cfg(feature = "unstable-msc4274")]
DependentQueuedRequestKind::FinishGallery { .. } => {
true
}
}
}
}
#[cfg(not(tarpaulin_include))]
impl fmt::Debug for QueuedRequest {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("QueuedRequest")
.field("transaction_id", &self.transaction_id)
.field("is_wedged", &self.is_wedged())
.finish_non_exhaustive()
}
}