mirror of
https://github.com/element-hq/synapse.git
synced 2026-11-11 10:07:59 +00:00
Lays the two foundations the Rust DBAPI2 backend needs before any connection code: a Python↔Postgres value-mapping layer, and the helpers that drive async work from sync Python. Value mapping: - `PgValue` — enum that implements `tokio_postgres::types::ToSql`, encoding into Postgres' binary wire format per the prepared-statement column type (so a single Python `int` becomes INT2/INT4/INT8 with range checks). - `PythonPgFromSql` — the decode counterpart, turning wire bytes back into Python objects (SQL NULL → `None`). - Covers int / float / bool / str / bytes / None; lists etc are left to a follow-up. Blocking helpers: - `block_on` / `block_on_pg_result` / `block_on_next` drive `tokio-postgres` futures to completion from sync, GIL-holding Python methods, releasing the GIL for the wait. Both modules are `pub` for now so not-yet-consumed items don't trip clippy's `dead_code` lint; later PRs in the stack tighten visibility. Everything here is unit-tested with no live Postgres server.
119 lines
3.1 KiB
Rust
119 lines
3.1 KiB
Rust
use std::{
|
|
convert::Infallible,
|
|
time::{SystemTime, UNIX_EPOCH},
|
|
};
|
|
|
|
use lazy_static::lazy_static;
|
|
use pyo3::{exceptions::PyRuntimeError, prelude::*};
|
|
use pyo3_log::ResetHandle;
|
|
|
|
pub mod acl;
|
|
pub mod canonical_json;
|
|
pub mod clock;
|
|
pub mod config;
|
|
pub mod database;
|
|
pub mod deferred;
|
|
pub mod duration;
|
|
pub mod errors;
|
|
pub mod events;
|
|
pub mod handlers;
|
|
pub mod homeserver;
|
|
pub mod http;
|
|
pub mod http_client;
|
|
pub mod identifier;
|
|
pub mod json;
|
|
pub mod logging;
|
|
pub mod matrix_const;
|
|
pub mod msc4388_rendezvous;
|
|
pub mod push;
|
|
pub mod reactor;
|
|
pub mod rendezvous;
|
|
pub mod room_versions;
|
|
pub mod runtime;
|
|
pub mod segmenter;
|
|
pub mod storage;
|
|
pub mod twisted_dispatch;
|
|
pub mod types;
|
|
|
|
lazy_static! {
|
|
static ref LOGGING_HANDLE: ResetHandle = pyo3_log::init();
|
|
}
|
|
|
|
/// Returns the hash of all the rust source files at the time it was compiled.
|
|
///
|
|
/// Used by python to detect if the rust library is outdated.
|
|
#[pyfunction]
|
|
fn get_rust_file_digest() -> &'static str {
|
|
env!("SYNAPSE_RUST_DIGEST")
|
|
}
|
|
|
|
/// Returns the `rustc` version used when this native module was built.
|
|
///
|
|
/// This value is embedded at build time, so it can be exported as a prometheus metrics.
|
|
#[pyfunction]
|
|
pub fn get_rustc_version() -> &'static str {
|
|
env!("SYNAPSE_RUSTC_VERSION")
|
|
}
|
|
|
|
/// Formats the sum of two numbers as string.
|
|
#[pyfunction]
|
|
#[pyo3(text_signature = "(a, b, /)")]
|
|
fn sum_as_string(a: usize, b: usize) -> PyResult<String> {
|
|
Ok((a + b).to_string())
|
|
}
|
|
|
|
/// Reset the cached logging configuration of pyo3-log to pick up any changes
|
|
/// in the Python logging configuration.
|
|
///
|
|
#[pyfunction]
|
|
fn reset_logging_config() {
|
|
LOGGING_HANDLE.reset();
|
|
}
|
|
|
|
/// The entry point for defining the Python module.
|
|
#[pymodule]
|
|
fn synapse_rust(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
// We expect that system clock is set for after the Unix epoch, 1970. We'll
|
|
// panic later if it is not, so we check here and fail early.
|
|
if SystemTime::now().duration_since(UNIX_EPOCH).is_err() {
|
|
return Err(PyRuntimeError::new_err(
|
|
"system clock was set before the Unix epoch, 1970",
|
|
));
|
|
}
|
|
|
|
m.add_function(wrap_pyfunction!(sum_as_string, m)?)?;
|
|
m.add_function(wrap_pyfunction!(get_rust_file_digest, m)?)?;
|
|
m.add_function(wrap_pyfunction!(get_rustc_version, m)?)?;
|
|
m.add_function(wrap_pyfunction!(reset_logging_config, m)?)?;
|
|
|
|
acl::register_module(py, m)?;
|
|
logging::context::register_module(py, m)?;
|
|
deferred::register_module(py, m)?;
|
|
database::register_module(py, m)?;
|
|
push::register_module(py, m)?;
|
|
events::register_module(py, m)?;
|
|
handlers::register_module(py, m)?;
|
|
http_client::register_module(py, m)?;
|
|
rendezvous::register_module(py, m)?;
|
|
runtime::register_module(py, m)?;
|
|
msc4388_rendezvous::register_module(py, m)?;
|
|
segmenter::register_module(py, m)?;
|
|
room_versions::register_module(py, m)?;
|
|
types::register_module(py, m)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub trait UnwrapInfallible<T> {
|
|
fn unwrap_infallible(self) -> T;
|
|
}
|
|
|
|
impl<T> UnwrapInfallible<T> for Result<T, Infallible> {
|
|
fn unwrap_infallible(self) -> T {
|
|
match self {
|
|
Ok(val) => val,
|
|
Err(never) => match never {},
|
|
}
|
|
}
|
|
}
|