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}