1use async_trait::async_trait;
2use sea_orm::{ColumnTrait, DbErr, EntityTrait, QueryFilter};
3
4use hoprd_db_entity::{aliases::Column, types::Alias};
5use hoprd_migration::OnConflict;
6
7use crate::{db::HoprdDb, errors::Result};
8
9pub const ME_AS_ALIAS: &str = "me";
10
11#[async_trait]
13pub trait HoprdDbAliasesOperations {
14 async fn resolve_alias(&self, alias: String) -> Result<Option<String>>;
16
17 async fn get_aliases(&self) -> Result<Vec<Alias>>;
19
20 async fn set_alias(&self, peer: String, alias: String) -> Result<()>;
22
23 async fn set_aliases(&self, aliases: Vec<Alias>) -> Result<()>;
25
26 async fn delete_alias(&self, alias: String) -> Result<()>;
28
29 async fn clear_aliases(&self) -> Result<()>;
31}
32
33#[async_trait]
34impl HoprdDbAliasesOperations for HoprdDb {
35 async fn resolve_alias(&self, alias: String) -> Result<Option<String>> {
36 let row = hoprd_db_entity::aliases::Entity::find()
37 .filter(hoprd_db_entity::aliases::Column::Alias.eq(alias))
38 .one(&self.metadata)
39 .await?;
40
41 Ok(row.map(|model| model.peer_id))
42 }
43
44 async fn get_aliases(&self) -> Result<Vec<Alias>> {
45 let rows = hoprd_db_entity::aliases::Entity::find().all(&self.metadata).await?;
46
47 let aliases: Vec<Alias> = rows.into_iter().map(Alias::from).collect();
48
49 Ok(aliases)
50 }
51
52 async fn set_aliases(&self, aliases: Vec<Alias>) -> Result<()> {
53 match self.resolve_alias(ME_AS_ALIAS.to_string()).await {
54 Ok(Some(me)) => {
55 if aliases.iter().any(|entry| entry.peer_id == me) {
56 return Err(crate::errors::DbError::LogicalError(
57 "own alias cannot be modified".into(),
58 ));
59 }
60 }
61 Ok(None) => {}
62 Err(e) => return Err(e),
63 }
64
65 let new_aliases = aliases
66 .into_iter()
67 .map(|entry| hoprd_db_entity::aliases::ActiveModel {
68 id: Default::default(),
69 peer_id: sea_orm::ActiveValue::Set(entry.peer_id.clone()),
70 alias: sea_orm::ActiveValue::Set(entry.alias.clone()),
71 })
72 .collect::<Vec<_>>();
73
74 let _ = hoprd_db_entity::aliases::Entity::insert_many(new_aliases)
75 .on_conflict(
76 OnConflict::new()
77 .update_columns([Column::PeerId, Column::Alias])
78 .to_owned(),
79 )
80 .exec(&self.metadata)
81 .await?;
82
83 Ok(())
84 }
85
86 async fn set_alias(&self, peer: String, alias: String) -> Result<()> {
87 if let Ok(Some(me)) = self.resolve_alias(ME_AS_ALIAS.to_string()).await {
88 if me == peer {
89 return Err(crate::errors::DbError::ReAliasingSelfNotAllowed);
90 }
91 }
92
93 let new_pair = hoprd_db_entity::aliases::ActiveModel {
94 id: Default::default(),
95 peer_id: sea_orm::ActiveValue::Set(peer),
96 alias: sea_orm::ActiveValue::Set(alias),
97 };
98
99 match hoprd_db_entity::aliases::Entity::insert(new_pair)
100 .on_conflict(OnConflict::new().do_nothing().to_owned())
101 .exec(&self.metadata)
102 .await
103 {
104 Ok(_) => Ok(()),
105 Err(DbErr::RecordNotInserted) => Err(crate::errors::DbError::AliasOrPeerIdAlreadyExists),
106 Err(e) => Err(e.into()),
107 }
108 }
109
110 async fn delete_alias(&self, alias: String) -> Result<()> {
111 let res = hoprd_db_entity::aliases::Entity::delete_many()
112 .filter(hoprd_db_entity::aliases::Column::Alias.eq(alias))
113 .filter(hoprd_db_entity::aliases::Column::Alias.ne(ME_AS_ALIAS.to_string()))
114 .exec(&self.metadata)
115 .await?;
116
117 if res.rows_affected > 0 {
118 Ok(())
119 } else {
120 Err(crate::errors::DbError::LogicalError(
121 "alias cannot be removed because it does not exist or it is the node's own alias.".into(),
122 ))
123 }
124 }
125
126 async fn clear_aliases(&self) -> Result<()> {
127 let _ = hoprd_db_entity::aliases::Entity::delete_many()
128 .filter(hoprd_db_entity::aliases::Column::Alias.ne(ME_AS_ALIAS.to_string()))
129 .exec(&self.metadata)
130 .await?;
131
132 Ok(())
133 }
134}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139 use libp2p_identity::PeerId;
140
141 #[async_std::test]
142 async fn set_alias_should_succeed() {
143 let db = HoprdDb::new_in_memory().await;
144
145 db.set_alias(PeerId::random().to_string(), "test_alias".to_string())
146 .await
147 .expect("should add alias");
148
149 let aliases = db.get_aliases().await.expect("should get aliases");
150
151 assert_eq!(aliases.len(), 1);
152 }
153
154 #[async_std::test]
155 async fn set_alias_should_set_multiple_aliases_in_a_transaction() -> Result<()> {
156 let db: HoprdDb = HoprdDb::new_in_memory().await;
157 let entries = vec![
158 Alias {
159 peer_id: PeerId::random().to_string(),
160 alias: "test_alias".to_string(),
161 },
162 Alias {
163 peer_id: PeerId::random().to_string(),
164 alias: "test_alias_2".to_string(),
165 },
166 ];
167
168 db.set_aliases(entries.clone()).await?;
169
170 let aliases = db.get_aliases().await?;
171
172 assert_eq!(aliases.len(), 2);
173
174 Ok(())
175 }
176
177 #[async_std::test]
178 async fn set_me_among_other_alias_should_fail() {
179 let db = HoprdDb::new_in_memory().await;
180
181 let me_peer_id = PeerId::random().to_string();
182 let alias = ME_AS_ALIAS.to_string();
183
184 let res = db.set_alias(me_peer_id.clone(), alias.clone()).await;
185
186 assert!(res.is_ok());
187
188 let entries = vec![
189 Alias {
190 peer_id: me_peer_id.to_string(),
191 alias: "test_alias".to_string(),
192 },
193 Alias {
194 peer_id: PeerId::random().to_string(),
195 alias: "test_alias_2".to_string(),
196 },
197 ];
198
199 let res = db.set_aliases(entries.clone()).await;
200
201 assert!(res.is_err());
202 }
203
204 #[async_std::test]
205 async fn set_me_alias_should_fail_if_set() {
206 let db = HoprdDb::new_in_memory().await;
207
208 let me_peer_id = PeerId::random().to_string();
209 let alias = ME_AS_ALIAS.to_string();
210
211 let res = db.set_alias(me_peer_id.clone(), alias.clone()).await;
212
213 assert!(res.is_ok());
214
215 let res = db.set_alias(me_peer_id.clone(), alias.clone()).await;
216
217 assert!(res.is_err());
218 }
219
220 #[async_std::test]
221 async fn set_alias_should_fail_if_the_alias_already_is_assigned_to_any_peer_id() -> anyhow::Result<()> {
222 let db = HoprdDb::new_in_memory().await;
223
224 let peer_id = PeerId::random().to_string();
225 let peer_id_2 = PeerId::random().to_string();
226 let alias = "test_alias".to_string();
227
228 db.set_alias(peer_id.clone(), alias.clone()).await?;
229
230 assert!(db.set_alias(peer_id_2, alias.clone()).await.is_err());
231
232 let aliases = db.get_aliases().await.unwrap();
233
234 assert_eq!(aliases.len(), 1);
235 assert_eq!(aliases[0].peer_id, peer_id);
236
237 Ok(())
238 }
239
240 #[async_std::test]
241 async fn set_alias_should_fail_if_the_peerid_already_is_aliased() -> anyhow::Result<()> {
242 let db = HoprdDb::new_in_memory().await;
243
244 let peer_id = PeerId::random().to_string();
245 let alias = "test_alias".to_string();
246 let alias2 = "alias".to_string();
247
248 db.set_alias(peer_id.clone(), alias.clone()).await?;
249
250 assert!(db.set_alias(peer_id.clone(), alias2.clone()).await.is_err());
251
252 let aliases = db.get_aliases().await.unwrap();
253
254 assert_eq!(aliases.len(), 1);
255 assert_eq!(aliases[0].alias, alias);
256
257 Ok(())
258 }
259
260 #[async_std::test]
261 async fn resolve_alias_should_return_alias() {
262 let db = HoprdDb::new_in_memory().await;
263
264 let peer_id = PeerId::random().to_string();
265 let alias = "test_alias".to_string();
266
267 db.set_alias(peer_id.clone(), alias.clone())
268 .await
269 .expect("should add alias");
270
271 let alias = db.resolve_alias(alias).await.expect("should get alias");
272
273 assert!(alias.is_some());
274 }
275
276 #[async_std::test]
277 async fn resolve_not_stored_alias_should_return_none() {
278 let db = HoprdDb::new_in_memory().await;
279
280 let peer_id = PeerId::random().to_string();
281 let alias = "test_alias".to_string();
282
283 db.set_alias(peer_id.clone(), alias.clone())
284 .await
285 .expect("should add alias");
286
287 let alias = db
288 .resolve_alias(PeerId::random().to_string())
289 .await
290 .expect("should get alias");
291
292 assert!(alias.is_none());
293 }
294
295 #[async_std::test]
296 async fn delete_stored_alias() {
297 let db = HoprdDb::new_in_memory().await;
298
299 let peer_id = PeerId::random().to_string();
300 let alias = "test_alias".to_string();
301
302 db.set_alias(peer_id.clone(), alias.clone())
303 .await
304 .expect("should add alias");
305 let aliases = db.get_aliases().await.expect("should get aliases");
306 assert_eq!(aliases.len(), 1);
307
308 db.delete_alias(alias).await.expect("should delete alias");
309 let aliases = db.get_aliases().await.expect("should get aliases");
310 assert_eq!(aliases.len(), 0);
311 }
312
313 #[async_std::test]
314 async fn delete_all_aliases() {
315 let db = HoprdDb::new_in_memory().await;
316
317 let me_peer_id = PeerId::random().to_string();
318 let peer_id = PeerId::random().to_string();
319 let alias = "test_alias".to_string();
320
321 db.set_alias(peer_id.clone(), alias.clone())
322 .await
323 .expect("should add alias");
324 db.set_alias(me_peer_id.clone(), ME_AS_ALIAS.to_string())
325 .await
326 .expect("should add alias");
327
328 let aliases = db.get_aliases().await.expect("should get aliases");
329 assert_eq!(aliases.len(), 2);
330
331 db.clear_aliases()
332 .await
333 .expect(format!("should clear aliases except '{}'", ME_AS_ALIAS).as_str());
334 let aliases = db.get_aliases().await.expect("should get aliases");
335 assert_eq!(aliases.len(), 1);
336 assert_eq!(aliases[0].peer_id, me_peer_id);
337 }
338
339 #[async_std::test]
340 async fn set_aliases_with_existing_alias_should_replace_peer_id() {
341 let db = HoprdDb::new_in_memory().await;
342
343 let peer_id = PeerId::random().to_string();
344 let alias = "test_alias".to_string();
345
346 db.set_alias(peer_id.clone(), alias.clone())
347 .await
348 .expect("should add alias");
349
350 let new_peer_id = PeerId::random().to_string();
351 db.set_aliases(vec![Alias {
352 peer_id: new_peer_id.clone(),
353 alias: alias.clone(),
354 }])
355 .await
356 .expect("should replace peer_id");
357
358 let aliases = db.get_aliases().await.expect("should get aliases");
359
360 assert_eq!(aliases.len(), 1);
361 assert_eq!(aliases[0].peer_id, new_peer_id);
362 }
363
364 #[async_std::test]
365 async fn set_aliases_with_existing_peer_id_should_replace_alias() {
366 let db = HoprdDb::new_in_memory().await;
367
368 let peer_id = PeerId::random().to_string();
369 let alias = "test_alias".to_string();
370
371 db.set_alias(peer_id.clone(), alias.clone())
372 .await
373 .expect("should add alias");
374
375 db.set_aliases(vec![Alias {
376 peer_id: peer_id.clone(),
377 alias: alias.clone().to_uppercase(),
378 }])
379 .await
380 .expect("should replace alias");
381
382 let aliases = db.get_aliases().await.expect("should get aliases");
383
384 assert_eq!(aliases.len(), 1);
385 assert_eq!(aliases[0].alias, alias.to_uppercase());
386 }
387
388 #[async_std::test]
389 async fn set_aliases_with_existing_entry_should_do_nothing() {
390 let db = HoprdDb::new_in_memory().await;
391
392 let peer_id = PeerId::random().to_string();
393 let alias = "test_alias".to_string();
394
395 db.set_alias(peer_id.clone(), alias.clone())
396 .await
397 .expect("should add alias");
398
399 db.set_aliases(vec![Alias {
400 peer_id: peer_id.clone(),
401 alias: alias.clone(),
402 }])
403 .await
404 .expect("should do nothing");
405
406 let aliases = db.get_aliases().await.expect("should get aliases");
407
408 assert_eq!(aliases.len(), 1);
409 }
410}