Skip to main content

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