use std::{collections::BTreeMap, iter, sync::Arc, time::Duration};
#[cfg(test)]
use as_variant::as_variant;
use ruma::{
api::client::{
backup::{add_backup_keys::v3::Response as KeysBackupResponse, RoomKeyBackup},
keys::{
claim_keys::v3::{Request as KeysClaimRequest, Response as KeysClaimResponse},
get_keys::v3::Response as KeysQueryResponse,
upload_keys::v3::{Request as KeysUploadRequest, Response as KeysUploadResponse},
upload_signatures::v3::{
Request as SignatureUploadRequest, Response as SignatureUploadResponse,
},
upload_signing_keys::v3::Response as SigningKeysUploadResponse,
},
message::send_message_event::v3::Response as RoomMessageResponse,
to_device::send_event_to_device::v3::Response as ToDeviceResponse,
},
events::{
AnyMessageLikeEventContent, AnyToDeviceEventContent, EventContent, ToDeviceEventType,
},
serde::Raw,
to_device::DeviceIdOrAllDevices,
OwnedDeviceId, OwnedRoomId, OwnedTransactionId, OwnedUserId, TransactionId, UserId,
};
use serde::{Deserialize, Serialize};
use crate::types::CrossSigningKey;
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ToDeviceRequest {
pub event_type: ToDeviceEventType,
pub txn_id: OwnedTransactionId,
pub messages:
BTreeMap<OwnedUserId, BTreeMap<DeviceIdOrAllDevices, Raw<AnyToDeviceEventContent>>>,
}
impl ToDeviceRequest {
pub fn new(
recipient: &UserId,
recipient_device: impl Into<DeviceIdOrAllDevices>,
event_type: &str,
content: Raw<AnyToDeviceEventContent>,
) -> Self {
let event_type = ToDeviceEventType::from(event_type);
let user_messages = iter::once((recipient_device.into(), content)).collect();
let messages = iter::once((recipient.to_owned(), user_messages)).collect();
ToDeviceRequest { event_type, txn_id: TransactionId::new(), messages }
}
pub(crate) fn for_recipients(
recipient: &UserId,
recipient_devices: Vec<OwnedDeviceId>,
content: &AnyToDeviceEventContent,
txn_id: OwnedTransactionId,
) -> Self {
let event_type = content.event_type();
let raw_content = Raw::new(content).expect("Failed to serialize to-device event");
if recipient_devices.is_empty() {
Self::new(
recipient,
DeviceIdOrAllDevices::AllDevices,
&event_type.to_string(),
raw_content,
)
} else {
let device_messages = recipient_devices
.into_iter()
.map(|d| (DeviceIdOrAllDevices::DeviceId(d), raw_content.clone()))
.collect();
let messages = iter::once((recipient.to_owned(), device_messages)).collect();
ToDeviceRequest { event_type, txn_id, messages }
}
}
pub(crate) fn with_id_raw(
recipient: &UserId,
recipient_device: impl Into<DeviceIdOrAllDevices>,
content: Raw<AnyToDeviceEventContent>,
event_type: ToDeviceEventType,
txn_id: OwnedTransactionId,
) -> Self {
let user_messages = iter::once((recipient_device.into(), content)).collect();
let messages = iter::once((recipient.to_owned(), user_messages)).collect();
ToDeviceRequest { event_type, txn_id, messages }
}
pub(crate) fn with_id(
recipient: &UserId,
recipient_device: impl Into<DeviceIdOrAllDevices>,
content: &AnyToDeviceEventContent,
txn_id: OwnedTransactionId,
) -> Self {
let event_type = content.event_type();
let raw_content = Raw::new(content).expect("Failed to serialize to-device event");
let user_messages = iter::once((recipient_device.into(), raw_content)).collect();
let messages = iter::once((recipient.to_owned(), user_messages)).collect();
ToDeviceRequest { event_type, txn_id, messages }
}
pub fn message_count(&self) -> usize {
self.messages.values().map(|d| d.len()).sum()
}
}
#[derive(Debug, Clone)]
pub struct UploadSigningKeysRequest {
pub master_key: Option<CrossSigningKey>,
pub self_signing_key: Option<CrossSigningKey>,
pub user_signing_key: Option<CrossSigningKey>,
}
#[derive(Clone, Debug)]
pub struct KeysQueryRequest {
pub timeout: Option<Duration>,
pub device_keys: BTreeMap<OwnedUserId, Vec<OwnedDeviceId>>,
}
impl KeysQueryRequest {
pub(crate) fn new(users: impl Iterator<Item = OwnedUserId>) -> Self {
let device_keys = users.map(|u| (u, Vec::new())).collect();
Self { timeout: None, device_keys }
}
}
#[derive(Debug)]
pub enum OutgoingRequests {
KeysUpload(KeysUploadRequest),
KeysQuery(KeysQueryRequest),
KeysClaim(KeysClaimRequest),
ToDeviceRequest(ToDeviceRequest),
SignatureUpload(SignatureUploadRequest),
RoomMessage(RoomMessageRequest),
}
#[cfg(test)]
impl OutgoingRequests {
pub fn to_device(&self) -> Option<&ToDeviceRequest> {
as_variant!(self, Self::ToDeviceRequest)
}
}
impl From<KeysQueryRequest> for OutgoingRequests {
fn from(request: KeysQueryRequest) -> Self {
Self::KeysQuery(request)
}
}
impl From<KeysClaimRequest> for OutgoingRequests {
fn from(r: KeysClaimRequest) -> Self {
Self::KeysClaim(r)
}
}
impl From<KeysUploadRequest> for OutgoingRequests {
fn from(request: KeysUploadRequest) -> Self {
Self::KeysUpload(request)
}
}
impl From<ToDeviceRequest> for OutgoingRequests {
fn from(request: ToDeviceRequest) -> Self {
Self::ToDeviceRequest(request)
}
}
impl From<RoomMessageRequest> for OutgoingRequests {
fn from(request: RoomMessageRequest) -> Self {
Self::RoomMessage(request)
}
}
impl From<SignatureUploadRequest> for OutgoingRequests {
fn from(request: SignatureUploadRequest) -> Self {
Self::SignatureUpload(request)
}
}
impl From<OutgoingVerificationRequest> for OutgoingRequest {
fn from(r: OutgoingVerificationRequest) -> Self {
Self { request_id: r.request_id().to_owned(), request: Arc::new(r.into()) }
}
}
impl From<SignatureUploadRequest> for OutgoingRequest {
fn from(r: SignatureUploadRequest) -> Self {
Self { request_id: TransactionId::new(), request: Arc::new(r.into()) }
}
}
impl From<KeysUploadRequest> for OutgoingRequest {
fn from(r: KeysUploadRequest) -> Self {
Self { request_id: TransactionId::new(), request: Arc::new(r.into()) }
}
}
#[derive(Debug)]
pub enum IncomingResponse<'a> {
KeysUpload(&'a KeysUploadResponse),
KeysQuery(&'a KeysQueryResponse),
ToDevice(&'a ToDeviceResponse),
KeysClaim(&'a KeysClaimResponse),
SigningKeysUpload(&'a SigningKeysUploadResponse),
SignatureUpload(&'a SignatureUploadResponse),
RoomMessage(&'a RoomMessageResponse),
KeysBackup(&'a KeysBackupResponse),
}
impl<'a> From<&'a KeysUploadResponse> for IncomingResponse<'a> {
fn from(response: &'a KeysUploadResponse) -> Self {
IncomingResponse::KeysUpload(response)
}
}
impl<'a> From<&'a KeysBackupResponse> for IncomingResponse<'a> {
fn from(response: &'a KeysBackupResponse) -> Self {
IncomingResponse::KeysBackup(response)
}
}
impl<'a> From<&'a KeysQueryResponse> for IncomingResponse<'a> {
fn from(response: &'a KeysQueryResponse) -> Self {
IncomingResponse::KeysQuery(response)
}
}
impl<'a> From<&'a ToDeviceResponse> for IncomingResponse<'a> {
fn from(response: &'a ToDeviceResponse) -> Self {
IncomingResponse::ToDevice(response)
}
}
impl<'a> From<&'a RoomMessageResponse> for IncomingResponse<'a> {
fn from(response: &'a RoomMessageResponse) -> Self {
IncomingResponse::RoomMessage(response)
}
}
impl<'a> From<&'a KeysClaimResponse> for IncomingResponse<'a> {
fn from(response: &'a KeysClaimResponse) -> Self {
IncomingResponse::KeysClaim(response)
}
}
impl<'a> From<&'a SignatureUploadResponse> for IncomingResponse<'a> {
fn from(response: &'a SignatureUploadResponse) -> Self {
IncomingResponse::SignatureUpload(response)
}
}
#[derive(Debug, Clone)]
pub struct OutgoingRequest {
pub(crate) request_id: OwnedTransactionId,
pub(crate) request: Arc<OutgoingRequests>,
}
impl OutgoingRequest {
pub fn request_id(&self) -> &TransactionId {
&self.request_id
}
pub fn request(&self) -> &OutgoingRequests {
&self.request
}
}
#[derive(Clone, Debug)]
pub struct RoomMessageRequest {
pub room_id: OwnedRoomId,
pub txn_id: OwnedTransactionId,
pub content: AnyMessageLikeEventContent,
}
#[derive(Clone, Debug)]
pub struct KeysBackupRequest {
pub version: String,
pub rooms: BTreeMap<OwnedRoomId, RoomKeyBackup>,
}
#[derive(Clone, Debug)]
pub enum OutgoingVerificationRequest {
ToDevice(ToDeviceRequest),
InRoom(RoomMessageRequest),
}
impl OutgoingVerificationRequest {
pub fn request_id(&self) -> &TransactionId {
match self {
OutgoingVerificationRequest::ToDevice(t) => &t.txn_id,
OutgoingVerificationRequest::InRoom(r) => &r.txn_id,
}
}
}
impl From<ToDeviceRequest> for OutgoingVerificationRequest {
fn from(r: ToDeviceRequest) -> Self {
OutgoingVerificationRequest::ToDevice(r)
}
}
impl From<RoomMessageRequest> for OutgoingVerificationRequest {
fn from(r: RoomMessageRequest) -> Self {
OutgoingVerificationRequest::InRoom(r)
}
}
impl From<OutgoingVerificationRequest> for OutgoingRequests {
fn from(request: OutgoingVerificationRequest) -> Self {
match request {
OutgoingVerificationRequest::ToDevice(r) => OutgoingRequests::ToDeviceRequest(r),
OutgoingVerificationRequest::InRoom(r) => OutgoingRequests::RoomMessage(r),
}
}
}