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}