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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
#![doc = include_str!("../doc/rustdoc/client.md")]
pub mod auth;
pub mod cap;
pub mod conn;
mod handler;
pub mod handlers;
pub mod nick;
pub mod queue;
pub mod register;
mod sink;
pub mod state;
#[cfg(feature = "tls")]
pub mod tls;
pub use {handler::*, sink::*};
use self::{channel::ChannelSpec, queue::Queue};
/// A client connection.
#[derive(Default)]
pub struct Client<C, S> {
/// The connection to the IRC server.
conn: C,
/// The [`ChannelSpec`] for creating now channels.
spec: S,
/// A message queue for rate-limiting.
queue: Box<Queue>,
/// A buffer that is used internally for inbound message I/O.
buf_i: Vec<u8>,
/// A buffer that is used internally for outbound message I/O.
buf_o: Vec<u8>,
/// Collection of handlers.
handlers: Handlers,
/// Limit on how long reading one message can take.
timeout: Box<conn::TimeLimits>,
/// Shared state.
state: ClientState,
}
impl<C, S: ChannelSpec> Client<C, S> {
/// Creates a new `Client` from the provided connection.
pub fn new(conn: C, spec: S) -> Self {
Self::new_with_queue(conn, spec, Queue::new())
}
/// Creates a new `Client` from the provided connection and [`Queue`].
pub fn new_with_queue(conn: C, spec: S, queue: Queue) -> Self {
Client {
conn,
spec,
queue: Box::new(queue),
buf_i: Vec::new(),
buf_o: Vec::new(),
handlers: Handlers::default(),
timeout: Box::default(),
state: ClientState::new(),
}
}
/// Adds a handler. Creates a new channel using the internal [`ChannelSpec`].
///
/// Returns the handler id and the receiver half of the channel.
pub fn add<T, M: MakeHandler<T>>(
&mut self,
make_handler: M,
value: T,
) -> Result<(usize, M::Receiver<S>), M::Error> {
let (send, recv) = M::make_channel(&self.spec);
Ok((self.add_with_sender(send, make_handler, value)?, recv))
}
}
impl<C, S> Client<C, S> {
/// Extracts the connection from `self`, allowing it to be used elsewhere.
pub fn take_conn(self) -> C {
self.conn
}
/// Uses the provided connection for `self`.
///
/// This connection does not change any of [`Client`]s state aside from
/// requiring an update of the connection's IO timeouts.
/// Additionally use [`reset`][Client::reset] if you want to reset the state.
pub fn with_conn<C2>(self, conn: C2) -> Client<C2, S> {
let Self { spec, queue, buf_i, buf_o, handlers, mut timeout, state, .. } = self;
timeout.require_update();
Client { conn, spec, queue, buf_i, buf_o, timeout, handlers, state }
}
/// Uses the provided [`ChannelSpec`] for `self`.
/// This changes the type of channels returned by [`add`][Client::add].
pub fn with_spec<S2: ChannelSpec>(self, spec: S2) -> Client<C, S2> {
let Self { conn, queue, buf_i, buf_o, handlers, timeout, state, .. } = self;
Client { conn, spec, queue, buf_i, buf_o, timeout, handlers, state }
}
/// Returns a shared reference to the internal [`Queue`].
pub fn queue(&self) -> &Queue {
&self.queue
}
/// Returns a mutable reference to the internal [`Queue`].
///
/// Removing items from the queue may confuse handlers.
pub fn queue_mut(&mut self) -> &mut Queue {
&mut self.queue
}
/// Returns a shared reference to the internal [shared state][ClientState].
pub fn state(&self) -> &ClientState {
&self.state
}
/// Returns a mutable reference to the internal [shared state][ClientState].
pub fn state_mut(&mut self) -> &mut ClientState {
&mut self.state
}
/// Changes the upper limit on how long an I/O operation may take to receive one message.
/// A timeout of `None` means no limit.
///
/// This upper limit should be long, on the order of tens of seconds.
pub fn set_read_timeout(&mut self, timeout: Option<std::time::Duration>) -> &mut Self {
self.timeout.set_read_timeout(timeout);
self
}
/// Changes the upper limit on how long an I/O operation may take to send any data.
/// A timeout of `None` means no limit.
///
/// This upper limit should be fairly short, on the order of a few seconds.
pub fn set_write_timeout(&mut self, timeout: Option<std::time::Duration>) -> &mut Self {
self.timeout.set_write_timeout(timeout);
self
}
/// Adds a handler. Creates a new channel using the provided [`ChannelSpec`].
///
/// Returns the handler id and the receiver half of the channel.
pub fn add_with_spec<T, M: MakeHandler<T>, S2: ChannelSpec>(
&mut self,
chanspec: &S2,
make_handler: M,
value: T,
) -> Result<(usize, M::Receiver<S2>), M::Error> {
let (send, recv) = M::make_channel(chanspec);
Ok((self.add_with_sender(send, make_handler, value)?, recv))
}
/// Adds a handler using an existing channel.
///
/// Returns the handler id.
pub fn add_with_sender<T, M: MakeHandler<T>>(
&mut self,
sender: Box<dyn channel::Sender<Value = M::Value> + Send>,
make_handler: M,
value: T,
) -> Result<usize, M::Error> {
let handler = make_handler.make_handler(&self.state, self.queue.edit(), value)?;
Ok(self.handlers.add(handler, sender))
}
/// Resets client state to when the connection was just opened.
///
/// Cancels all handlers, removes all [shared state][ClientState],
/// and resets the [queue][Queue] including removing the [queue's labeler][Queue::use_labeler].
/// Does not reset any state that is considered configuration,
/// such as what the queue's rate limits are.
pub fn reset(&mut self) {
self.handlers.cancel();
self.queue.reset();
self.state.clear();
}
/// Uses the provided connection instead of the current one
/// and resets the client state as [`reset`][Client::reset].
/// Returns the old connection.
///
/// This results in a fresh [`Client`] ready to perform connection registration again.
pub fn reset_with_conn(&mut self, conn: C) -> C {
let retval = std::mem::replace(&mut self.conn, conn);
self.timeout.require_update();
self.reset();
retval
}
/// Returns `true` if the client has handlers or queued messages.
pub fn needs_run(&self) -> bool {
!self.handlers.is_empty() || !self.queue.is_empty()
}
}
// Implementations of other Client methods can be found in `conn`,
// specifically the submodules depending on I/O flavor.
/// A collection of heterogenous client state shared between handlers.
///
/// There are many pieces of client state that need to be shared between handlers,
/// such as the client's source string for accurate message length calculations.
/// This type facilitates that in an extensible manner, allowing handlers to
/// add new elements of state at runtime.
///
/// This type intentionally offers no way for state to be removed.
pub struct ClientState {
state: crate::util::FlatMap<(std::any::TypeId, Box<dyn std::any::Any + Send + Sync>)>,
}
impl ClientState {
/// Returns a new, empty `ClientState`.
pub const fn new() -> ClientState {
ClientState { state: crate::util::FlatMap::new() }
}
/// Gets a shared reference to the state denoted by `K`, if any.
pub fn get<K: state::ClientStateKey>(&self) -> Option<&K::Value> {
self.state.get(&K::default().type_id()).and_then(|v| v.1.downcast_ref())
}
/// Gets a mutable reference to the state denoted by `K`, if any.
pub fn get_mut<K: state::ClientStateKey>(&mut self) -> Option<&mut K::Value> {
self.state.get_mut(&K::default().type_id()).and_then(|v| v.1.downcast_mut())
}
/// Sets the state denoted by `K` to `value`.
///
/// This should be called infrequently. Prefer [`ClientState::get_mut`] for most updates.
pub fn insert<K: state::ClientStateKey>(&mut self, value: K::Value) {
self.state.edit().insert((K::default().type_id(), Box::new(value)));
}
/// Clears all state.
pub(super) fn clear(&mut self) {
self.state.clear();
}
}
impl Default for ClientState {
fn default() -> Self {
Self::new()
}
}