11use bigdecimal:: num_bigint:: BigUint ;
2+ use log:: error;
23use rand:: TryRngCore ;
3- use sqlx:: { Decode , Encode , Postgres , Type , types:: BigDecimal } ;
4+ use sqlx:: { Decode , Encode , Postgres , Type , query, types:: BigDecimal } ;
5+
6+ use crate :: { database:: Database , errors:: Error } ;
47
58// TODO: This could be in polyproto instead
69
@@ -9,6 +12,48 @@ use sqlx::{Decode, Encode, Postgres, Type, types::BigDecimal};
912pub struct SerialNumber ( BigDecimal ) ;
1013
1114impl SerialNumber {
15+ /// Tries to generate a [SerialNumber] which does not yet exist in the
16+ /// `idcsr` table and its' `serial_number` column.
17+ ///
18+ /// Calls [Self::try_generate_random] internally.
19+ ///
20+ /// ## Errors
21+ ///
22+ /// Will error, if:
23+ ///
24+ /// - The [ThreadRng] fails to generate randomness. Depending on the
25+ /// implementation of `ThreadRng`, this method may cause a panic in these
26+ /// cases.
27+ /// - The database or database connection is unavailable for any reason.
28+ pub ( crate ) async fn try_generate_unique_random (
29+ db : & Database ,
30+ rng : & mut rand:: rngs:: ThreadRng ,
31+ ) -> Result < Self , Error > {
32+ let mut serial_number =
33+ SerialNumber :: try_generate_random ( & mut rand:: rng ( ) ) . map_err ( |e| {
34+ error ! ( "Error while trying to generate serial_number: {e}" ) ;
35+ Error :: new_internal_error ( None )
36+ } ) ?;
37+ while ( query ! (
38+ "
39+ SELECT serial_number
40+ FROM idcsr
41+ WHERE serial_number = $1
42+ " ,
43+ serial_number. as_bigdecimal( )
44+ )
45+ . fetch_optional ( & db. pool )
46+ . await ?)
47+ . is_some ( )
48+ {
49+ serial_number = SerialNumber :: try_generate_random ( rng) . map_err ( |e| {
50+ error ! ( "Error while trying to generate serial_number: {e}" ) ;
51+ Error :: new_internal_error ( None )
52+ } ) ?;
53+ }
54+ Ok ( serial_number)
55+ }
56+
1257 /// From a [ThreadRng], get 20 octets (160 bits) of entropy and construct a
1358 /// serial number out of it.
1459 ///
0 commit comments