From f4b96c0b3f63de18b5da08bf117e730c06df6ef2 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Thu, 5 Mar 2026 13:33:11 +0000 Subject: [PATCH] WIP --- rust/src/events/constants.rs | 76 +++++++++++++++++++++------- rust/src/events/internal_metadata.rs | 2 +- rust/src/events/mod.rs | 76 ++++++++++++++++++++++++---- 3 files changed, 123 insertions(+), 31 deletions(-) diff --git a/rust/src/events/constants.rs b/rust/src/events/constants.rs index 1d7e7172e9..3e6a8a5d05 100644 --- a/rust/src/events/constants.rs +++ b/rust/src/events/constants.rs @@ -5,6 +5,12 @@ use std::{fmt::Display, str::FromStr}; use anyhow::Error; +use once_cell::sync::OnceCell; +use pyo3::{ + types::PyAnyMethods, Borrowed, Bound, FromPyObject, Py, PyAny, PyErr, PyResult, Python, +}; + +use crate::events::Event; /// Maximum size of a PDU pub const MAX_PDU_SIZE_BYTES: usize = 65_535; @@ -48,27 +54,33 @@ pub enum RoomVersion { Custom(String), } +impl RoomVersion { + pub fn as_str(&self) -> &str { + match self { + RoomVersion::V1 => "1", + RoomVersion::V2 => "2", + RoomVersion::V3 => "3", + RoomVersion::V4 => "4", + RoomVersion::V5 => "5", + RoomVersion::V6 => "6", + RoomVersion::V7 => "7", + RoomVersion::V8 => "8", + RoomVersion::V9 => "9", + RoomVersion::V10 => "10", + RoomVersion::V11 => "11", + RoomVersion::V12 => "12", + RoomVersion::OrgMatrixMsc1767_10 => "org.matrix.msc1767.10", + RoomVersion::OrgMatrixMsc3757_10 => "org.matrix.msc3757.10", + RoomVersion::OrgMatrixMsc3757_11 => "org.matrix.msc3757.11", + RoomVersion::OrgMatrixHydra11 => "org.matrix.hydra.11", + RoomVersion::Custom(s) => s.as_str(), + } + } +} + impl Display for RoomVersion { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - RoomVersion::V1 => write!(f, "1"), - RoomVersion::V2 => write!(f, "2"), - RoomVersion::V3 => write!(f, "3"), - RoomVersion::V4 => write!(f, "4"), - RoomVersion::V5 => write!(f, "5"), - RoomVersion::V6 => write!(f, "6"), - RoomVersion::V7 => write!(f, "7"), - RoomVersion::V8 => write!(f, "8"), - RoomVersion::V9 => write!(f, "9"), - RoomVersion::V10 => write!(f, "10"), - RoomVersion::V11 => write!(f, "11"), - RoomVersion::V12 => write!(f, "12"), - RoomVersion::OrgMatrixMsc1767_10 => write!(f, "org.matrix.msc1767.10"), - RoomVersion::OrgMatrixMsc3757_10 => write!(f, "org.matrix.msc3757.10"), - RoomVersion::OrgMatrixMsc3757_11 => write!(f, "org.matrix.msc3757.11"), - RoomVersion::OrgMatrixHydra11 => write!(f, "org.matrix.hydra.11"), - RoomVersion::Custom(s) => write!(f, "{s}"), - } + write!(f, "{}", self.as_str()) } } @@ -221,3 +233,29 @@ pub mod redaction_field { /// Redacts event field: redacts pub const REDACTS: &str = "redacts"; } + +/// A reference to the `synapse.api.room_version.KNOWN_ROOM_VERSIONS`. +static KNOWN_ROOM_VERSIONS: OnceCell> = OnceCell::new(); + +/// Access to the `synapse.api.room_version.KNOWN_ROOM_VERSIONS`. +fn known_room_version_py(py: Python<'_>) -> PyResult<&Bound<'_, PyAny>> { + Ok(KNOWN_ROOM_VERSIONS + .get_or_try_init(|| -> PyResult> { + let module = py.import("synapse.api.room_version")?; + + let room_versions_class = module.getattr("KNOWN_ROOM_VERSIONS")?; + + Ok(room_versions_class.unbind().into()) + })? + .bind(py)) +} + +pub fn get_room_version_py<'a>( + room_version: &RoomVersion, + py: Python<'a>, +) -> PyResult> { + let room_version_module = known_room_version_py(py)?; + let room_version_str = room_version.as_str(); + let room_version_py = room_version_module.get_item(room_version_str)?; + Ok(room_version_py) +} diff --git a/rust/src/events/internal_metadata.rs b/rust/src/events/internal_metadata.rs index a53c1e771b..db1046e929 100644 --- a/rust/src/events/internal_metadata.rs +++ b/rust/src/events/internal_metadata.rs @@ -275,7 +275,7 @@ pub struct EventInternalMetadata { #[pymethods] impl EventInternalMetadata { #[new] - fn new(dict: &Bound<'_, PyDict>) -> PyResult { + pub fn new(dict: &Bound<'_, PyDict>) -> PyResult { let mut data = Vec::with_capacity(dict.len()); for (key, value) in dict.iter() { diff --git a/rust/src/events/mod.rs b/rust/src/events/mod.rs index b081f43ad1..0213fb2b74 100644 --- a/rust/src/events/mod.rs +++ b/rust/src/events/mod.rs @@ -22,20 +22,26 @@ use std::{ collections::HashMap, + str::FromStr, sync::{Arc, RwLock}, }; use pyo3::{ - exceptions::{PyException, PyKeyError}, + exceptions::{PyException, PyKeyError, PyValueError}, pyclass, pymethods, - types::{PyAnyMethods, PyIterator, PyMapping, PyMappingMethods, PyModule, PyModuleMethods}, - wrap_pyfunction, Bound, IntoPyObject, PyAny, PyErr, PyResult, Python, + types::{ + PyAnyMethods, PyDict, PyIterator, PyMapping, PyMappingMethods, PyModule, PyModuleMethods, + }, + wrap_pyfunction, Bound, IntoPyObject, PyAny, PyResult, Python, }; use pythonize::{depythonize, pythonize}; use serde::{Deserialize, Serialize}; use crate::{ - events::{constants::RoomVersion, utils::calculate_event_id}, + events::{ + constants::{get_room_version_py, RoomVersion}, + utils::calculate_event_id, + }, identifier::EventID, }; @@ -382,30 +388,62 @@ struct EventCommonFields { struct Event { inner: EventFormatEnum, event_id: EventID, + internal_metadata: internal_metadata::EventInternalMetadata, + room_version: RoomVersion, + rejected_reason: Option>, } #[pymethods] impl Event { #[new] - fn new<'a, 'py>(format: u8, event_dict: &'a Bound<'py, PyAny>) -> PyResult { - if format != 3 { - return Err(PyKeyError::new_err(format!( - "Unsupported event format version: {}", - format - ))); + fn new<'a, 'py>( + event_dict: &'a Bound<'py, PyAny>, + room_version: &'a Bound<'py, PyAny>, + internal_metadata_dict: &'a Bound<'py, PyDict>, + rejected_reason: Option, + ) -> PyResult { + let room_version = { + let r = room_version.getattr("identifier")?; + let room_version_str = r.extract::<&str>()?; + RoomVersion::from_str(room_version_str) + .map_err(|e| PyValueError::new_err(format!("Unsupported room version: {}", e)))? + }; + + let rejected_reason = rejected_reason.map(String::into_boxed_str); + + // Check we're the right room version + match room_version { + RoomVersion::V4 + | RoomVersion::V5 + | RoomVersion::V6 + | RoomVersion::V7 + | RoomVersion::V8 + | RoomVersion::V9 + | RoomVersion::V10 + | RoomVersion::V11 + | RoomVersion::OrgMatrixMsc1767_10 + | RoomVersion::OrgMatrixMsc3757_10 + | RoomVersion::OrgMatrixMsc3757_11 => {} + _ => return Err(PyValueError::new_err("Unsupported room version")), } let event_format_v3: EventFormatV3Container = depythonize(event_dict)?; + let internal_metadata = + internal_metadata::EventInternalMetadata::new(internal_metadata_dict)?; + let event_value = serde_json::to_value(&event_format_v3) .map_err(|err| PyException::new_err(format!("Failed to serialize event: {}", err)))?; - let event_id = calculate_event_id(&event_value, &RoomVersion::V10).map_err(|err| { + let event_id = calculate_event_id(&event_value, &room_version).map_err(|err| { PyException::new_err(format!("Failed to calculate event_id: {}", err)) })?; Ok(Self { inner: EventFormatEnum::V3(event_format_v3), event_id, + room_version, + rejected_reason, + internal_metadata, }) } @@ -505,6 +543,22 @@ impl Event { // ... } } + + #[getter] + fn internal_metadata(&self) -> PyResult { + // TODO: Interior mutability + Ok(self.internal_metadata.clone()) + } + + #[getter] + fn rejected_reason(&self) -> Option<&str> { + self.rejected_reason.as_deref() + } + + #[getter] + fn room_version<'py>(&self, py: Python<'py>) -> PyResult> { + get_room_version_py(&self.room_version, py) + } } enum EventFormatEnum {