Skip to content

Commit fb8a60b

Browse files
committed
Foundation of new syn2mas tool (#3636)
1 parent b0b6af0 commit fb8a60b

28 files changed

+1980
-1
lines changed

Cargo.lock

Lines changed: 71 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ mas-tasks = { path = "./crates/tasks/", version = "=0.13.0-rc.1" }
5454
mas-templates = { path = "./crates/templates/", version = "=0.13.0-rc.1" }
5555
mas-tower = { path = "./crates/tower/", version = "=0.13.0-rc.1" }
5656
oauth2-types = { path = "./crates/oauth2-types/", version = "=0.13.0-rc.1" }
57+
syn2mas = { path = "./crates/syn2mas", version = "=0.13.0-rc.1" }
5758

5859
# OpenAPI schema generation and validation
5960
[workspace.dependencies.aide]
@@ -65,6 +66,9 @@ features = ["axum", "axum-headers", "macros"]
6566
version = "7.0.14"
6667
features = ["chrono", "url", "tracing"]
6768

69+
[workspace.dependencies.async-stream]
70+
version = "0.3.6"
71+
6872
# Utility to write and implement async traits
6973
[workspace.dependencies.async-trait]
7074
version = "0.1.85"
@@ -94,6 +98,10 @@ version = "1.9.0"
9498
[workspace.dependencies.camino]
9599
version = "1.1.9"
96100

101+
# Memory optimisation for short strings
102+
[workspace.dependencies.compact_str]
103+
version = "0.8.0"
104+
97105
# Time utilities
98106
[workspace.dependencies.chrono]
99107
version = "0.4.39"
@@ -312,11 +320,17 @@ features = [
312320
[workspace.dependencies.thiserror]
313321
version = "2.0.11"
314322

323+
[workspace.dependencies.thiserror-ext]
324+
version = "0.2.0"
325+
315326
# Async runtime
316327
[workspace.dependencies.tokio]
317328
version = "1.43.0"
318329
features = ["full"]
319330

331+
[workspace.dependencies.tokio-stream]
332+
version = "0.1.16"
333+
320334
# Useful async utilities
321335
[workspace.dependencies.tokio-util]
322336
version = "0.7.13"

clippy.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
doc-valid-idents = ["OpenID", "OAuth", "..", "PostgreSQL"]
1+
doc-valid-idents = ["OpenID", "OAuth", "..", "PostgreSQL", "SQLite"]
22

33
disallowed-methods = [
44
{ path = "rand::thread_rng", reason = "do not create rngs on the fly, pass them as parameters" },

crates/cli/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ serde_yaml = "0.9.34"
3737
sqlx.workspace = true
3838
tokio.workspace = true
3939
tokio-util.workspace = true
40+
tokio-stream.workspace = true
4041
tower.workspace = true
4142
tower-http.workspace = true
4243
url.workspace = true
@@ -78,6 +79,9 @@ mas-tasks.workspace = true
7879
mas-templates.workspace = true
7980
mas-tower.workspace = true
8081

82+
oauth2-types.workspace = true
83+
syn2mas.workspace = true
84+
8185
[build-dependencies]
8286
anyhow.workspace = true
8387
vergen-gitcl = { version = "1.0.5", features = ["rustc"] }

crates/cli/src/commands/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ mod debug;
1919
mod doctor;
2020
mod manage;
2121
mod server;
22+
mod syn2mas;
2223
mod templates;
2324
mod worker;
2425

@@ -48,6 +49,10 @@ enum Subcommand {
4849

4950
/// Run diagnostics on the deployment
5051
Doctor(self::doctor::Options),
52+
53+
/// Migrate from Synapse's built-in auth system to MAS.
54+
#[clap(name = "syn2mas")]
55+
Syn2Mas(self::syn2mas::Options),
5156
}
5257

5358
#[derive(Parser, Debug)]
@@ -75,6 +80,7 @@ impl Options {
7580
Some(S::Templates(c)) => Box::pin(c.run(figment)).await,
7681
Some(S::Debug(c)) => Box::pin(c.run(figment)).await,
7782
Some(S::Doctor(c)) => Box::pin(c.run(figment)).await,
83+
Some(S::Syn2Mas(c)) => Box::pin(c.run(figment)).await,
7884
None => Box::pin(self::server::Options::default().run(figment)).await,
7985
}
8086
}

crates/cli/src/commands/syn2mas.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
use std::process::ExitCode;
2+
3+
use anyhow::Context;
4+
use clap::Parser;
5+
use figment::Figment;
6+
use mas_config::{ConfigurationSectionExt, DatabaseConfig};
7+
use rand::thread_rng;
8+
use sqlx::{Connection, Either, PgConnection};
9+
use syn2mas::{LockedMasDatabase, MasWriter, SynapseReader};
10+
use tracing::{error, warn};
11+
12+
use crate::util::database_connection_from_config;
13+
14+
#[derive(Parser, Debug)]
15+
pub(super) struct Options {
16+
#[command(subcommand)]
17+
subcommand: Subcommand,
18+
19+
/// This version of the syn2mas tool is EXPERIMENTAL and INCOMPLETE. It is only suitable for TESTING.
20+
/// If you want to use this tool anyway, please pass this argument.
21+
///
22+
/// If you want to migrate from Synapse to MAS today, please use the Node.js-based tool in the MAS repository.
23+
#[clap(long = "i-swear-i-am-just-testing-in-a-staging-environment")]
24+
experimental_accepted: bool,
25+
}
26+
27+
#[derive(Parser, Debug)]
28+
enum Subcommand {
29+
Check,
30+
Migrate,
31+
}
32+
33+
/// The number of parallel writing transactions active against the MAS database.
34+
const NUM_WRITER_CONNECTIONS: usize = 8;
35+
36+
impl Options {
37+
pub async fn run(self, figment: &Figment) -> anyhow::Result<ExitCode> {
38+
warn!("This version of the syn2mas tool is EXPERIMENTAL and INCOMPLETE. Do not use it, except for TESTING.");
39+
if !self.experimental_accepted {
40+
error!("Please agree that you can only use this tool for testing.");
41+
return Ok(ExitCode::FAILURE);
42+
}
43+
44+
// TODO allow configuring the synapse database location
45+
let mut syn_conn = PgConnection::connect("postgres:///fakesyn").await.unwrap();
46+
47+
let config = DatabaseConfig::extract_or_default(figment)?;
48+
49+
let mut mas_connection = database_connection_from_config(&config).await?;
50+
51+
let Either::Left(mut mas_connection) = LockedMasDatabase::try_new(&mut mas_connection)
52+
.await
53+
.context("failed to issue query to lock database")?
54+
else {
55+
error!("Failed to acquire syn2mas lock on the database.");
56+
error!("This likely means that another syn2mas instance is already running!");
57+
return Ok(ExitCode::FAILURE);
58+
};
59+
60+
syn2mas::mas_pre_migration_checks(&mut mas_connection).await?;
61+
syn2mas::synapse_pre_migration_checks(&mut syn_conn).await?;
62+
63+
let mut reader = SynapseReader::new(&mut syn_conn, true).await?;
64+
let mut writer_mas_connections = Vec::with_capacity(NUM_WRITER_CONNECTIONS);
65+
for _ in 0..NUM_WRITER_CONNECTIONS {
66+
writer_mas_connections.push(database_connection_from_config(&config).await?);
67+
}
68+
let mut writer = MasWriter::new(mas_connection, writer_mas_connections).await?;
69+
70+
// TODO is this rng ok?
71+
#[allow(clippy::disallowed_methods)]
72+
let mut rng = thread_rng();
73+
74+
// TODO progress reporting
75+
// TODO allow configuring the server name
76+
syn2mas::migrate(&mut reader, &mut writer, "matrix.org", &mut rng).await?;
77+
78+
reader.finish().await?;
79+
writer.finish().await?;
80+
81+
Ok(ExitCode::SUCCESS)
82+
}
83+
}

crates/syn2mas/.sqlx/query-07ec66733b67a9990cc9d483b564c8d05c577cf8f049d8822746c7d1dbd23752.json

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/syn2mas/.sqlx/query-12112011318abc0bdd7f722ed8c5d4a86bf5758f8c32d9d41a22999b2f0698ca.json

Lines changed: 34 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/syn2mas/.sqlx/query-486f3177dcf6117c6b966954a44d9f96a754eba64912566e81a90bd4cbd186f0.json

Lines changed: 34 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)