From 75abd13b2f1dbf60ef38134b3717410290f032e1 Mon Sep 17 00:00:00 2001 From: Olaf Wintermann Date: Sun, 12 Jul 2026 10:53:56 +0200 Subject: [PATCH] generate unique nodename --- Cargo.lock | 59 +++++++++++++++---- application/Cargo.toml | 1 + application/src/backend.rs | 54 ++++++++++++----- application/src/note.rs | 3 + .../src/m20260502_184134_create_settings.rs | 4 +- 5 files changed, 94 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bcbe107..498bad9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -468,6 +468,17 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "chacha20" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "rand_core 0.10.1", +] + [[package]] name = "chrono" version = "0.4.44" @@ -586,6 +597,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crc" version = "3.4.0" @@ -978,6 +998,7 @@ dependencies = [ "cfg-if", "libc", "r-efi 6.0.0", + "rand_core 0.10.1", "wasip2", "wasip3", ] @@ -1525,6 +1546,7 @@ dependencies = [ "dav-rs", "entity", "migration", + "rand 0.10.2", "sea-orm", "tokio", "ui-rs", @@ -1551,7 +1573,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand", + "rand 0.8.6", "smallvec", "zeroize", ] @@ -1934,7 +1956,18 @@ checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ "libc", "rand_chacha", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" +dependencies = [ + "chacha20", + "getrandom 0.4.2", + "rand_core 0.10.1", ] [[package]] @@ -1944,7 +1977,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -1956,6 +1989,12 @@ dependencies = [ "getrandom 0.2.17", ] +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + [[package]] name = "redox_syscall" version = "0.5.18" @@ -2054,7 +2093,7 @@ dependencies = [ "num-traits", "pkcs1", "pkcs8", - "rand_core", + "rand_core 0.6.4", "signature", "spki", "subtle", @@ -2071,7 +2110,7 @@ dependencies = [ "borsh", "bytes", "num-traits", - "rand", + "rand 0.8.6", "rkyv", "serde", "serde_json", @@ -2396,7 +2435,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest", ] @@ -2407,7 +2446,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest", ] @@ -2433,7 +2472,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -2606,7 +2645,7 @@ dependencies = [ "memchr", "once_cell", "percent-encoding", - "rand", + "rand 0.8.6", "rsa", "rust_decimal", "serde", @@ -2648,7 +2687,7 @@ dependencies = [ "md-5", "memchr", "once_cell", - "rand", + "rand 0.8.6", "rust_decimal", "serde", "serde_json", diff --git a/application/Cargo.toml b/application/Cargo.toml index af0ace5..0e5b480 100644 --- a/application/Cargo.toml +++ b/application/Cargo.toml @@ -10,3 +10,4 @@ entity = { path = "../entity" } migration = { path = "../migration" } sea-orm = { version = "2.0.0-rc", features = [ "sqlx-sqlite", "sqlx-postgres", "runtime-tokio-native-tls", "macros" ] } tokio = { version = "1.52.1", features = ["rt-multi-thread"] } +rand = "0.10.2" diff --git a/application/src/backend.rs b/application/src/backend.rs index 057682e..d9cb824 100644 --- a/application/src/backend.rs +++ b/application/src/backend.rs @@ -33,6 +33,8 @@ use sea_orm::{ActiveModelTrait, Database, DatabaseConnection, EntityTrait, Query use tokio::runtime::Runtime; use std::sync::{Arc}; use std::thread::JoinHandle; +use rand::distr::Alphanumeric; +use rand::RngExt; use tokio::sync::{broadcast, mpsc}; use tokio::sync::broadcast::error::SendError; use migration::{Expr, JoinType, Migrator, MigratorTrait}; @@ -391,11 +393,25 @@ impl BackendHandle { let _ = self.tx.send(cmd); } - pub fn save_note(&self, initiator: u64, id: NoteId, note: note::ActiveModel, content: Option, callback: F) + pub fn save_note(&self, initiator: u64, id: NoteId, mut note: note::ActiveModel, content: Option, callback: F) where F: FnOnce(SaveNoteResult) + Send + 'static { + let Set(collection_id) = note.collection_id else { + callback(SaveNoteResult::ValidationError("collection_id not set")); + return; + }; + let Set(nn) = ¬e.nodename else { + callback(SaveNoteResult::ValidationError("nodename not set")); + return; + }; + let nodename = nn.clone(); + let Set(version) = note.version else { + callback(SaveNoteResult::ValidationError("version not set")); + return; + }; + let bhandle = self.clone(); let cmd = Box::pin(async move { - let local_storage_path = if let Set(collection_id) = note.collection_id { + let local_storage_path = { let result = collection::Entity::find_by_id(collection_id) .join(JoinType::InnerJoin, collection::Relation::Repository.def()) .select_only() @@ -414,8 +430,6 @@ impl BackendHandle { } else { None } - } else { - return; }; let result = if let Set(note_id) = note.note_id { @@ -427,14 +441,6 @@ impl BackendHandle { update = update.col_expr(Column::Title, Expr::value(title)); } - let version = if let Set(version) = note.version { - version - } else { - // not setting version when calling save_note is a mistake and will probably - // lead to a VersionConflict - 0 - }; - let uresult = update .col_expr(Column::Lastmodified, Expr::value(Utc::now())) .col_expr(Column::Version, Expr::col(Column::Version).add(1)) @@ -460,10 +466,27 @@ impl BackendHandle { } } } else { - let result = note.insert(&bhandle.backend.db).await; + let result = note.clone().insert(&bhandle.backend.db).await; match result { Ok(note) => Ok(note), - Err(e) => Err(SaveNoteResult::Error(e)), + Err(e) => { + // The main reason why insertion might fail is the + // collection+name unique constraint. + // Generate a random suffix and try it again + + let suffix: String = rand::rng() + .sample_iter(Alphanumeric) + .take(6) + .map(char::from) + .collect(); + let new_nodename = nodename + "-" + suffix.as_str(); + note.nodename = Set(new_nodename); + let result = note.clone().insert(&bhandle.backend.db).await; + match result { + Ok(note) => Ok(note), + Err(e) => Err(SaveNoteResult::Error(e)) + } + } } }; @@ -515,7 +538,8 @@ impl BackendHandle { pub enum SaveNoteResult { Ok((entity::note::Model, i32)), VersionConflict, - Error(DbErr) + Error(DbErr), + ValidationError(&'static str) } impl SaveNoteResult { diff --git a/application/src/note.rs b/application/src/note.rs index 817a186..43f6dad 100644 --- a/application/src/note.rs +++ b/application/src/note.rs @@ -276,6 +276,9 @@ impl Note { }, SaveNoteResult::Error(e) => { println!("Failed to save note: {}", e); + }, + SaveNoteResult::ValidationError(s) => { + println!("Failed to save note: validation error: {}", s); } } }); diff --git a/migration/src/m20260502_184134_create_settings.rs b/migration/src/m20260502_184134_create_settings.rs index 49effd2..d3c6cf8 100644 --- a/migration/src/m20260502_184134_create_settings.rs +++ b/migration/src/m20260502_184134_create_settings.rs @@ -85,7 +85,7 @@ impl MigrationTrait for Migration { .name("index-note-name") .table("note") .col(Note::CollectionId) - .col(Note::NodeName) + .col(Note::Nodename) .unique() .to_owned() ).await?; @@ -130,5 +130,5 @@ impl MigrationTrait for Migration { #[derive(Iden)] enum Note { CollectionId, - NodeName + Nodename } \ No newline at end of file -- 2.52.0