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