uri_register/
sync.rs

1// Copyright TELICENT LTD
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Synchronous wrapper for URI register operations
16//!
17//! This module provides a synchronous API for applications that cannot use async/await.
18//! It wraps the async implementation with a lightweight Tokio runtime.
19
20use crate::cache::CacheStrategy;
21use crate::error::Result;
22use crate::postgres::{PostgresUriRegister, RegisterStats};
23use crate::service::UriService;
24use std::collections::HashMap;
25use tokio::runtime::Runtime;
26
27/// Synchronous PostgreSQL URI register
28///
29/// This is a synchronous wrapper around [`PostgresUriRegister`] for use in
30/// synchronous Rust applications. It uses a lightweight current-thread Tokio
31/// runtime internally to execute async operations.
32///
33/// All methods have the same semantics as their async counterparts but block
34/// the calling thread until completion.
35///
36/// # Example
37///
38/// ```rust,no_run
39/// use uri_register::SyncPostgresUriRegister;
40///
41/// fn main() -> uri_register::Result<()> {
42///     let register = SyncPostgresUriRegister::new(
43///         "postgres://localhost/mydb",
44///         "uri_register",
45///         20,
46///         10_000
47///     )?;
48///
49///     let id = register.register_uri("https://example.com")?;
50///     println!("URI registered with ID: {}", id);
51///
52///     Ok(())
53/// }
54/// ```
55pub struct SyncPostgresUriRegister {
56    inner: PostgresUriRegister,
57    runtime: Runtime,
58}
59
60impl SyncPostgresUriRegister {
61    /// Create a new synchronous PostgreSQL URI register with default cache (Moka/W-TinyLFU)
62    ///
63    /// This is the backwards-compatible constructor that uses Moka caching by default.
64    ///
65    /// # Arguments
66    ///
67    /// * `database_url` - PostgreSQL connection string
68    /// * `table_name` - Name of the database table
69    /// * `max_connections` - Maximum number of connections in the pool
70    /// * `cache_size` - Number of URI-to-ID mappings to cache
71    pub fn new(
72        database_url: &str,
73        table_name: &str,
74        max_connections: u32,
75        cache_size: usize,
76    ) -> Result<Self> {
77        Self::new_with_cache_strategy(
78            database_url,
79            table_name,
80            max_connections,
81            cache_size,
82            None, // Default cache strategy
83            None, // Default to no TLS
84        )
85    }
86
87    /// Create a new synchronous PostgreSQL URI register with custom cache strategy and TLS
88    ///
89    /// # Arguments
90    ///
91    /// * `database_url` - PostgreSQL connection string
92    /// * `table_name` - Name of the database table
93    /// * `max_connections` - Maximum number of connections in the pool
94    /// * `cache_size` - Number of URI-to-ID mappings to cache
95    /// * `cache_strategy` - Optional cache strategy (defaults to Moka if None)
96    /// * `use_tls` - Optional TLS flag (defaults to false/None for backwards compatibility)
97    pub fn new_with_cache_strategy(
98        database_url: &str,
99        table_name: &str,
100        max_connections: u32,
101        cache_size: usize,
102        cache_strategy: Option<CacheStrategy>,
103        use_tls: Option<bool>,
104    ) -> Result<Self> {
105        let runtime = Runtime::new().map_err(|e| {
106            crate::error::Error::Configuration(crate::error::ConfigurationError::InvalidBackoff(
107                format!("Failed to create Tokio runtime: {}", e),
108            ))
109        })?;
110
111        let inner = runtime.block_on(PostgresUriRegister::new_with_cache_strategy(
112            database_url,
113            table_name,
114            max_connections,
115            cache_size,
116            cache_strategy,
117            use_tls,
118        ))?;
119
120        Ok(Self { inner, runtime })
121    }
122
123    /// Register a single URI and return its ID (blocking)
124    ///
125    /// If the URI already exists, returns the existing ID.
126    /// If the URI is new, creates a new ID and returns it.
127    pub fn register_uri(&self, uri: &str) -> Result<u64> {
128        self.runtime.block_on(self.inner.register_uri(uri))
129    }
130
131    /// Register multiple URIs in batch and return their IDs (blocking)
132    ///
133    /// The returned vector maintains order correspondence with the input.
134    pub fn register_uri_batch(&self, uris: &[String]) -> Result<Vec<u64>> {
135        self.runtime.block_on(self.inner.register_uri_batch(uris))
136    }
137
138    /// Register multiple URIs in batch and return a HashMap (blocking)
139    pub fn register_uri_batch_hashmap(&self, uris: &[String]) -> Result<HashMap<String, u64>> {
140        self.runtime
141            .block_on(self.inner.register_uri_batch_hashmap(uris))
142    }
143
144    /// Get statistics about the register (blocking)
145    pub fn stats(&self) -> Result<RegisterStats> {
146        self.runtime.block_on(self.inner.stats())
147    }
148}
149
150// Implement Send + Sync since Runtime is Send + Sync and PostgresUriRegister is Send + Sync
151unsafe impl Send for SyncPostgresUriRegister {}
152unsafe impl Sync for SyncPostgresUriRegister {}