-
Notifications
You must be signed in to change notification settings - Fork 560
Concept: Rust database access via Python database connection pool (via runInteraction) (LLM splat v1)
#19846
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
MadLittleMods
wants to merge
58
commits into
develop
Choose a base branch
from
madlittlemods/rust-db-access-using-python-db-pool-run-interaction-llm1
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+2,728
−202
Draft
Changes from 4 commits
Commits
Show all changes
58 commits
Select commit
Hold shift + click to select a range
3696e7c
Splat based on #19824
MadLittleMods c63b40e
A little bit of iterating
MadLittleMods bb4c555
Adjust comment
MadLittleMods 8f0768d
LLM attempt 1
MadLittleMods d9a111b
LLM attempt at simplifying
MadLittleMods 6b5e9f2
Partial `Row`
MadLittleMods d3af0c4
LLM further `Row`
MadLittleMods 65ba851
Concrete `Row` type
MadLittleMods 0226a67
Add comments why row expectations
MadLittleMods 7bf4b6a
Non-working: Add `test_versions.py`
MadLittleMods 8270087
Fix test failing with `RuntimeError: Tokio runtime is not running`
MadLittleMods 0b6a973
Passing `tests_versions.py`: Wait real time for tokio thread pool to …
MadLittleMods 158b4a0
Revert "Passing `tests_versions.py`: Wait real time for tokio thread …
MadLittleMods e2ec3f1
`FakeChannel.await_rust_result`
MadLittleMods 1dcf17d
Rename: `await_rust_result` -> `await_result_with_rust`
MadLittleMods 357860c
Specify features to enable
MadLittleMods ca1371e
Refactor `deferred` and `tokio_runtime` to their own crates
MadLittleMods f76c8c1
Refactor to remove `SynapseConfig` from shared code
MadLittleMods 29e5830
Fix Rust warnings
MadLittleMods 5b1a1ae
WIP: `RoomCreationPreset`
MadLittleMods 9688d48
Fix `RoomCreationPreset`
MadLittleMods 941188c
Remove unused `msc4222`
MadLittleMods 7c2790a
Serde `UnstableFeatureMap`
MadLittleMods 7aec5a0
Stub remaining features
MadLittleMods d9a02d3
Merge branch 'develop' into madlittlemods/rust-db-access-using-python…
MadLittleMods 19c0777
Add changelog
MadLittleMods 5f23dc6
Fix lint
MadLittleMods 1d6eb1e
Remove `await_result_with_rust` in favor of updating `await_result` w…
MadLittleMods 4eec02c
Explain possible better future for async fn that need to be `Send`
MadLittleMods dc93a23
Fix grammar, add intended fix
MadLittleMods 874178a
`poll_once` instead of `futures::executor::block_on`
MadLittleMods 505b599
Panic for programming error
MadLittleMods d40adfa
Explain why `poll_once`
MadLittleMods 065c5cb
Non-working: Try to save/restore logcontext
MadLittleMods 441e580
Fix logcontext
MadLittleMods 7466574
Less wordy
MadLittleMods 37ff660
Align imports on `OnceCell` which has `get_or_try_init`
MadLittleMods f42ba67
Avoid circular import issues
MadLittleMods c21dbbd
Rename `Value` -> `DbValue`
MadLittleMods ce68c0f
Merge branch 'develop' into madlittlemods/rust-db-access-using-python…
MadLittleMods 2860e4e
LLM attempt at switching back to `Store` with `dyn DatabasePool`
MadLittleMods 683f264
LLM simplify `dyn DatabasePool`
MadLittleMods adeb039
Sync trait not needed on `run_interaction`
MadLittleMods a4e4af7
"Dyn-compatibility" is the new name for "object safety"
MadLittleMods 87ca67d
Update comments
MadLittleMods 590fd2b
Fill in the rest of `rust/src/handlers/versions.rs`
MadLittleMods 2a609a5
Fill in missing experimental config
MadLittleMods 59228e5
Fill in the rest of the config
MadLittleMods 55d89f9
Use `time.sleep(0)` to align with decision in #19871
MadLittleMods 7ed525d
Rename `SynapseConfig` -> `SynapseHomeServerConfig`
MadLittleMods 8ddab4f
Iterate on Database trait comments
MadLittleMods 79a8cc1
Rename `Row` -> `DbRow`
MadLittleMods a2e68ad
Explain more about `python_db_pool`
MadLittleMods 0090330
Iterate on `python_db_pool` comments
MadLittleMods 6195074
Only return runInteraction result if it succeeded
MadLittleMods b5ea2f7
Avoid `String` allocation
MadLittleMods 5ce6b8a
Better `failure_to_pyerr`
MadLittleMods 74ad3b2
Merge branch 'develop' into madlittlemods/rust-db-access-using-python…
MadLittleMods File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| /* | ||
| * This file is licensed under the Affero General Public License (AGPL) version 3. | ||
| * | ||
| * Copyright (C) 2026 Element Creations Ltd | ||
| * | ||
| * This program is free software: you can redistribute it and/or modify | ||
| * it under the terms of the GNU Affero General Public License as | ||
| * published by the Free Software Foundation, either version 3 of the | ||
| * License, or (at your option) any later version. | ||
| * | ||
| * See the GNU Affero General Public License for more details: | ||
| * <https://www.gnu.org/licenses/agpl-3.0.html>. | ||
| * | ||
| */ | ||
|
|
||
| use pyo3::prelude::*; | ||
|
|
||
| #[derive(FromPyObject, Clone)] | ||
| pub struct SynapseConfig { | ||
| pub experimental: ExperimentalConfig, | ||
| } | ||
|
|
||
| // #[derive(FromPyObject)] | ||
| // #[serde(rename_all = "snake_case")] | ||
| // pub enum RoomCreationPreset { | ||
| // PrviateChat, | ||
| // PublicChat, | ||
| // TrustedPrivateChat, | ||
| // } | ||
|
|
||
| #[derive(FromPyObject, Clone)] | ||
| pub struct ExperimentalConfig { | ||
| pub msc3881_enabled: bool, | ||
| pub msc3575_enabled: bool, | ||
| pub msc4222_enabled: bool, | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| /* | ||
| * This file is licensed under the Affero General Public License (AGPL) version 3. | ||
| * | ||
| * Copyright (C) 2026 Element Creations Ltd | ||
| * | ||
| * This program is free software: you can redistribute it and/or modify | ||
| * it under the terms of the GNU Affero General Public License as | ||
| * published by the Free Software Foundation, either version 3 of the | ||
| * License, or (at your option) any later version. | ||
| * | ||
| * See the GNU Affero General Public License for more details: | ||
| * <https://www.gnu.org/licenses/agpl-3.0.html>. | ||
| * | ||
| */ | ||
|
|
||
| use std::sync::Arc; | ||
|
|
||
| use pyo3::{ | ||
| prelude::*, | ||
| types::{PyAnyMethods, PyModule, PyModuleMethods}, | ||
| Bound, PyResult, Python, | ||
| }; | ||
|
|
||
| use crate::config::SynapseConfig; | ||
| use crate::storage::db::python_db_pool::PythonDatabasePoolWrapper; | ||
| use crate::storage::store::Store; | ||
|
|
||
| pub mod versions; | ||
|
|
||
| #[pyclass] | ||
| struct RustHandlers { | ||
| versions: Py<versions::VersionsHandler>, | ||
| } | ||
|
|
||
| #[pymethods] | ||
| impl RustHandlers { | ||
| #[new] | ||
| #[pyo3(signature = (homeserver))] | ||
| pub fn py_new(py: Python<'_>, homeserver: &Bound<'_, PyAny>) -> PyResult<RustHandlers> { | ||
| let config: SynapseConfig = homeserver.getattr("config")?.extract()?; | ||
|
|
||
| // The Twisted reactor, used both to drive our Tokio runtime and to | ||
| // marshal database work back onto the reactor thread. | ||
| let reactor: Py<PyAny> = homeserver.call_method0("get_reactor")?.unbind(); | ||
|
|
||
| // hs.get_datastores().main.db_pool | ||
| let db_pool_py: Py<PyAny> = homeserver | ||
| .call_method0("get_datastores")? | ||
| .getattr("main")? | ||
| .getattr("db_pool")? | ||
| .unbind(); | ||
| let db_pool = PythonDatabasePoolWrapper::new(db_pool_py, reactor.clone_ref(py)); | ||
|
|
||
| // Store is shared across all of the handlers so let's use an `Arc` | ||
| let store = Arc::new(Store { | ||
| config: config.clone(), | ||
| db_pool: Box::new(db_pool), | ||
| }); | ||
|
|
||
| let versions = Py::new( | ||
| py, | ||
| versions::VersionsHandler { | ||
| config: config.clone(), | ||
| store: Arc::clone(&store), | ||
| reactor: reactor.clone_ref(py), | ||
| }, | ||
| )?; | ||
|
|
||
| Ok(RustHandlers { versions }) | ||
| } | ||
|
|
||
| #[getter] | ||
| fn versions(&self, py: Python<'_>) -> Py<versions::VersionsHandler> { | ||
| self.versions.clone_ref(py) | ||
| } | ||
| } | ||
|
|
||
| /// Called when registering modules with python. | ||
| pub fn register_module(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { | ||
| let child_module = PyModule::new(py, "handlers")?; | ||
| child_module.add_class::<RustHandlers>()?; | ||
|
|
||
| m.add_submodule(&child_module)?; | ||
|
|
||
| // We need to manually add the module to sys.modules to make `from | ||
| // synapse.synapse_rust import push` work. | ||
| py.import("sys")? | ||
| .getattr("modules")? | ||
| .set_item("synapse.synapse_rust.handlers", child_module)?; | ||
|
|
||
| Ok(()) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,223 @@ | ||
| /* | ||
| * This file is licensed under the Affero General Public License (AGPL) version 3. | ||
| * | ||
| * Copyright (C) 2026 Element Creations Ltd | ||
| * | ||
| * This program is free software: you can redistribute it and/or modify | ||
| * it under the terms of the GNU Affero General Public License as | ||
| * published by the Free Software Foundation, either version 3 of the | ||
| * License, or (at your option) any later version. | ||
| * | ||
| * See the GNU Affero General Public License for more details: | ||
| * <https://www.gnu.org/licenses/agpl-3.0.html>. | ||
| * | ||
| */ | ||
|
|
||
| use std::sync::Arc; | ||
|
|
||
| use pyo3::prelude::*; | ||
| use pythonize::{pythonize, PythonizeError}; | ||
| use serde::{Deserialize, Serialize}; | ||
|
|
||
| use crate::config::SynapseConfig; | ||
| use crate::http_client::create_deferred; | ||
| use crate::storage::store::{PerUserExperimentalFeature, Store}; | ||
|
|
||
| /// `GET /_matrix/client/versions` response | ||
| #[derive(Serialize, Deserialize, Clone, Debug)] | ||
| struct VersionsResponse { | ||
| versions: Vec<String>, | ||
| /// as per MSC1497 | ||
| unstable_features: std::collections::BTreeMap<String, bool>, | ||
| } | ||
|
|
||
| impl<'py> IntoPyObject<'py> for VersionsResponse { | ||
| type Target = PyAny; | ||
| type Output = Bound<'py, Self::Target>; | ||
| type Error = PythonizeError; | ||
|
|
||
| fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> { | ||
| pythonize(py, &self) | ||
| } | ||
| } | ||
|
|
||
| #[pyclass] | ||
| pub struct VersionsHandler { | ||
| pub config: SynapseConfig, | ||
| pub store: Arc<Store>, | ||
| /// The Twisted reactor, used to bridge our `async` response back into a | ||
| /// Twisted deferred that Python can `await`. | ||
| pub reactor: Py<PyAny>, | ||
| } | ||
|
|
||
| #[pymethods] | ||
| impl VersionsHandler { | ||
| /// Assemble a `/versions` response, returning a Twisted deferred that | ||
| /// resolves to the response body (a dict). | ||
| #[pyo3(signature = (user_id=None))] | ||
| fn get_versions<'py>( | ||
| &self, | ||
| py: Python<'py>, | ||
| user_id: Option<String>, | ||
| ) -> PyResult<Bound<'py, PyAny>> { | ||
| let store = Arc::clone(&self.store); | ||
| let config = self.config.clone(); | ||
|
|
||
| create_deferred(py, self.reactor.bind(py), async move { | ||
| build_versions_response(&store, &config, user_id.as_deref()) | ||
| .await | ||
| .map_err(|err| { | ||
| pyo3::exceptions::PyRuntimeError::new_err(format!( | ||
| "Failed to build /versions response: {err:#}" | ||
| )) | ||
| }) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| /// Assemble a `/versions` response body. | ||
| async fn build_versions_response( | ||
| store: &Store, | ||
| config: &SynapseConfig, | ||
| user_id: Option<&str>, | ||
| ) -> Result<VersionsResponse, anyhow::Error> { | ||
| { | ||
| let msc3881_enabled = match user_id { | ||
| Some(user_id) => { | ||
| store | ||
| .is_feature_enabled(user_id, PerUserExperimentalFeature::MSC3881) | ||
| .await? | ||
| } | ||
| None => PerUserExperimentalFeature::MSC3881.is_globally_enabled(config), | ||
| }; | ||
|
|
||
| let msc3575_enabled = match user_id { | ||
| Some(user_id) => { | ||
| store | ||
| .is_feature_enabled(user_id, PerUserExperimentalFeature::MSC3575) | ||
| .await? | ||
| } | ||
| None => PerUserExperimentalFeature::MSC3575.is_globally_enabled(config), | ||
| }; | ||
|
|
||
| // TODO: Calculate these once since they shouldn't change after start-up. | ||
| // e2ee_forced_public = ( | ||
| // RoomCreationPreset.PUBLIC_CHAT | ||
| // in config.room.encryption_enabled_by_default_for_room_presets | ||
| // ); | ||
| // e2ee_forced_private = ( | ||
| // RoomCreationPreset.PRIVATE_CHAT | ||
| // in config.room.encryption_enabled_by_default_for_room_presets | ||
| // ); | ||
| // e2ee_forced_trusted_private = ( | ||
| // RoomCreationPreset.TRUSTED_PRIVATE_CHAT | ||
| // in config.room.encryption_enabled_by_default_for_room_presets | ||
| // ); | ||
|
|
||
| Ok(VersionsResponse { | ||
| versions: Vec::from([ | ||
| // XXX: at some point we need to decide whether we need to include | ||
| // the previous version numbers, given we've defined r0.3.0 to be | ||
| // backwards compatible with r0.2.0. But need to check how | ||
| // conscientious we've been in compatibility, and decide whether the | ||
| // middle number is the major revision when at 0.X.Y (as opposed to | ||
| // X.Y.Z). And we need to decide whether it's fair to make clients | ||
| // parse the version string to figure out what's going on. | ||
| "r0.0.1".to_string(), | ||
| "r0.1.0".to_string(), | ||
| "r0.2.0".to_string(), | ||
| "r0.3.0".to_string(), | ||
| "r0.4.0".to_string(), | ||
| "r0.5.0".to_string(), | ||
| "r0.6.0".to_string(), | ||
| "r0.6.1".to_string(), | ||
| "v1.1".to_string(), | ||
| "v1.2".to_string(), | ||
| "v1.3".to_string(), | ||
| "v1.4".to_string(), | ||
| "v1.5".to_string(), | ||
| "v1.6".to_string(), | ||
| "v1.7".to_string(), | ||
| "v1.8".to_string(), | ||
| "v1.9".to_string(), | ||
| "v1.10".to_string(), | ||
| "v1.11".to_string(), | ||
| "v1.12".to_string(), | ||
| ]), | ||
| unstable_features: std::collections::BTreeMap::from([ | ||
| // // Implements support for label-based filtering as described in | ||
| // // MSC2326. | ||
| // ("org.matrix.label_based_filtering".to_string(), true), | ||
| // // Implements support for cross signing as described in MSC1756 | ||
| // ("org.matrix.e2e_cross_signing".to_string(), true), | ||
| // // Implements additional endpoints as described in MSC2432 | ||
| // ("org.matrix.msc2432".to_string(), true), | ||
| // // Implements additional endpoints as described in MSC2666 | ||
| // ("uk.half-shot.msc2666.query_mutual_rooms.stable".to_string(), true), | ||
| // // Whether new rooms will be set to encrypted or not (based on presets). | ||
| // ("io.element.e2ee_forced.public".to_string(), e2ee_forced_public), | ||
| // ("io.element.e2ee_forced.private".to_string(), e2ee_forced_private), | ||
| // ("io.element.e2ee_forced.trusted_private".to_string(), e2ee_forced_trusted_private), | ||
| // // Supports the busy presence state described in MSC3026. | ||
| // ("org.matrix.msc3026.busy_presence".to_string(), config.experimental.msc3026_enabled), | ||
| // // Supports receiving private read receipts as per MSC2285 | ||
| // ("org.matrix.msc2285.stable".to_string(), true), // TODO: Remove when MSC2285 becomes a part of the spec | ||
| // // Supports filtering of /publicRooms by room type as per MSC3827 | ||
| // ("org.matrix.msc3827.stable".to_string(), true), | ||
| // // Adds support for thread relations, per MSC3440. | ||
| // ("org.matrix.msc3440.stable".to_string(), true), // TODO: remove when "v1.3" is added above | ||
| // // Support for thread read receipts & notification counts. | ||
| // ("org.matrix.msc3771".to_string(), true), | ||
| // ("org.matrix.msc3773".to_string(), config.experimental.msc3773_enabled), | ||
| // // Allows moderators to fetch redacted event content as described in MSC2815 | ||
| // ("fi.mau.msc2815".to_string(), config.experimental.msc2815_enabled), | ||
| // // Adds a ping endpoint for appservices to check HS->AS connection | ||
| // ("fi.mau.msc2659.stable".to_string(), true), // TODO: remove when "v1.7" is added above | ||
| // // TODO: this is no longer needed once unstable MSC3882 does not need to be supported: | ||
| // ("org.matrix.msc3882".to_string(), config.auth.login_via_existing_enabled), | ||
| // Adds support for remotely enabling/disabling pushers, as per MSC3881 | ||
| ("org.matrix.msc3881".to_string(), msc3881_enabled), | ||
| // // Adds support for filtering /messages by event relation. | ||
| // ("org.matrix.msc3874".to_string(), config.experimental.msc3874_enabled), | ||
| // // Adds support for relation-based redactions as per MSC3912. | ||
| // ("org.matrix.msc3912".to_string(), config.experimental.msc3912_enabled), | ||
| // // Whether recursively provide relations is supported. | ||
| // // TODO This is no longer needed once unstable MSC3981 does not need to be supported. | ||
| // ("org.matrix.msc3981".to_string(), true), | ||
| // // Adds support for deleting account data. | ||
| // ("org.matrix.msc3391".to_string(), config.experimental.msc3391_enabled), | ||
| // // Allows clients to inhibit profile update propagation. | ||
| // ("org.matrix.msc4069".to_string(), config.experimental.msc4069_profile_inhibit_propagation), | ||
| // // Allows clients to handle push for encrypted events. | ||
| // ("org.matrix.msc4028".to_string(), config.experimental.msc4028_push_encrypted_events), | ||
| // // MSC4108: Mechanism to allow OIDC sign in and E2EE set up via QR code - 2024 version | ||
| // ("org.matrix.msc4108".to_string(), ( | ||
| // config.experimental.msc4108_enabled | ||
| // or ( | ||
| // config.experimental.msc4108_delegation_endpoint | ||
| // is not None | ||
| // ) | ||
| // )), | ||
| // // MSC4140: Delayed events | ||
| // ("org.matrix.msc4140".to_string(), bool(config.server.max_event_delay_ms)), | ||
| // Simplified sliding sync | ||
| ("org.matrix.simplified_msc3575".to_string(), msc3575_enabled), | ||
| // // Arbitrary key-value profile fields. | ||
| // ("uk.tcpip.msc4133".to_string(), config.experimental.msc4133_enabled), | ||
| // ("uk.tcpip.msc4133.stable".to_string(), true), | ||
| // // MSC4155: Invite filtering | ||
| // ("org.matrix.msc4155".to_string(), config.experimental.msc4155_enabled), | ||
| // // MSC4306: Support for thread subscriptions | ||
| // ("org.matrix.msc4306".to_string(), config.experimental.msc4306_enabled), | ||
| // // MSC4169: Backwards-compatible redaction sending using `/send` | ||
| // ("com.beeper.msc4169".to_string(), config.experimental.msc4169_enabled), | ||
| // // MSC4354: Sticky events | ||
| // ("org.matrix.msc4354".to_string(), config.experimental.msc4354_enabled), | ||
| // // MSC4380: Invite blocking | ||
| // ("org.matrix.msc4380.stable".to_string(), true), | ||
| // // MSC4445: Sync timeline order | ||
| // ("org.matrix.msc4445.initial_sync_timeline_topological_ordering".to_string(), true), | ||
| ]), | ||
| }) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.