paper_client/
paper_pool.rs

1/*
2 * Copyright (c) Kia Shakiba
3 *
4 * This source code is licensed under the GNU AGPLv3 license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8use std::sync::{
9	Arc,
10	Mutex,
11	MutexGuard,
12	atomic::{Ordering, AtomicUsize},
13};
14
15use crate::{
16	paper_client::PaperClient,
17	error::PaperClientError,
18	addr::FromPaperAddr,
19};
20
21#[derive(Debug, Clone)]
22pub struct PaperPool {
23	clients: Arc<Box<[Arc<Mutex<PaperClient>>]>>,
24	index: Arc<AtomicUsize>,
25}
26
27impl PaperPool {
28	/// Creates a new instance of a pool of clients of size `size`.
29	/// If a connection could not be established to any of the clients,
30	/// a `PaperClientError` is returned.
31	///
32	/// # Examples
33	/// ```
34	/// use paper_client::PaperPool;
35	///
36	/// let pool = PaperPool::new("paper://127.0.0.1:3145", 4).unwrap();
37	/// ```
38	pub fn new(paper_addr: impl FromPaperAddr, size: usize) -> Result<Self, PaperClientError> {
39		assert!(size > 0);
40
41		let mut clients = Vec::new();
42
43		for _ in 0..size {
44			let client = PaperClient::new(paper_addr.clone())?;
45			clients.push(Arc::new(Mutex::new(client)));
46		}
47
48		let pool = PaperPool {
49			clients: Arc::new(clients.into_boxed_slice()),
50			index: Arc::new(AtomicUsize::default()),
51		};
52
53		Ok(pool)
54	}
55
56	/// Attempts to authorize each client with the supplied auth token.
57	///
58	/// # Examples
59	/// ```
60	/// use paper_client::PaperPool;
61	///
62	/// let pool = PaperPool::new("paper://127.0.0.1:3145", 4).unwrap();
63	///
64	/// if let Err(err) = pool.auth("my_token") {
65	///     println!("{err:?}");
66	/// };
67	/// ```
68	pub fn auth(&self, token: &str) -> Result<(), PaperClientError> {
69		for client in self.clients.iter() {
70			client
71				.lock().expect("Could not obtain client.")
72				.auth(token)?;
73		}
74
75		Ok(())
76	}
77
78	/// Obtains a guarded `PaperClient`. Use this client, then drop the
79	/// reference (or allow it to go out of scope). Do not hold a reference
80	/// to this client, otherwise the client will be unusable by other
81	/// threads in the future.
82	///
83	/// # Examples
84	/// ```
85	/// use paper_client::PaperPool;
86	///
87	/// let pool = PaperPool::new("paper://127.0.0.1:3145", 4).unwrap();
88	///
89	/// match pool.client().ping() {
90	///     Ok(value) => println!("{value:?}"),
91	///     Err(err) => println!("{err:?}"),
92	/// };
93	/// ```
94	pub fn client(&self) -> MutexGuard<'_, PaperClient> {
95		self.clients[self.get_index()]
96			.lock().expect("Could not obtain client.")
97	}
98
99	fn get_index(&self) -> usize {
100		let index = self.index.load(Ordering::Relaxed);
101		self.index.store((index + 1) % self.clients.len(), Ordering::Relaxed);
102		index
103	}
104}