diff --git a/crates/ruma-client-api/Cargo.toml b/crates/ruma-client-api/Cargo.toml index 4c3ae8e5..e0316f7e 100644 --- a/crates/ruma-client-api/Cargo.toml +++ b/crates/ruma-client-api/Cargo.toml @@ -18,6 +18,7 @@ rustdoc-args = ["--cfg", "docsrs"] [features] compat = [] unstable-exhaustive-types = [] +unstable-msc2246 = [] unstable-msc2448 = [] unstable-msc2654 = [] unstable-msc2676 = [] diff --git a/crates/ruma-client-api/src/error.rs b/crates/ruma-client-api/src/error.rs index 52d51403..0b820382 100644 --- a/crates/ruma-client-api/src/error.rs +++ b/crates/ruma-client-api/src/error.rs @@ -141,6 +141,14 @@ pub enum ErrorKind { /// M_WEAK_PASSWORD WeakPassword, + /// FI.MAU.MSC2246_NOT_YET_UPLOADED + #[cfg(feature = "unstable-msc2246")] + NotYetUploaded, + + /// FI.MAU.MSC2246_CANNOT_OVERWRITE_MEDIA + #[cfg(feature = "unstable-msc2246")] + CannotOverwriteMedia, + #[doc(hidden)] _Custom { errcode: PrivOwnedStr, extra: Extra }, } @@ -185,6 +193,10 @@ impl AsRef for ErrorKind { Self::ResourceLimitExceeded { .. } => "M_RESOURCE_LIMIT_EXCEEDED", Self::CannotLeaveServerNoticeRoom => "M_CANNOT_LEAVE_SERVER_NOTICE_ROOM", Self::WeakPassword => "M_WEAK_PASSWORD", + #[cfg(feature = "unstable-msc2246")] + Self::NotYetUploaded => "FI.MAU.MSC2246_NOT_YET_UPLOADED", + #[cfg(feature = "unstable-msc2246")] + Self::CannotOverwriteMedia => "FI.MAU.MSC2246_CANNOT_OVERWRITE_MEDIA", Self::_Custom { errcode, .. } => &errcode.0, } } diff --git a/crates/ruma-client-api/src/error/kind_serde.rs b/crates/ruma-client-api/src/error/kind_serde.rs index 4d93ced1..ec943a5a 100644 --- a/crates/ruma-client-api/src/error/kind_serde.rs +++ b/crates/ruma-client-api/src/error/kind_serde.rs @@ -206,6 +206,10 @@ impl<'de> Visitor<'de> for ErrorKindVisitor { }, ErrCode::CannotLeaveServerNoticeRoom => ErrorKind::CannotLeaveServerNoticeRoom, ErrCode::WeakPassword => ErrorKind::WeakPassword, + #[cfg(feature = "unstable-msc2246")] + ErrCode::NotYetUploaded => ErrorKind::NotYetUploaded, + #[cfg(feature = "unstable-msc2246")] + ErrCode::CannotOverwriteMedia => ErrorKind::CannotOverwriteMedia, ErrCode::_Custom(errcode) => ErrorKind::_Custom { errcode, extra }, }) } @@ -247,6 +251,15 @@ enum ErrCode { ResourceLimitExceeded, CannotLeaveServerNoticeRoom, WeakPassword, + #[cfg(feature = "unstable-msc2246")] + #[ruma_enum(rename = "FI.MAU.MSC2246_NOT_YET_UPLOADED", alias = "M_NOT_YET_UPLOADED")] + NotYetUploaded, + #[cfg(feature = "unstable-msc2246")] + #[ruma_enum( + rename = "FI.MAU.MSC2246_CANNOT_OVERWRITE_MEDIA", + alias = "M_CANNOT_OVERWRITE_MEDIA" + )] + CannotOverwriteMedia, _Custom(PrivOwnedStr), } diff --git a/crates/ruma-client-api/src/media.rs b/crates/ruma-client-api/src/media.rs index 91064a52..250560c6 100644 --- a/crates/ruma-client-api/src/media.rs +++ b/crates/ruma-client-api/src/media.rs @@ -1,6 +1,10 @@ //! Endpoints for the media repository. pub mod create_content; +#[cfg(feature = "unstable-msc2246")] +pub mod create_content_async; +#[cfg(feature = "unstable-msc2246")] +pub mod create_mxc_uri; pub mod get_content; pub mod get_content_as_filename; pub mod get_content_thumbnail; diff --git a/crates/ruma-client-api/src/media/create_content_async.rs b/crates/ruma-client-api/src/media/create_content_async.rs new file mode 100644 index 00000000..63d76325 --- /dev/null +++ b/crates/ruma-client-api/src/media/create_content_async.rs @@ -0,0 +1,57 @@ +//! `POST /_matrix/media/*/upload/{serverName}/{mediaId}` + +pub mod unstable { + //! `/unstable/` ([spec]) + //! + //! [spec]: https://github.com/tulir/matrix-doc/blob/asynchronous_uploads/proposals/2246-asynchronous-uploads.md + + use ruma_common::{api::ruma_api, IdParseError, MxcUri, ServerName}; + + ruma_api! { + metadata: { + description: "Upload media to an MXC URI that was created with create_mxc_uri.", + method: PUT, + name: "create_content_async", + unstable_path: "/_matrix/media/unstable/fi.mau.msc2246/upload/:server_name/:media_id", + rate_limited: true, + authentication: AccessToken, + } + + request: { + /// The media ID from the mxc:// URI (the path component). + #[ruma_api(path)] + pub media_id: &'a str, + + /// The server name from the mxc:// URI (the authoritory component). + #[ruma_api(path)] + pub server_name: &'a ServerName, + + /// The file contents to upload. + #[ruma_api(raw_body)] + pub file: &'a [u8], + + /// The content type of the file being uploaded. + #[ruma_api(header = CONTENT_TYPE)] + pub content_type: Option<&'a str>, + + // TODO: How does this and msc2448 (blurhash) interact? + } + + response: {} + + error: crate::Error + } + + impl<'a> Request<'a> { + /// Creates a new `Request` with the given file contents. + pub fn new(media_id: &'a str, server_name: &'a ServerName, file: &'a [u8]) -> Self { + Self { media_id, server_name, file, content_type: None } + } + + /// Creates a new `Request` with the given url and file contents. + pub fn from_url(url: &'a MxcUri, file: &'a [u8]) -> Result { + let (server_name, media_id) = url.parts()?; + Ok(Self::new(media_id, server_name, file)) + } + } +} diff --git a/crates/ruma-client-api/src/media/create_mxc_uri.rs b/crates/ruma-client-api/src/media/create_mxc_uri.rs new file mode 100644 index 00000000..acaf5f2a --- /dev/null +++ b/crates/ruma-client-api/src/media/create_mxc_uri.rs @@ -0,0 +1,40 @@ +//! `POST /_matrix/media/*/create` + +pub mod unstable { + //! `/unstable/` ([spec]) + //! + //! [spec]: https://github.com/tulir/matrix-doc/blob/asynchronous_uploads/proposals/2246-asynchronous-uploads.md + + use js_int::UInt; + use ruma_common::{api::ruma_api, OwnedMxcUri}; + + ruma_api! { + metadata: { + description: "Create an MXC URI without content.", + method: POST, + name: "create_mxc_uri", + unstable_path: "/_matrix/media/unstable/fi.mau.msc2246/create", + rate_limited: true, + authentication: AccessToken, + } + + request: {} + + response: { + /// The MXC URI for the about to be uploaded content. + pub content_uri: OwnedMxcUri, + + /// The time at which the URI will expire if an upload has not been started. + pub unused_expires_at: UInt, + } + + error: crate::Error + } + + impl Response { + /// Creates a new `Response` with the given MXC URI which expires at a given point in time. + pub fn new(content_uri: OwnedMxcUri, unused_expires_at: UInt) -> Self { + Self { content_uri, unused_expires_at } + } + } +} diff --git a/crates/ruma-client-api/src/media/get_content.rs b/crates/ruma-client-api/src/media/get_content.rs index c95b6d0a..d5c2f20b 100644 --- a/crates/ruma-client-api/src/media/get_content.rs +++ b/crates/ruma-client-api/src/media/get_content.rs @@ -5,6 +5,8 @@ pub mod v3 { //! //! [spec]: https://spec.matrix.org/v1.2/client-server-api/#get_matrixmediav3downloadservernamemediaid + #[cfg(feature = "unstable-msc2246")] + use js_int::UInt; use ruma_common::{api::ruma_api, IdParseError, MxcUri, ServerName}; ruma_api! { @@ -34,6 +36,21 @@ pub mod v3 { #[ruma_api(query)] #[serde(default = "ruma_common::serde::default_true", skip_serializing_if = "ruma_common::serde::is_true")] pub allow_remote: bool, + + + /// How long to wait for the media to be uploaded + /// + /// This uses the unstable prefix in + /// [MSC2246](https://github.com/matrix-org/matrix-spec-proposals/pull/2246) + #[ruma_api(query)] + #[cfg(feature = "unstable-msc2246")] + #[serde( + default, + skip_serializing_if = "ruma_common::serde::is_default", + rename = "fi.mau.msc2246.max_stall_ms", + alias = "max_stall_ms" + )] + pub max_stall_ms: Option, } response: { @@ -61,14 +78,20 @@ pub mod v3 { impl<'a> Request<'a> { /// Creates a new `Request` with the given media ID and server name. pub fn new(media_id: &'a str, server_name: &'a ServerName) -> Self { - Self { media_id, server_name, allow_remote: true } + Self { + media_id, + server_name, + allow_remote: true, + #[cfg(feature = "unstable-msc2246")] + max_stall_ms: None, + } } /// Creates a new `Request` with the given url. pub fn from_url(url: &'a MxcUri) -> Result { let (server_name, media_id) = url.parts()?; - Ok(Self { media_id, server_name, allow_remote: true }) + Ok(Self::new(media_id, server_name)) } } diff --git a/crates/ruma-client-api/src/media/get_content_thumbnail.rs b/crates/ruma-client-api/src/media/get_content_thumbnail.rs index 700dc736..9b9a3d38 100644 --- a/crates/ruma-client-api/src/media/get_content_thumbnail.rs +++ b/crates/ruma-client-api/src/media/get_content_thumbnail.rs @@ -54,6 +54,20 @@ pub mod v3 { #[ruma_api(query)] #[serde(default = "ruma_common::serde::default_true", skip_serializing_if = "ruma_common::serde::is_true")] pub allow_remote: bool, + + /// How long to wait for the media to be uploaded + /// + /// This uses the unstable prefix in + /// [MSC2246](https://github.com/matrix-org/matrix-spec-proposals/pull/2246) + #[ruma_api(query)] + #[cfg(feature = "unstable-msc2246")] + #[serde( + default, + skip_serializing_if = "ruma_common::serde::is_default", + rename = "fi.mau.msc2246.max_stall_ms", + alias = "max_stall_ms" + )] + pub max_stall_ms: Option, } response: { @@ -78,7 +92,16 @@ pub mod v3 { width: UInt, height: UInt, ) -> Self { - Self { media_id, server_name, method: None, width, height, allow_remote: true } + Self { + media_id, + server_name, + method: None, + width, + height, + allow_remote: true, + #[cfg(feature = "unstable-msc2246")] + max_stall_ms: None, + } } /// Creates a new `Request` with the given url, desired thumbnail width and @@ -86,7 +109,7 @@ pub mod v3 { pub fn from_url(url: &'a MxcUri, width: UInt, height: UInt) -> Result { let (server_name, media_id) = url.parts()?; - Ok(Self { media_id, server_name, method: None, width, height, allow_remote: true }) + Ok(Self::new(media_id, server_name, width, height)) } } diff --git a/crates/ruma/Cargo.toml b/crates/ruma/Cargo.toml index a6c688e3..c4be4ab4 100644 --- a/crates/ruma/Cargo.toml +++ b/crates/ruma/Cargo.toml @@ -118,6 +118,7 @@ unstable-pre-spec = [ "ruma-push-gateway-api/unstable-pre-spec", ] unstable-msc1767 = ["ruma-common/unstable-msc1767"] +unstable-msc2246 = ["ruma-client-api/unstable-msc2246"] unstable-msc2448 = [ "ruma-client-api/unstable-msc2448", "ruma-common/unstable-msc2448",