identifiers: Add matrix.to URL formatting
This commit is contained in:
parent
8b44f279c8
commit
7cbffe35da
@ -26,6 +26,7 @@ serde = ["ruma-serde", "serde1"]
|
||||
[dependencies]
|
||||
either = { version = "1.6.1", optional = true }
|
||||
paste = "1.0.5"
|
||||
percent-encoding = "2.1.0"
|
||||
rand = { version = "0.8.3", optional = true }
|
||||
ruma-identifiers-macros = { version = "=0.20.0", path = "../ruma-identifiers-macros" }
|
||||
ruma-identifiers-validation = { version = "0.5.0", path = "../ruma-identifiers-validation", default-features = false }
|
||||
|
@ -28,6 +28,7 @@ pub use crate::{
|
||||
event_id::EventId,
|
||||
key_id::{DeviceSigningKeyId, KeyId, ServerSigningKeyId, SigningKeyId},
|
||||
key_name::{KeyName, KeyNameBox},
|
||||
matrix_to::MatrixToRef,
|
||||
mxc_uri::MxcUri,
|
||||
room_alias_id::RoomAliasId,
|
||||
room_id::RoomId,
|
||||
@ -54,6 +55,7 @@ mod device_key_id;
|
||||
mod event_id;
|
||||
mod key_id;
|
||||
mod key_name;
|
||||
mod matrix_to;
|
||||
mod mxc_uri;
|
||||
mod room_alias_id;
|
||||
mod room_id;
|
||||
|
84
crates/ruma-identifiers/src/matrix_to.rs
Normal file
84
crates/ruma-identifiers/src/matrix_to.rs
Normal file
@ -0,0 +1,84 @@
|
||||
use std::fmt;
|
||||
|
||||
use percent_encoding::{percent_encode, AsciiSet, CONTROLS};
|
||||
|
||||
use crate::{EventId, ServerName};
|
||||
|
||||
const BASE_URL: &str = "https://matrix.to/#/";
|
||||
// Controls + Space + reserved characters from RFC 3986. In practice only the
|
||||
// reserved characters will be encountered most likely, but better be safe.
|
||||
// https://datatracker.ietf.org/doc/html/rfc3986/#page-13
|
||||
const TO_ENCODE: &AsciiSet = &CONTROLS
|
||||
.add(b':')
|
||||
.add(b'/')
|
||||
.add(b'?')
|
||||
.add(b'#')
|
||||
.add(b'[')
|
||||
.add(b']')
|
||||
.add(b'@')
|
||||
.add(b'!')
|
||||
.add(b'$')
|
||||
.add(b'&')
|
||||
.add(b'\'')
|
||||
.add(b'(')
|
||||
.add(b')')
|
||||
.add(b'*')
|
||||
.add(b'+')
|
||||
.add(b',')
|
||||
.add(b';')
|
||||
.add(b'=');
|
||||
|
||||
/// A reference to a user, room or event.
|
||||
///
|
||||
/// Turn it into a `matrix.to` URL through its `Display` implementation (i.e. by
|
||||
/// interpolating it in a formatting macro or via `.to_string()`).
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct MatrixToRef<'a> {
|
||||
id: &'a str,
|
||||
event_id: Option<&'a EventId>,
|
||||
via: Vec<&'a ServerName>,
|
||||
}
|
||||
|
||||
impl<'a> MatrixToRef<'a> {
|
||||
pub(crate) fn new(id: &'a str, via: Vec<&'a ServerName>) -> Self {
|
||||
Self { id, event_id: None, via }
|
||||
}
|
||||
|
||||
pub(crate) fn event(id: &'a str, event_id: &'a EventId, via: Vec<&'a ServerName>) -> Self {
|
||||
Self { id, event_id: Some(event_id), via }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Display for MatrixToRef<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(BASE_URL)?;
|
||||
write!(f, "{}", percent_encode(self.id.as_bytes(), TO_ENCODE))?;
|
||||
|
||||
if let Some(ev_id) = self.event_id {
|
||||
write!(f, "/{}", percent_encode(ev_id.as_bytes(), TO_ENCODE))?;
|
||||
}
|
||||
|
||||
let mut first = true;
|
||||
for server_name in &self.via {
|
||||
f.write_str(if first { "?via=" } else { "&via=" })?;
|
||||
f.write_str(server_name.as_str())?;
|
||||
|
||||
first = false;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::user_id;
|
||||
|
||||
#[test]
|
||||
fn matrix_to_ref() {
|
||||
assert_eq!(
|
||||
user_id!("@jplatte:notareal.hs").matrix_to_url().to_string(),
|
||||
"https://matrix.to/#/%40jplatte%3Anotareal.hs"
|
||||
);
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
use std::{convert::TryInto, fmt, num::NonZeroU8};
|
||||
|
||||
use crate::server_name::ServerName;
|
||||
use crate::{server_name::ServerName, EventId, MatrixToRef};
|
||||
|
||||
/// A Matrix room alias ID.
|
||||
///
|
||||
@ -39,6 +39,16 @@ impl RoomAliasId {
|
||||
pub fn server_name(&self) -> &ServerName {
|
||||
self.full_id[self.colon_idx.get() as usize + 1..].try_into().unwrap()
|
||||
}
|
||||
|
||||
/// Create a `matrix.to` reference for this room alias ID.
|
||||
pub fn matrix_to_url(&self) -> MatrixToRef<'_> {
|
||||
MatrixToRef::new(&self.full_id, Vec::new())
|
||||
}
|
||||
|
||||
/// Create a `matrix.to` reference for an event scoped under this room alias ID.
|
||||
pub fn matrix_to_event_url<'a>(&'a self, ev_id: &'a EventId) -> MatrixToRef<'a> {
|
||||
MatrixToRef::event(&self.full_id, ev_id, Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to create a new Matrix room alias ID from a string representation.
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use std::{convert::TryInto, fmt, num::NonZeroU8};
|
||||
|
||||
use crate::ServerName;
|
||||
use crate::{EventId, MatrixToRef, ServerName};
|
||||
|
||||
/// A Matrix room ID.
|
||||
///
|
||||
@ -53,6 +53,32 @@ impl RoomId {
|
||||
pub fn server_name(&self) -> &ServerName {
|
||||
self.full_id[self.colon_idx.get() as usize + 1..].try_into().unwrap()
|
||||
}
|
||||
|
||||
/// Create a `matrix.to` reference for this room ID.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use ruma_identifiers::{room_id, server_name};
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// room_id!("!somewhere:example.org")
|
||||
/// .matrix_to_url([&*server_name!("example.org"), &*server_name!("alt.example.org")])
|
||||
/// .to_string(),
|
||||
/// "https://matrix.to/#/%21somewhere%3Aexample.org?via=example.org&via=alt.example.org"
|
||||
/// );
|
||||
/// ```
|
||||
pub fn matrix_to_url<'a>(
|
||||
&'a self,
|
||||
via: impl IntoIterator<Item = &'a ServerName>,
|
||||
) -> MatrixToRef<'a> {
|
||||
MatrixToRef::new(&self.full_id, via.into_iter().collect())
|
||||
}
|
||||
|
||||
/// Create a `matrix.to` reference for an event scoped under this room ID.
|
||||
pub fn matrix_to_event_url<'a>(&'a self, ev_id: &'a EventId) -> MatrixToRef<'a> {
|
||||
MatrixToRef::event(&self.full_id, ev_id, Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to create a new Matrix room ID from a string representation.
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use std::{convert::TryInto, fmt, num::NonZeroU8};
|
||||
|
||||
use crate::ServerName;
|
||||
use crate::{MatrixToRef, ServerName};
|
||||
|
||||
/// A Matrix user ID.
|
||||
///
|
||||
@ -92,6 +92,22 @@ impl UserId {
|
||||
pub fn is_historical(&self) -> bool {
|
||||
self.is_historical
|
||||
}
|
||||
|
||||
/// Create a `matrix.to` reference for this user ID.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use ruma_identifiers::user_id;
|
||||
///
|
||||
/// let message = format!(
|
||||
/// r#"Thanks for the update <a href="{link}">{display_name}</a>."#,
|
||||
/// link = user_id!("@jplatte:notareal.hs").matrix_to_url(), display_name = "jplatte",
|
||||
/// );
|
||||
/// ```
|
||||
pub fn matrix_to_url(&self) -> MatrixToRef<'_> {
|
||||
MatrixToRef::new(&self.full_id, Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to create a new Matrix user ID from a string representation.
|
||||
|
Loading…
x
Reference in New Issue
Block a user